any-doctor 0.0.7 → 0.0.9
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.
- package/CONTEXT.md +96 -12
- package/README.md +45 -29
- package/bin/analysis-host.d.ts +5 -3
- package/bin/analysis-host.js +10 -6
- package/bin/analysis.d.ts +9 -1
- package/bin/analysis.js +188 -17
- package/bin/certify.js +56 -139
- package/bin/cli.js +15 -8
- package/bin/cohort.d.ts +4 -3
- package/bin/cohort.js +4 -4
- package/bin/contract.d.ts +99 -8
- package/bin/contract.js +67 -25
- package/bin/dashboard.d.ts +3 -55
- package/bin/dashboard.js +12 -209
- package/bin/diff.d.ts +30 -5
- package/bin/diff.js +170 -40
- package/bin/discover.js +16 -3
- package/bin/doctor-tree.d.ts +52 -0
- package/bin/doctor-tree.js +113 -0
- package/bin/engine.d.ts +2 -0
- package/bin/engine.js +100 -1
- package/bin/identity.d.ts +63 -0
- package/bin/identity.js +456 -0
- package/bin/palette.d.ts +1 -0
- package/bin/palette.js +1 -1
- package/bin/prompts.d.ts +4 -0
- package/bin/prompts.js +103 -0
- package/bin/report.d.ts +9 -19
- package/bin/report.js +49 -13
- package/bin/runner.js +12 -1
- package/bin/score.d.ts +2 -0
- package/bin/score.js +9 -2
- package/bin/sdk.d.ts +0 -1
- package/bin/sdk.js +24 -25
- package/bin/search-host.d.ts +0 -2
- package/bin/search-host.js +1 -32
- package/bin/summary.d.ts +1 -3
- package/bin/summary.js +9 -6
- package/docs/HANDOFF.md +102 -64
- package/docs/decisions.md +149 -1
- package/docs/doctor-reliability.md +82 -0
- package/docs/evidence/repair-after-0.0.7/convex-verify.txt +103 -0
- package/docs/evidence/repair-after-0.0.7/sift-convex-packed.json +583 -0
- package/docs/evidence/repair-after-0.0.7/sift-convex-published.json +1023 -0
- package/docs/evidence/repair-after-0.0.7/sift-slop-packed.json +956 -0
- package/docs/evidence/repair-after-0.0.7/sift-slop-published.json +951 -0
- package/docs/evidence/repair-after-0.0.7/tests.txt +307 -0
- package/docs/example-catalog.md +7 -1
- package/docs/features.md +62 -67
- package/docs/intents.md +6 -0
- package/docs/plans/analysis-improvements.md +234 -0
- package/docs/plans/finding-lifecycle/design.md +170 -0
- package/docs/plans/finding-lifecycle/milestones.md +120 -0
- package/docs/plans/finding-lifecycle/proposal.md +104 -0
- package/docs/repair-audit-007.md +78 -0
- package/docs/vision.md +101 -83
- package/doctors/convex-doctor.fixtures.mjs +472 -34
- package/doctors/convex-doctor.mjs +137 -219
- package/fixtures/sensitivity/discard-with-unrelated-combiner/convex/notes.ts +9 -0
- package/fixtures/sensitivity/discard-with-unrelated-combiner/expect.json +13 -0
- package/package.json +2 -1
- package/skill/any-doctor.skill.md +64 -32
package/CONTEXT.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
Canonical vocabulary for any-doctor. Glossary only — no implementation.
|
|
4
4
|
When a term here conflicts with language elsewhere, this file wins.
|
|
5
5
|
|
|
6
|
+
Current product intent lives in [docs/vision.md](docs/vision.md). For work on
|
|
7
|
+
persistent decisions, history, identity, or team convergence, read the
|
|
8
|
+
[lifecycle design](docs/plans/finding-lifecycle/design.md); the first identity
|
|
9
|
+
delivery (lifecycle M1, slices A1+A2) is planned in
|
|
10
|
+
[analysis improvements](docs/plans/analysis-improvements.md). Their proposed records
|
|
11
|
+
are not implemented interfaces; the glossary below describes current behavior
|
|
12
|
+
unless a term is explicitly marked planned.
|
|
13
|
+
|
|
6
14
|
## Doctor program
|
|
7
15
|
|
|
8
16
|
The artifact an LLM writes: a JavaScript module that inspects a target
|
|
@@ -57,6 +65,33 @@ deriving twice from one RunOutcome yields one Summary; rendering
|
|
|
57
65
|
derivation. The facts a gate needs (`--fail-on` severity counts,
|
|
58
66
|
baseline-diffable shapes) live here as data, not inside rendering.
|
|
59
67
|
|
|
68
|
+
## Dashboard
|
|
69
|
+
|
|
70
|
+
The interactive review surface over a RunOutcome: one module
|
|
71
|
+
(src/dashboard.ts) that owns layout, the frame renderer, the TUI loop, and
|
|
72
|
+
the per-finding read state — composing the Doctor tree as its view-model
|
|
73
|
+
and the Task prompts it copies. Selection, expansion, keymap, and the
|
|
74
|
+
clipboard notice live here; the tree's shape and the prompt copy do not.
|
|
75
|
+
|
|
76
|
+
## Doctor tree
|
|
77
|
+
|
|
78
|
+
The dashboard's view-model: DoctorGroup → checks → SiteFinding, computed
|
|
79
|
+
once from the Summary's per-doctor check buckets (src/doctor-tree.ts —
|
|
80
|
+
the tree joins and orders, it never re-groups) and ordered for triage —
|
|
81
|
+
worst severity first, then finding count, then name. Every consumer (the
|
|
82
|
+
list rows, the detail pane, the task prompts) flattens or reads the one
|
|
83
|
+
tree without rebuilding it. A SiteFinding's readKey
|
|
84
|
+
(`checkKey@file:line`) is the within-run identity the read state keys on.
|
|
85
|
+
|
|
86
|
+
## Task prompt
|
|
87
|
+
|
|
88
|
+
Text the dashboard copies to the clipboard as one unit of agent work: one
|
|
89
|
+
finding (fixPrompt), every finding of one check (checkFixPrompt), or a
|
|
90
|
+
doctor's whole batch (doctorFixPrompt) — pure functions of Doctor-tree
|
|
91
|
+
types plus the verify command, no terminal required. The lifecycle plan
|
|
92
|
+
(M2) reworks this family toward investigation-first framing and
|
|
93
|
+
authorized decision paths.
|
|
94
|
+
|
|
60
95
|
## Gate
|
|
61
96
|
|
|
62
97
|
A run's exit policy — one module (src/gate.ts), one law. Findings are
|
|
@@ -69,13 +104,15 @@ infrastructure failure is not a finding and must never paint a run
|
|
|
69
104
|
green. Diff mode (`--base <ref>`) judges only what a change ADDED: the
|
|
70
105
|
same cohort scans the merge base of the ref and HEAD (a stateless
|
|
71
106
|
baseline — nothing committed, nothing stale), the two deduped finding
|
|
72
|
-
sets compare through the
|
|
107
|
+
sets compare through the identity layer (movement-aware — a finding
|
|
108
|
+
that moved with its code is Continuing; `compareFindings` remains the
|
|
109
|
+
fixture gate's exact multiset, never the diff's), and the
|
|
73
110
|
bar counts added findings only; a change is not blamed for the debt it
|
|
74
111
|
was born into. A partial base never gates: any base-scan crash aborts
|
|
75
112
|
the run loudly (exit 1, no report, no JSON), because a baseline
|
|
76
113
|
missing findings would dress pre-existing debt up as "added" — and a
|
|
77
114
|
crashed HEAD doctor skips the diff for the same reason: its findings
|
|
78
|
-
are absent, and absence must never read as "
|
|
115
|
+
are absent, and absence must never read as "no longer detected". Machine
|
|
79
116
|
output rides `--format json` — one schema-tagged object on stdout,
|
|
80
117
|
diagnostics on stderr.
|
|
81
118
|
|
|
@@ -93,12 +130,21 @@ runs. There is no override in any mode.
|
|
|
93
130
|
|
|
94
131
|
## Finding
|
|
95
132
|
|
|
96
|
-
One emitted finding: a location (file, line) plus optional per-finding
|
|
133
|
+
One emitted finding: an observed condition, represented by a location (file, line, optional zero-based column) plus optional per-finding
|
|
97
134
|
message or severity override. "Issue" and "instance" are retired
|
|
98
135
|
synonyms — Finding is the term in code, copy, and prompts. The
|
|
99
136
|
doctor-level truth (id, description, default severity, blind spots)
|
|
100
137
|
lives in the program's meta, not in individual findings.
|
|
101
138
|
|
|
139
|
+
A finding may establish a defect, flag a project convention, or identify a
|
|
140
|
+
contextual review candidate. Its existence alone does not establish that a code
|
|
141
|
+
change is appropriate. Current locations are not durable lifecycle identities,
|
|
142
|
+
but a finding may carry an optional `evidence` range (`endLine`, exclusive
|
|
143
|
+
`endColumn`) covering its whole expression: the host validates it against the
|
|
144
|
+
scanned source and the identity layer digests the covered span, so edits on
|
|
145
|
+
continuation lines still break identity. Findings without a range match on
|
|
146
|
+
their flagged line alone — line-scoped, surfaced as such.
|
|
147
|
+
|
|
102
148
|
## Check
|
|
103
149
|
|
|
104
150
|
One rule within a doctor program. A finding names its check via `rule`;
|
|
@@ -107,7 +153,7 @@ and, when the check uses the identity engine at full power, its
|
|
|
107
153
|
declaration of that need (`needs`), which is what renders "narrowed"
|
|
108
154
|
when the engine is absent; the doctor's meta supplies the defaults when
|
|
109
155
|
a finding names no check. A check id is a short kebab-case noun phrase
|
|
110
|
-
over [a-z0-9-], unique within its doctor, naming the
|
|
156
|
+
over [a-z0-9-], unique within its doctor, naming the detected concern
|
|
111
157
|
(fetch-calls-without-abortsignal, filter-table-scan). One doctor
|
|
112
158
|
program, many checks.
|
|
113
159
|
|
|
@@ -167,9 +213,12 @@ scans doctors once carried privately (the audit truncation bugs lived in
|
|
|
167
213
|
those approximations). The engine is optional (oxc-parser +
|
|
168
214
|
eslint-scope behind the Engine seam's second adapter): checks declare
|
|
169
215
|
the analysis they need on their CheckMeta (`needs` — vocabulary:
|
|
170
|
-
"bindings", "spans"), narrow without it,
|
|
216
|
+
"bindings", "spans", "calls"), narrow without it,
|
|
171
217
|
and the report renders "narrowed" — a degraded run is visible, never
|
|
172
|
-
silent.
|
|
218
|
+
silent. `ctx.analysis.calls(file)` provides immediate call use, receiver identity,
|
|
219
|
+
inline callback registration, and linked call ranges. These are syntax facts;
|
|
220
|
+
stored, passed, or returned is not a promise-settlement verdict. Parse/adapter
|
|
221
|
+
errors fail the doctor run explicitly. References answer by position, so analysis queries compose with
|
|
173
222
|
rule queries: shapes from one engine, identities from the other.
|
|
174
223
|
|
|
175
224
|
## Engine
|
|
@@ -197,7 +246,7 @@ count as the doctors scanned it (default extensions); findings naming
|
|
|
197
246
|
files outside that count can push the raw value negative, so the result
|
|
198
247
|
is floored into 0–100 — and floored, never rounded, so any finding costs
|
|
199
248
|
at least one point. Findings duplicated across doctors at the same
|
|
200
|
-
file:line are deduplicated before scoring — the first-sorted copy wins
|
|
249
|
+
file:line:column are deduplicated before scoring — the first-sorted copy wins
|
|
201
250
|
(groups sort by the first finding carrying an explicit severity
|
|
202
251
|
override, else the doctor's declared default; equal-severity groups
|
|
203
252
|
fall back to input order) and a hidden duplicate's severity does not
|
|
@@ -227,9 +276,10 @@ known input.
|
|
|
227
276
|
## Fixture
|
|
228
277
|
|
|
229
278
|
One seed plus the findings expected from running a doctor program against
|
|
230
|
-
it. Expected findings match
|
|
279
|
+
it. Expected findings match on (rule, file, line, optional column), duplicates
|
|
231
280
|
counted: a missing expected finding is a recall failure; an unexpected
|
|
232
|
-
finding is a precision failure
|
|
281
|
+
finding is a precision failure within these labeled cases, not a population
|
|
282
|
+
accuracy measurement. The rule in an expectation is part of the
|
|
233
283
|
match — a wrong-check finding at the right line fails the gate. A fixture
|
|
234
284
|
also declares its analysis mode (D20 Stage 2): "on" (default) pins the
|
|
235
285
|
full-power path and skips with a named notice where the engine is not
|
|
@@ -248,8 +298,8 @@ workflow's second pass; a doctor ships only after surviving its attack.
|
|
|
248
298
|
Running a doctor program against its fixtures and diffing the findings.
|
|
249
299
|
The trust gate: a doctor program is not considered working until verify
|
|
250
300
|
passes. The policies that compose the gate — the claim contract, the
|
|
251
|
-
per-fixture diff, the shared innocent corpus,
|
|
252
|
-
|
|
301
|
+
per-fixture diff, the shared innocent corpus, per-check location
|
|
302
|
+
coverage, the shared sensitivity corpus — live in one module, the
|
|
253
303
|
Certification harness (`src/certify.ts`), behind one interface:
|
|
254
304
|
`certify(mod, fixtures) -> result rows`. The doctor loader calls it once;
|
|
255
305
|
prevention tiers land there, not in loader choreography.
|
|
@@ -277,7 +327,8 @@ the consuming repo), user-global (`~/.any-doctor/doctors/`, available
|
|
|
277
327
|
in every repo), or bundled (the first-party pack inside the package,
|
|
278
328
|
read-only — a starting point, not a dependency). Repo-local wins slug
|
|
279
329
|
collisions, then user-global, then bundled. Scanning a target repo
|
|
280
|
-
|
|
330
|
+
currently does not persist state in any scope. Planned CLI-owned state is
|
|
331
|
+
separate from doctor discovery and does not grant doctors write capabilities.
|
|
281
332
|
|
|
282
333
|
## Skill
|
|
283
334
|
|
|
@@ -287,3 +338,36 @@ marker; `generate` refreshes a copy it planted (the marker is the
|
|
|
287
338
|
boundary) and never touches a copy without one. The generation prompt
|
|
288
339
|
embeds the skill verbatim. Any Doctor equips agents with the skill;
|
|
289
340
|
it never launches, deploys, or speaks for an agent.
|
|
341
|
+
|
|
342
|
+
## Location coverage
|
|
343
|
+
|
|
344
|
+
A certification result for one check's reporting unit. Occurrence-level
|
|
345
|
+
warning/error checks need a passing, context-preserving fixture with two
|
|
346
|
+
distinct locations of that check in one file. File/project checks need a
|
|
347
|
+
positive witness. Unspecified legacy units and unavailable analysis are
|
|
348
|
+
reported as not exercised, not counted as passing. Fixture expectations
|
|
349
|
+
establish tested coverage, not general correctness or independence of labels.
|
|
350
|
+
|
|
351
|
+
## Lifecycle vocabulary (planned, except where marked landed)
|
|
352
|
+
|
|
353
|
+
These terms describe the accepted direction, not current fields on Finding or
|
|
354
|
+
DoctorCtx. The [design](docs/plans/finding-lifecycle/design.md) owns their data
|
|
355
|
+
and applicability rules.
|
|
356
|
+
|
|
357
|
+
- **Finding identity** *(landed in the diff path, D30)*: continuity of one
|
|
358
|
+
occurrence across comparable scans, distinct from its current source
|
|
359
|
+
coordinates. Host-derived today — check key, file, normalized flagged-line
|
|
360
|
+
digest, indentation-relative column, and innermost enclosing function span —
|
|
361
|
+
computed per comparison from one post-scan read, never persisted.
|
|
362
|
+
- **Observation:** evidence that a finding was detected in a particular scan.
|
|
363
|
+
- **Decision:** a reasoned accepted/not-applicable disposition with local or project
|
|
364
|
+
scope; it changes review state, not the raw observation.
|
|
365
|
+
- **Continuing** *(landed in the diff path)*: a head occurrence matched to a
|
|
366
|
+
compatible base occurrence by identity — movement is not addition. Matches
|
|
367
|
+
resting on content alone are flagged contextFallback; identical copies
|
|
368
|
+
matched by cardinality are flagged ambiguous.
|
|
369
|
+
- **No longer detected** *(landed in the diff path)*: absence established by
|
|
370
|
+
compatible, completed coverage.
|
|
371
|
+
- **Claimed fix:** a recorded explanation of remediation, separate from rescan evidence.
|
|
372
|
+
- **Reassessment:** a decision requires review because identity or applicability is
|
|
373
|
+
changed, conflicting, or uncertain.
|
package/README.md
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
# any-doctor
|
|
2
2
|
|
|
3
|
-
> Your agent writes the
|
|
3
|
+
> Your agent writes the doctor. Inspect its findings. Remember what matters.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
Any Doctor helps you and your agent find recurring problems in AI-written code
|
|
6
|
+
beyond ordinary lint configurations. **Doctors** are small deterministic analysis
|
|
7
|
+
programs that surface concrete concerns and codebase-specific conventions.
|
|
8
8
|
|
|
9
9
|
When none of them covers the convention you keep explaining in code review,
|
|
10
|
-
your agent writes a
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
your own agent writes a doctor for it against a typed `ctx` API, with positive
|
|
11
|
+
examples and valid lookalikes. Run it after coding, inspect the evidence, and
|
|
12
|
+
rescan after changes. Saved doctors run without model inference.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Analysis runs locally without an account, API key, or telemetry. Package/tool
|
|
15
|
+
installation can require downloads; the doctor runtime has no network access.
|
|
16
|
+
Remembered decisions and finding history are [planned](docs/plans/finding-lifecycle/proposal.md),
|
|
17
|
+
not available yet.
|
|
15
18
|
|
|
16
19
|
[](https://www.npmjs.com/package/any-doctor)
|
|
17
20
|
[](#)
|
|
@@ -45,11 +48,12 @@ Non-terminals and CI never see a prompt — output is stable and pipeable
|
|
|
45
48
|
| **openrouter-doctor** | OpenRouter discipline: stream errors surfaced, keep-alives skipped, cancellations that stop billing | 5 |
|
|
46
49
|
| **async-doctor** | Async and concurrency: dropped promise results, uncleared timers, fetch hygiene | 3 |
|
|
47
50
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
Checks ship positive and innocent-lookalike fixtures. `verify` compares an
|
|
52
|
+
exact multiset of rule/file/line and optional column, then runs shared innocent
|
|
53
|
+
and sensitivity corpora. Convex checks also declare per-check location coverage;
|
|
54
|
+
legacy undeclared coverage is reported as not exercised. Passing fixtures show
|
|
55
|
+
agreement on those cases, not a general accuracy guarantee. See
|
|
56
|
+
[the reliability protocol](docs/doctor-reliability.md).
|
|
53
57
|
|
|
54
58
|
## Write your own
|
|
55
59
|
|
|
@@ -64,7 +68,7 @@ writes two files:
|
|
|
64
68
|
- `doctors/your-doctor.mjs` — the analyzer: `meta` (checks, blind spots,
|
|
65
69
|
severity) + `doctor(ctx)`. One self-contained file; `ctx` is its entire
|
|
66
70
|
world (files, structural search via ast-grep, binding analysis, findings).
|
|
67
|
-
- `doctors/your-doctor.fixtures.mjs` —
|
|
71
|
+
- `doctors/your-doctor.fixtures.mjs` — regression evidence: seed codebases plus the
|
|
68
72
|
findings the doctor must produce, and the lookalikes it must ignore.
|
|
69
73
|
|
|
70
74
|
Then the loop agents love:
|
|
@@ -76,11 +80,11 @@ npx any-doctor@latest verify doctors/your-doctor.mjs
|
|
|
76
80
|
# ✔ accepts an awaited result
|
|
77
81
|
```
|
|
78
82
|
|
|
79
|
-
`missing`
|
|
80
|
-
non-zero until every fixture passes
|
|
83
|
+
`missing` and `unexpected` identify failures against the labeled fixture cases;
|
|
84
|
+
the exit code stays non-zero until every fixture passes. The skill teaches the sharp edges
|
|
81
85
|
(scope-analysis semantics, fixture-seed worlds, the adversarial
|
|
82
|
-
counter-fixture pass)
|
|
83
|
-
`verify` sandboxes
|
|
86
|
+
counter-fixture pass). Passing these cases does not measure general accuracy.
|
|
87
|
+
No project install needed; `verify` sandboxes the doctor runs.
|
|
84
88
|
|
|
85
89
|
## CI: the gate
|
|
86
90
|
|
|
@@ -100,17 +104,22 @@ npx any-doctor@latest run --all --fail-on warning --base origin/main
|
|
|
100
104
|
|
|
101
105
|
## Why trust a finding
|
|
102
106
|
|
|
103
|
-
- **
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
+
- **Repeatable analysis.** Hold source contents, doctor implementation, engine
|
|
108
|
+
versions, configuration, and capabilities fixed when comparing runs. No model
|
|
109
|
+
runs at scan time.
|
|
110
|
+
- **Executable evidence.** Run `verify` to test declared cases and shared
|
|
111
|
+
counterexamples. Discovery is not proof that a doctor passed verification;
|
|
112
|
+
independent real-code evaluation is still needed.
|
|
113
|
+
- **Specific claims.** A finding can establish a defect, flag a project convention,
|
|
114
|
+
or identify a review candidate. Its evidence should support that interpretation;
|
|
115
|
+
a suggested change can still require judgment.
|
|
107
116
|
- **Blind spots are data.** Every doctor declares what it cannot see, and
|
|
108
117
|
the report renders those declarations beside the findings.
|
|
109
118
|
- **Doctors are confined.** The runtime capability gate refuses to execute
|
|
110
119
|
a doctor that imports, writes, spawns, or touches the network — a
|
|
111
120
|
malicious doctor is refused before it runs, with no override.
|
|
112
|
-
- **The score
|
|
113
|
-
|
|
121
|
+
- **The score summarizes files without reported findings**, per doctor and overall.
|
|
122
|
+
It is not a probability of correctness or proof that unexamined code is safe.
|
|
114
123
|
|
|
115
124
|
## Docs
|
|
116
125
|
|
|
@@ -118,14 +127,21 @@ npx any-doctor@latest run --all --fail-on warning --base origin/main
|
|
|
118
127
|
|---|---|
|
|
119
128
|
| [skill/any-doctor.skill.md](skill/any-doctor.skill.md) | The authoring contract — what your agent reads to write doctors |
|
|
120
129
|
| [CONTEXT.md](CONTEXT.md) | Domain glossary — canonical terms |
|
|
121
|
-
| [docs/
|
|
122
|
-
| [docs/
|
|
130
|
+
| [docs/vision.md](docs/vision.md) | Current goals and product direction |
|
|
131
|
+
| [docs/features.md](docs/features.md) | Available features versus planned work |
|
|
132
|
+
| [docs/plans/analysis-improvements.md](docs/plans/analysis-improvements.md) | Next slice: source evidence, identity, and reliable Git-base comparisons |
|
|
133
|
+
| [docs/plans/finding-lifecycle/proposal.md](docs/plans/finding-lifecycle/proposal.md) | Planned decisions, history, and team workflows |
|
|
134
|
+
| [docs/plans/finding-lifecycle/design.md](docs/plans/finding-lifecycle/design.md) | State ownership, SQLite, Git convergence, and open choices |
|
|
135
|
+
| [docs/plans/finding-lifecycle/milestones.md](docs/plans/finding-lifecycle/milestones.md) | Implementation slices and acceptance evidence |
|
|
136
|
+
| [docs/HANDOFF.md](docs/HANDOFF.md) | Current handoff and next bounded task |
|
|
137
|
+
| [docs/decisions.md](docs/decisions.md) | Historical choices and explicit supersessions |
|
|
123
138
|
| [docs/kill-test.md](docs/kill-test.md) + [docs/RESULTS.md](docs/RESULTS.md) | The validation experiment and its numbers |
|
|
124
139
|
| [docs/REPAIR-LOG.md](docs/REPAIR-LOG.md) | Generation-bug categories — feeds the authoring skill |
|
|
125
140
|
| [docs/example-catalog.md](docs/example-catalog.md) | Rule intents across the JS ecosystem |
|
|
126
141
|
|
|
127
142
|
## Status
|
|
128
143
|
|
|
129
|
-
Pre-1.0
|
|
130
|
-
|
|
131
|
-
|
|
144
|
+
Pre-1.0. The next direction is reliable finding identity, remembered decisions,
|
|
145
|
+
team sharing, and bounded local history. Scanning stays available through npx
|
|
146
|
+
without mandatory initialization. See the [feature map](docs/features.md) for
|
|
147
|
+
current availability. MIT.
|
package/bin/analysis-host.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AnalysisFile, AnalysisSpans, Mode } from "./contract.js";
|
|
2
|
-
import { analysisStatus, analyzeBindings, analyzeSpans } from "./analysis.js";
|
|
1
|
+
import { AnalysisFile, AnalysisSpans, AnalysisCalls, Mode } from "./contract.js";
|
|
2
|
+
import { analysisStatus, analyzeBindings, analyzeSpans, analyzeCalls } from "./analysis.js";
|
|
3
3
|
type Analyzer = typeof analyzeBindings;
|
|
4
4
|
type SpansAnalyzer = typeof analyzeSpans;
|
|
5
5
|
type Status = typeof analysisStatus;
|
|
@@ -16,8 +16,10 @@ export type AnalysisResponse = {
|
|
|
16
16
|
file: AnalysisFile;
|
|
17
17
|
} | {
|
|
18
18
|
file: AnalysisSpans;
|
|
19
|
+
} | {
|
|
20
|
+
file: AnalysisCalls;
|
|
19
21
|
} | {
|
|
20
22
|
error: string;
|
|
21
23
|
};
|
|
22
|
-
export declare function handleAnalysisRequest(req: AnalysisRequestBody, mode: Mode, analyzer?: Analyzer, status?: Status, spansAnalyzer?: SpansAnalyzer): AnalysisResponse;
|
|
24
|
+
export declare function handleAnalysisRequest(req: AnalysisRequestBody, mode: Mode, analyzer?: Analyzer, status?: Status, spansAnalyzer?: SpansAnalyzer, callsAnalyzer?: typeof analyzeCalls): AnalysisResponse;
|
|
23
25
|
export {};
|
package/bin/analysis-host.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as path from "path";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { searchBase, withinBase, withinDir } from "./contract.js";
|
|
4
|
+
import { analysisStatus, analyzeBindings, analyzeSpans, analyzeCalls } from "./analysis.js";
|
|
5
5
|
// One cache per host process. The host lives in the runner process, so
|
|
6
6
|
// the lifetime is the any-doctor invocation; across a cohort's doctors
|
|
7
7
|
// the same unchanged file answers from memory.
|
|
8
8
|
const modelCache = new Map();
|
|
9
|
+
const callsCache = new Map();
|
|
9
10
|
const spansCache = new Map();
|
|
10
11
|
// Test seam: the model cache is keyed by mtime+size for the process
|
|
11
12
|
// lifetime; tests bust it between cases. Invisible to slop-doctor's
|
|
@@ -13,8 +14,9 @@ const spansCache = new Map();
|
|
|
13
14
|
export function clearAnalysisCache() {
|
|
14
15
|
modelCache.clear();
|
|
15
16
|
spansCache.clear();
|
|
17
|
+
callsCache.clear();
|
|
16
18
|
}
|
|
17
|
-
export function handleAnalysisRequest(req, mode, analyzer = analyzeBindings, status = analysisStatus, spansAnalyzer = analyzeSpans) {
|
|
19
|
+
export function handleAnalysisRequest(req, mode, analyzer = analyzeBindings, status = analysisStatus, spansAnalyzer = analyzeSpans, callsAnalyzer = analyzeCalls) {
|
|
18
20
|
const base = searchBase(mode);
|
|
19
21
|
const root = typeof req.root === "string" ? path.resolve(req.root) : "";
|
|
20
22
|
if (base === "" || !withinBase(root, base)) {
|
|
@@ -24,20 +26,22 @@ export function handleAnalysisRequest(req, mode, analyzer = analyzeBindings, sta
|
|
|
24
26
|
const s = status();
|
|
25
27
|
return s.available ? { available: true } : { available: false, reason: s.reason };
|
|
26
28
|
}
|
|
27
|
-
if (req.kind === "bindings" || req.kind === "spans") {
|
|
29
|
+
if (req.kind === "bindings" || req.kind === "spans" || req.kind === "calls") {
|
|
28
30
|
if (typeof req.file !== "string" || req.file === "") {
|
|
29
31
|
return { error: `ctx.analysis.${req.kind} needs a "file" path` };
|
|
30
32
|
}
|
|
31
33
|
const abs = path.resolve(root, req.file);
|
|
32
|
-
if (!
|
|
34
|
+
if (!withinDir(abs, root)) {
|
|
33
35
|
return { error: `ctx.analysis failed: file is outside the search root: ${req.file}` };
|
|
34
36
|
}
|
|
35
37
|
if (req.kind === "bindings") {
|
|
36
38
|
return cachedModel(abs, root, modelCache, analyzer, req.file);
|
|
37
39
|
}
|
|
40
|
+
if (req.kind === "calls")
|
|
41
|
+
return cachedModel(abs, root, callsCache, callsAnalyzer, req.file);
|
|
38
42
|
return cachedModel(abs, root, spansCache, spansAnalyzer, req.file);
|
|
39
43
|
}
|
|
40
|
-
return { error: `unknown analysis kind ${JSON.stringify(req.kind)} — known kinds: available, bindings, spans` };
|
|
44
|
+
return { error: `unknown analysis kind ${JSON.stringify(req.kind)} — known kinds: available, bindings, spans, calls` };
|
|
41
45
|
}
|
|
42
46
|
// The shared per-file model lifecycle: stat (cache hit on mtime+size),
|
|
43
47
|
// read, compute, cache. Bindings and spans are the same policy over two
|
package/bin/analysis.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AnalysisFile, AnalysisSpans, BindingInfo, BindingRef, SpanInfo } from "./contract.js";
|
|
1
|
+
import { AnalysisFile, AnalysisSpans, AnalysisCalls, BindingInfo, BindingRef, SpanInfo } from "./contract.js";
|
|
2
2
|
export type { AnalysisFile, AnalysisSpans, BindingInfo, BindingRef, SpanInfo };
|
|
3
3
|
export interface AnalysisStatus {
|
|
4
4
|
available: true;
|
|
@@ -15,6 +15,13 @@ export type AnalysisResult = {
|
|
|
15
15
|
ok: false;
|
|
16
16
|
error: string;
|
|
17
17
|
};
|
|
18
|
+
export type CallsResult = {
|
|
19
|
+
ok: true;
|
|
20
|
+
file: AnalysisCalls;
|
|
21
|
+
} | {
|
|
22
|
+
ok: false;
|
|
23
|
+
error: string;
|
|
24
|
+
};
|
|
18
25
|
export type SpansResult = {
|
|
19
26
|
ok: true;
|
|
20
27
|
file: AnalysisSpans;
|
|
@@ -24,3 +31,4 @@ export type SpansResult = {
|
|
|
24
31
|
};
|
|
25
32
|
export declare function analyzeSpans(file: string, source: string): SpansResult;
|
|
26
33
|
export declare function analyzeBindings(file: string, source: string): AnalysisResult;
|
|
34
|
+
export declare function analyzeCalls(file: string, source: string): CallsResult;
|