any-doctor 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/CONTEXT.md +128 -0
  2. package/README.md +68 -0
  3. package/bin/capabilities.d.ts +15 -0
  4. package/bin/capabilities.js +131 -0
  5. package/bin/cli.d.ts +2 -0
  6. package/bin/cli.js +426 -0
  7. package/bin/clipboard.d.ts +1 -0
  8. package/bin/clipboard.js +10 -0
  9. package/bin/contract.d.ts +134 -0
  10. package/bin/contract.js +70 -0
  11. package/bin/dashboard.d.ts +108 -0
  12. package/bin/dashboard.js +718 -0
  13. package/bin/discover.d.ts +24 -0
  14. package/bin/discover.js +87 -0
  15. package/bin/doctor-loader.d.mts +1 -0
  16. package/bin/doctor-loader.mjs +161 -0
  17. package/bin/engine.d.ts +18 -0
  18. package/bin/engine.js +22 -0
  19. package/bin/fuzzy.d.ts +2 -0
  20. package/bin/fuzzy.js +31 -0
  21. package/bin/import-guard.mjs +31 -0
  22. package/bin/keys.d.ts +2 -0
  23. package/bin/keys.js +72 -0
  24. package/bin/palette.d.ts +7 -0
  25. package/bin/palette.js +14 -0
  26. package/bin/picker.d.ts +12 -0
  27. package/bin/picker.js +82 -0
  28. package/bin/report.d.ts +18 -0
  29. package/bin/report.js +159 -0
  30. package/bin/runner.d.ts +58 -0
  31. package/bin/runner.js +271 -0
  32. package/bin/score.d.ts +13 -0
  33. package/bin/score.js +39 -0
  34. package/bin/sdk.d.ts +5 -0
  35. package/bin/sdk.js +95 -0
  36. package/bin/search-host.d.ts +6 -0
  37. package/bin/search-host.js +56 -0
  38. package/bin/select.d.ts +35 -0
  39. package/bin/select.js +45 -0
  40. package/bin/tty.d.ts +38 -0
  41. package/bin/tty.js +94 -0
  42. package/docs/REPAIR-LOG.md +45 -0
  43. package/docs/RESULTS.md +70 -0
  44. package/docs/decisions.md +450 -0
  45. package/docs/example-catalog.md +122 -0
  46. package/docs/features.md +67 -0
  47. package/docs/first-shot-results.md +18 -0
  48. package/docs/intents.md +21 -0
  49. package/docs/kill-test.md +54 -0
  50. package/docs/research.md +66 -0
  51. package/docs/vision.md +83 -0
  52. package/doctors/AGENTS.md +103 -0
  53. package/doctors/api-route-files-do-import.fixtures.mjs +61 -0
  54. package/doctors/api-route-files-do-import.mjs +26 -0
  55. package/doctors/async-doctor.fixtures.mjs +147 -0
  56. package/doctors/async-doctor.mjs +295 -0
  57. package/doctors/convex-doctor.fixtures.mjs +177 -0
  58. package/doctors/convex-doctor.mjs +223 -0
  59. package/doctors/date-now-used-inside-effect.fixtures.mjs +46 -0
  60. package/doctors/date-now-used-inside-effect.mjs +132 -0
  61. package/doctors/json-parse-calls-llm-api.fixtures.mjs +37 -0
  62. package/doctors/json-parse-calls-llm-api.mjs +85 -0
  63. package/doctors/route-handlers-touch-database-before.fixtures.mjs +58 -0
  64. package/doctors/route-handlers-touch-database-before.mjs +98 -0
  65. package/doctors/z-record-called-with-single.fixtures.mjs +28 -0
  66. package/doctors/z-record-called-with-single.mjs +19 -0
  67. package/fixtures/sample-app/src/hooks/useChat.ts +15 -0
  68. package/fixtures/sample-app/src/lib/ai/client.ts +5 -0
  69. package/fixtures/sample-app/src/schemas/user.ts +6 -0
  70. package/fixtures/sample-app/src/services/chat.ts +17 -0
  71. package/fixtures/sample-app/src/services/user.ts +10 -0
  72. package/fixtures/sample-app/src/utils/sync.ts +16 -0
  73. package/package.json +42 -0
  74. package/skill/any-doctor.skill.md +188 -0
