fix: add react doctor and resolve reported errors
Some checks failed
Some checks failed
This commit is contained in:
parent
3683ba9dd2
commit
fd8afb2742
46
.agents/skills/react-doctor/SKILL.md
Normal file
46
.agents/skills/react-doctor/SKILL.md
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
name: react-doctor
|
||||||
|
description: Use when finishing a feature, fixing a bug, before committing React code, or when the user types `/doctor`, asks to scan, triage, or clean up React diagnostics. Covers lint, accessibility, bundle size, architecture. Includes a regression check and a full local-triage workflow that fetches the canonical playbook.
|
||||||
|
version: "1.1.0"
|
||||||
|
---
|
||||||
|
|
||||||
|
# React Doctor
|
||||||
|
|
||||||
|
Scans React codebases for security, performance, correctness, and architecture issues. Outputs a 0–100 health score.
|
||||||
|
|
||||||
|
## After making React code changes:
|
||||||
|
|
||||||
|
Run `npx react-doctor@latest --verbose --diff` and check the score did not regress.
|
||||||
|
|
||||||
|
If the score dropped, fix the regressions before committing.
|
||||||
|
|
||||||
|
## For general cleanup or code improvement:
|
||||||
|
|
||||||
|
Run `npx react-doctor@latest --verbose` (without `--diff`) to scan the full codebase. Fix issues by severity — errors first, then warnings.
|
||||||
|
|
||||||
|
## /doctor — full local triage workflow
|
||||||
|
|
||||||
|
When the user types `/doctor`, says "run react doctor", or asks for a full triage / cleanup pass (not just a regression check), fetch the canonical local-triage playbook and follow every step in it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl --fail --silent --show-error \
|
||||||
|
--header 'Cache-Control: no-cache' \
|
||||||
|
https://www.react.doctor/prompts/react-doctor-agent.md
|
||||||
|
```
|
||||||
|
|
||||||
|
The playbook is the single source of truth — a scan → filter → triage → fix → validate loop that edits the working tree directly (never commits, never opens PRs). Updating the prompt at its source updates every agent on its next fetch — no skill reinstall needed.
|
||||||
|
|
||||||
|
Pair it with the matching per-rule prompts at `https://www.react.doctor/prompts/rules/<plugin>/<rule>.md` (fetched on demand inside the playbook) so each fix uses the canonical, reviewer-tested recipe.
|
||||||
|
|
||||||
|
## Command
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx react-doctor@latest --verbose --diff
|
||||||
|
```
|
||||||
|
|
||||||
|
| Flag | Purpose |
|
||||||
|
| ----------- | --------------------------------------------- |
|
||||||
|
| `.` | Scan current directory |
|
||||||
|
| `--verbose` | Show affected files and line numbers per rule |
|
||||||
|
| `--diff` | Only scan changed files vs base branch |
|
||||||
|
| `--score` | Output only the numeric score |
|
||||||
46
.claude/skills/react-doctor/SKILL.md
Normal file
46
.claude/skills/react-doctor/SKILL.md
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
name: react-doctor
|
||||||
|
description: Use when finishing a feature, fixing a bug, before committing React code, or when the user types `/doctor`, asks to scan, triage, or clean up React diagnostics. Covers lint, accessibility, bundle size, architecture. Includes a regression check and a full local-triage workflow that fetches the canonical playbook.
|
||||||
|
version: "1.1.0"
|
||||||
|
---
|
||||||
|
|
||||||
|
# React Doctor
|
||||||
|
|
||||||
|
Scans React codebases for security, performance, correctness, and architecture issues. Outputs a 0–100 health score.
|
||||||
|
|
||||||
|
## After making React code changes:
|
||||||
|
|
||||||
|
Run `npx react-doctor@latest --verbose --diff` and check the score did not regress.
|
||||||
|
|
||||||
|
If the score dropped, fix the regressions before committing.
|
||||||
|
|
||||||
|
## For general cleanup or code improvement:
|
||||||
|
|
||||||
|
Run `npx react-doctor@latest --verbose` (without `--diff`) to scan the full codebase. Fix issues by severity — errors first, then warnings.
|
||||||
|
|
||||||
|
## /doctor — full local triage workflow
|
||||||
|
|
||||||
|
When the user types `/doctor`, says "run react doctor", or asks for a full triage / cleanup pass (not just a regression check), fetch the canonical local-triage playbook and follow every step in it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl --fail --silent --show-error \
|
||||||
|
--header 'Cache-Control: no-cache' \
|
||||||
|
https://www.react.doctor/prompts/react-doctor-agent.md
|
||||||
|
```
|
||||||
|
|
||||||
|
The playbook is the single source of truth — a scan → filter → triage → fix → validate loop that edits the working tree directly (never commits, never opens PRs). Updating the prompt at its source updates every agent on its next fetch — no skill reinstall needed.
|
||||||
|
|
||||||
|
Pair it with the matching per-rule prompts at `https://www.react.doctor/prompts/rules/<plugin>/<rule>.md` (fetched on demand inside the playbook) so each fix uses the canonical, reviewer-tested recipe.
|
||||||
|
|
||||||
|
## Command
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx react-doctor@latest --verbose --diff
|
||||||
|
```
|
||||||
|
|
||||||
|
| Flag | Purpose |
|
||||||
|
| ----------- | --------------------------------------------- |
|
||||||
|
| `.` | Scan current directory |
|
||||||
|
| `--verbose` | Show affected files and line numbers per rule |
|
||||||
|
| `--diff` | Only scan changed files vs base branch |
|
||||||
|
| `--score` | Output only the numeric score |
|
||||||
@ -134,8 +134,8 @@ export default function CaptureScreen() {
|
|||||||
const isActive = workspace.id === activeWorkspaceId;
|
const isActive = workspace.id === activeWorkspaceId;
|
||||||
return (
|
return (
|
||||||
<Pressable
|
<Pressable
|
||||||
{...buttonA11y(`Select workspace ${workspace.name}`, { selected: isActive })}
|
|
||||||
key={workspace.id}
|
key={workspace.id}
|
||||||
|
{...buttonA11y(`Select workspace ${workspace.name}`, { selected: isActive })}
|
||||||
onPress={() => setActiveWorkspace(workspace.id)}
|
onPress={() => setActiveWorkspace(workspace.id)}
|
||||||
style={[styles.workspaceChip, isActive ? styles.workspaceChipActive : null]}
|
style={[styles.workspaceChip, isActive ? styles.workspaceChipActive : null]}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -55,8 +55,8 @@ export default function HomeScreen() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Pressable
|
<Pressable
|
||||||
{...buttonA11y(`Filter by ${workspace.name}`, { selected: isActive })}
|
|
||||||
key={workspace.id}
|
key={workspace.id}
|
||||||
|
{...buttonA11y(`Filter by ${workspace.name}`, { selected: isActive })}
|
||||||
onPress={() => setActiveWorkspace(workspace.id)}
|
onPress={() => setActiveWorkspace(workspace.id)}
|
||||||
style={[styles.workspaceChip, isActive ? styles.workspaceChipActive : null]}
|
style={[styles.workspaceChip, isActive ? styles.workspaceChipActive : null]}
|
||||||
>
|
>
|
||||||
@ -70,7 +70,7 @@ export default function HomeScreen() {
|
|||||||
|
|
||||||
{isLoading ? <Text style={styles.empty}>Loading notes…</Text> : null}
|
{isLoading ? <Text style={styles.empty}>Loading notes…</Text> : null}
|
||||||
{recentNotes.map((note: (typeof recentNotes)[number]) => (
|
{recentNotes.map((note: (typeof recentNotes)[number]) => (
|
||||||
<Pressable {...buttonA11y(`Open note ${note.title}`)} key={note.id} onPress={() => router.push(`/note/${note.id}`)} style={styles.card}>
|
<Pressable key={note.id} {...buttonA11y(`Open note ${note.title}`)} onPress={() => router.push(`/note/${note.id}`)} style={styles.card}>
|
||||||
<View style={styles.badgeRow}>
|
<View style={styles.badgeRow}>
|
||||||
<Text style={styles.badge}>{note.workspace}</Text>
|
<Text style={styles.badge}>{note.workspace}</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@ -50,7 +50,7 @@ export default function SearchScreen() {
|
|||||||
<View style={styles.list}>
|
<View style={styles.list}>
|
||||||
{isLoading ? <Text style={styles.empty}>Loading searchable notes…</Text> : null}
|
{isLoading ? <Text style={styles.empty}>Loading searchable notes…</Text> : null}
|
||||||
{results.map((note: MobileNote) => (
|
{results.map((note: MobileNote) => (
|
||||||
<Pressable {...buttonA11y(`Open note ${note.title}`)} key={note.id} onPress={() => router.push(`/note/${note.id}`)} style={styles.row}>
|
<Pressable key={note.id} {...buttonA11y(`Open note ${note.title}`)} onPress={() => router.push(`/note/${note.id}`)} style={styles.row}>
|
||||||
<Text style={styles.rowText}>{note.title}</Text>
|
<Text style={styles.rowText}>{note.title}</Text>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -69,8 +69,8 @@ export default function SettingsScreen() {
|
|||||||
const isActive = type === feedbackType;
|
const isActive = type === feedbackType;
|
||||||
return (
|
return (
|
||||||
<Pressable
|
<Pressable
|
||||||
{...buttonA11y(`Select ${type} feedback type`, { selected: isActive })}
|
|
||||||
key={type}
|
key={type}
|
||||||
|
{...buttonA11y(`Select ${type} feedback type`, { selected: isActive })}
|
||||||
style={[styles.typeChip, isActive ? styles.typeChipActive : null]}
|
style={[styles.typeChip, isActive ? styles.typeChipActive : null]}
|
||||||
onPress={() => setFeedbackType(type)}
|
onPress={() => setFeedbackType(type)}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -20,10 +20,12 @@
|
|||||||
"audit:ui:ratchet:update": "bash scripts/ui-drift-ratchet.sh --update",
|
"audit:ui:ratchet:update": "bash scripts/ui-drift-ratchet.sh --update",
|
||||||
"dependency:health": "bash scripts/dependency-health.sh",
|
"dependency:health": "bash scripts/dependency-health.sh",
|
||||||
"verify": "pnpm run typecheck && pnpm run test && pnpm run build",
|
"verify": "pnpm run typecheck && pnpm run test && pnpm run build",
|
||||||
"prepare": "husky"
|
"prepare": "husky",
|
||||||
|
"doctor": "react-doctor --project @notelett/web,@notelett/mobile"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"husky": "^9.0.0"
|
"husky": "^9.0.0",
|
||||||
|
"react-doctor": "^0.2.9"
|
||||||
},
|
},
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"overrides": {
|
"overrides": {
|
||||||
|
|||||||
1030
pnpm-lock.yaml
generated
1030
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -205,7 +205,7 @@ export function AppShellNavItem({ className, ...props }: AppShellNavItemProps) {
|
|||||||
return <BytelystAppShellNavItem className={className} {...props} />;
|
return <BytelystAppShellNavItem className={className} {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getStatusTone(status: NoteLettStatus): StatusTone {
|
function getStatusTone(status: NoteLettStatus): StatusTone {
|
||||||
return statusToneMap[status];
|
return statusToneMap[status];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user