@@ -0,0 +1,188 @@
1
+ # any-doctor — doctor generation skill
2
+
3
+ You are writing a **doctor program**: a small analysis tool that detects one
4
+ codebase convention, plus the fixtures that prove it works. The INTENT is
5
+ the entire specification. Derive everything from the intent alone — never
6
+ scan a target repository to tune your doctor against its code.
7
+
8
+ ## The contract
9
+
10
+ Two files, exactly:
11
+
12
+ `doctors/<slug>.mjs` (slug = short kebab-case from the intent):
13
+
14
+ ```js
15
+ export const meta = {
16
+ id: "<slug>", // kebab-case, matches the filename
17
+ description: "<one-line finding text, shown in reports>",
18
+ severity: "warning", // default: "error" | "warning" | "info"
19
+ category: "<bugs | performance | security | style | ...>",
20
+ blindSpots: [ // what this approach CANNOT see — required
21
+ "<honest limitation>",
22
+ ],
23
+ checks: [ // optional: multiple related checks in ONE doctor
24
+ {
25
+ id: "<check-id>", // short kebab noun phrase, [a-z0-9-], unique per doctor; name the defect
26
+ description: "<finding text>",
27
+ severity: "warning",
28
+ impact: "<one line: what goes wrong for the user if this ships>",
29
+ why: "<one line: what in the code triggers this>",
30
+ fix: "<one line: the corrective action>",
31
+ },
32
+ ],
33
+ };
34
+
35
+ export async function doctor(ctx) {
36
+ // inspect the codebase, emit findings
37
+ // ctx.report.finding({ rule: "<check-id>", file, line, column?, message?, severity? })
38
+ }
39
+ ```
40
+
41
+ `doctors/<slug>.fixtures.mjs`:
42
+
43
+ ```js
44
+ export const fixtures = [
45
+ {
46
+ name: "<what this case proves>",
47
+ seed: { "src/example.ts": "...inline file contents..." },
48
+ expected: [{ file: "src/example.ts", line: 2 }], // exact set on (file, line)
49
+ },
50
+ // include cases where expected: [] — innocent lookalikes must stay silent
51
+ ];
52
+ ```
53
+
54
+ `ctx` is the only capability a doctor has:
55
+
56
+ - `ctx.files.list(exts?)` → relative paths (default .ts/.tsx/.js/.jsx/.mjs)
57
+ - `ctx.files.read(rel)` → file contents
58
+ - `ctx.search.pattern(pattern, language?)` → `[{ file, line, column, text }]`
59
+ (ast-grep pattern syntax, e.g. `"fetch($URL)"`; requires ast-grep installed)
60
+ - `ctx.report.finding({ file, line, column?, message?, severity? })`
61
+
62
+ Zero dependencies, zero imports — a doctor is one self-contained file;
63
+ everything reaches it through `ctx`. Node >= 18.
64
+
65
+ ## One doctor, many checks
66
+
67
+ If the intent covers several related patterns (an SDK migration with
68
+ multiple outdated calls, a family of anti-patterns, "all the stripe
69
+ practices we deprecated"), build ONE doctor with multiple checks — not one
70
+ doctor per pattern:
71
+
72
+ - Declare each check in `meta.checks` (`{ id, description, severity? }`).
73
+ - Emit each finding with `rule: "<check-id>"` matching a declared check.
74
+ - The report groups findings under each check's description, under the
75
+ doctor's umbrella.
76
+
77
+ Bundle when the checks share a theme or a codebase area. Stay separate
78
+ when the checks are unrelated concerns that would be deleted or shared
79
+ independently.
80
+
81
+ ## Severity judgment
82
+
83
+ If the intent dictates criticality ("make the findings critical"), follow
84
+ it. Otherwise judge by consequence:
85
+
86
+ - `error` — will break, lose, or expose data at runtime
87
+ - `warning` — wrong or risky but non-fatal
88
+ - `info` — stylistic or informational
89
+
90
+ Per-check severity lives in `meta.checks`; a finding may override with its
91
+ own `severity` only for exceptions.
92
+
93
+ ## Hard workflow
94
+
95
+ 1. Write both files.
96
+ 2. Run: `any-doctor verify doctors/<slug>.mjs` (or `node bin/cli.js verify doctors/<slug>.mjs`).
97
+ 3. ALL fixtures must pass. Iterate until green — a failed fixture is the
98
+ system telling you your rule or your expectations are wrong; fix the rule,
99
+ or fix the expectation if the expectation itself was wrong.
100
+ 4. Report: id, what it detects, declared blind spots, fixture count.
101
+
102
+ ## Fixture discipline
103
+
104
+ - Matching is exact-set on (file, line): a missing expected finding fails
105
+ (recall); an unexpected extra finding fails (precision). Get both sides right.
106
+ - Every doctor needs at least one `expected: []` fixture containing code that
107
+ LOOKS like a violation but isn't — the lookalike that a naive implementation
108
+ would wrongly flag.
109
+ - Cover the simplest violation and the sneakiest one. Vary quote styles where
110
+ syntax allows.
111
+ - Findings are locations. Wording lives in `meta.description`; use
112
+ per-finding `message` only when one violation needs its own explanation.
113
+
114
+ ## Authoring for the report
115
+
116
+ The report's detail pane shows, per check: category · severity · location,
117
+ then **Impact**, the code frame, and **Fix**. Write `impact`, `why`, and
118
+ `fix` on every check — one line each, plain language, no code in them.
119
+ They are what the user reads while deciding whether to care. `impact` =
120
+ consequence if it ships; `why` = the code shape that triggers the check;
121
+ `fix` = the corrective action in one sentence.
122
+
123
+ ## Honesty rules
124
+
125
+ - `blindSpots` is required and is data: declare what your approach cannot
126
+ see (aliased imports, cross-file references, dynamic constructs).
127
+ - Never silently narrow the intent. If the intent is not fully statically
128
+ checkable, implement the closest honest version and declare the gap.
129
+ - A clean run must mean clean. Never swallow errors into empty findings.
130
+
131
+ ## Capability rules (the runtime gate enforces these)
132
+
133
+ A doctor's entire world is the target repo through `ctx`. Anything else is
134
+ out of contract: the capability gate scans the program before it ever runs
135
+ and refuses to execute it — there is no override:
136
+
137
+ - **A doctor is one self-contained file.** No imports at all — not node
138
+ builtins, not local helpers, not npm packages. Everything reaches you
139
+ through `ctx`; every import is refused at runtime.
140
+ - **No network calls. Ever.** No fetch, http/https, net, tls, dns, dgram.
141
+ There is no legitimate reason for a doctor to reach the network — and the
142
+ network globals are deleted from the process before your code runs.
143
+ - **No file writes.** Doctors read; they never write, delete, or rename.
144
+ - **No subprocesses.** Searching goes through `ctx.search` — never spawn
145
+ anything yourself.
146
+ - Read files through `ctx.files.read` (it is repo-scoped); it is the only
147
+ way to read — imports are refused outright.
148
+ - `process.env` is flagged too. If you need configuration, it does not
149
+ belong in a doctor — the target repo is the input.
150
+
151
+ The scan is layered with runtime enforcement: on runtimes that support it,
152
+ doctors execute under Node's permission model, so file writes and
153
+ subprocesses are denied by the process itself — even code the scan cannot
154
+ see. Worker threads exist only as the import guard's carrier and inherit
155
+ every denial.
156
+
157
+ One helper recurs across doctor programs by design: the comment/string
158
+ masking function that blanks non-code before pattern matching. The
159
+ single-file law forbids importing it, so copy it in — that duplication is
160
+ the contract working, not a smell to fix.
161
+
162
+ If you cannot implement the intent without breaking a rule, the intent is
163
+ out of scope for a doctor: say so in your final report instead.
164
+
165
+ ## Failure lessons (each of these shipped in a real doctor — do not repeat)
166
+
167
+ 1. `String.replace(text, x)` replaces only the FIRST occurrence. When
168
+ substituting placeholders into a regex source string, use a global regex:
169
+ `.replace(/NAME/g, escaped)`.
170
+ 2. Escape anything variable you interpolate into a RegExp
171
+ (`s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")`).
172
+ 3. Match the innermost construct once. `await fetch(x)` contains a
173
+ `fetch(x)` node — a pattern for the inner call already matches it;
174
+ adding wrapper variants double-reports.
175
+ 4. Read each file once per pass. Don't re-read inside loops.
176
+ 5. If the intent is not fully statically checkable (cross-file references,
177
+ runtime behavior, types), implement the closest honest version and
178
+ declare the gap in `blindSpots`. Never drop an intent condition silently.
179
+ 6. Your own `console.log` goes to stderr, not the report. Don't rely on
180
+ stdout — stdout carries only the structured result.
181
+
182
+ ## What NOT to do
183
+
184
+ - Don't touch any file other than the two contract files.
185
+ - Don't add dependencies — and don't import anything at all, not even
186
+ `node:` builtins; every import is refused at runtime.
187
+ - Don't scan a target repository to "tune" the doctor against its code.
188
+ - Don't mark a fixture green by weakening the expectation — strengthen the doctor.