@drafthq/draft 3.7.2 → 5.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.
- package/.claude-plugin/marketplace.json +6 -3
- package/.claude-plugin/plugin.json +4 -2
- package/.cursor-plugin/plugin.json +4 -2
- package/LICENSE +1 -1
- package/README.md +7 -7
- package/bin/README.md +14 -13
- package/cli/src/cli.js +2 -2
- package/cli/src/installer.js +4 -2
- package/cli/src/lib/cursor-registry.js +2 -2
- package/cli/src/lib/graph.js +2 -1
- package/core/shared/condensation.md +8 -7
- package/core/shared/draft-context-loading.md +1 -1
- package/core/shared/graph-query.md +31 -23
- package/core/templates/architecture.md +1 -1
- package/integrations/agents/AGENTS.md +43 -34
- package/integrations/copilot/.github/copilot-instructions.md +43 -34
- package/package.json +7 -3
- package/scripts/fetch-memory-engine.sh +44 -11
- package/scripts/lib.sh +1 -1
- package/scripts/tools/_graph_queries.sh +28 -12
- package/scripts/tools/_lib.sh +38 -29
- package/scripts/tools/check-repo-size.sh +5 -1
- package/scripts/tools/cycle-detect.sh +11 -7
- package/scripts/tools/graph-callers.sh +1 -1
- package/scripts/tools/graph-impact.sh +63 -35
- package/scripts/tools/graph-init.sh +5 -10
- package/scripts/tools/graph-preflight.sh +6 -3
- package/scripts/tools/graph-query.sh +8 -7
- package/scripts/tools/graph-snapshot.sh +13 -24
- package/scripts/tools/graph-traces.sh +2 -2
- package/scripts/tools/hotspot-rank.sh +10 -1
- package/scripts/tools/mermaid-from-graph.sh +1 -1
- package/scripts/tools/okf-emit-catalog.sh +3 -0
- package/scripts/tools/okf-render-views.sh +6 -4
- package/scripts/tools/okf-validate.sh +5 -0
- package/scripts/tools/resolve-tools.sh +5 -3
- package/scripts/tools/scan-markers.sh +9 -1
- package/scripts/tools/verify-graph-binary.sh +14 -2
- package/skills/draft/intent-mapping.md +1 -1
- package/skills/implement/SKILL.md +1 -1
|
@@ -6025,7 +6025,7 @@ After a phase passes review, refresh `metadata.json.impact` so future tracks can
|
|
|
6025
6025
|
"$DRAFT_TOOLS/graph-impact.sh" --repo . --file <path>
|
|
6026
6026
|
```
|
|
6027
6027
|
|
|
6028
|
-
Aggregate across all files: `downstream_files` =
|
|
6028
|
+
Aggregate across all files: `downstream_files` = count of the union of each query's `downstream_files` array, `downstream_modules` = union of `affected_modules`, `max_depth` = max across queries, `by_category` = sum of each query's `by_category`. If the graph is absent, leave these fields as zeros / empty arrays — the snapshot still records the directly-touched files.
|
|
6029
6029
|
|
|
6030
6030
|
3. **Write metadata.json** with the populated `impact` block and `computed_at` set to the current timestamp.
|
|
6031
6031
|
|
|
@@ -9604,7 +9604,7 @@ Prefer `draft docs` going forward for all authoring requests. The legacy direct
|
|
|
9604
9604
|
|
|
9605
9605
|
## Discover Router
|
|
9606
9606
|
|
|
9607
|
-
When user says "discover debug" or "draft discover <intent>" (debug, bughunt, reviews, coverage, learn,
|
|
9607
|
+
When user says "discover debug" or "draft discover <intent>" (debug, bughunt, reviews, coverage, learn, tour, impact, etc.):
|
|
9608
9608
|
|
|
9609
9609
|
`draft discover` is the single front door for all investigation, auditing, pattern learning, and quality exploration activities.
|
|
9610
9610
|
|
|
@@ -17030,7 +17030,7 @@ If `draft/graph/schema.yaml` exists, the project has automated graph analysis da
|
|
|
17030
17030
|
|
|
17031
17031
|
| File | Purpose | Content |
|
|
17032
17032
|
|------|---------|---------|
|
|
17033
|
-
| `draft/graph/schema.yaml` | Gate marker (engine
|
|
17033
|
+
| `draft/graph/schema.yaml` | Gate marker (engine metadata + point-of-index counts); presence gates graph use | YAML, ~10 lines |
|
|
17034
17034
|
|
|
17035
17035
|
Note: `.ai-context.md` embeds a condensed graph summary (`GRAPH:MODULES`, `GRAPH:HOTSPOTS`, `GRAPH:CYCLES`) for first-pass structural ground truth. Deep structural data is queried live from the engine (see Live structural queries below).
|
|
17036
17036
|
|
|
@@ -17558,7 +17558,7 @@ Any skill that mutates `architecture.md` should execute this subroutine afterwar
|
|
|
17558
17558
|
| Input | Path | Description |
|
|
17559
17559
|
|-------|------|-------------|
|
|
17560
17560
|
| architecture.md | `draft/architecture.md` | Comprehensive human-readable engineering reference (source of truth) |
|
|
17561
|
-
|
|
|
17561
|
+
| Architecture view | `scripts/tools/graph-arch.sh --repo .` | Live graph metrics for tier computation (optional — skip when `draft/graph/schema.yaml` is absent) |
|
|
17562
17562
|
|
|
17563
17563
|
## Outputs
|
|
17564
17564
|
|
|
@@ -17571,11 +17571,12 @@ Any skill that mutates `architecture.md` should execute this subroutine afterwar
|
|
|
17571
17571
|
|
|
17572
17572
|
## Target Size
|
|
17573
17573
|
|
|
17574
|
-
Compute tier from `draft
|
|
17574
|
+
Compute tier from the live architecture view (the same metrics as `draft init` Step 1.4.5 — `schema.yaml` carries only counts, not these):
|
|
17575
17575
|
|
|
17576
|
-
|
|
17577
|
-
|
|
17578
|
-
|
|
17576
|
+
ARCH=$("$DRAFT_TOOLS/graph-arch.sh" --repo .) (DRAFT_TOOLS: resolver below)
|
|
17577
|
+
M = $ARCH | jq '.packages | length' (modules)
|
|
17578
|
+
F = $ARCH | jq '[.node_labels[] | select(.label=="Function" or .label=="Method") | .count] | add // 0' (functions + methods)
|
|
17579
|
+
P = $ARCH | jq '.routes | length' (routes / RPCs)
|
|
17579
17580
|
|
|
17580
17581
|
| Tier | Label | Condition | Budget |
|
|
17581
17582
|
|------|--------|----------------------------------------|---------------|
|
|
@@ -17585,7 +17586,7 @@ Compute tier from `draft/graph/schema.yaml` after graph build:
|
|
|
17585
17586
|
| 4 | large | M≤100 AND F≤5000 AND P≤500 | 400–600 lines |
|
|
17586
17587
|
| 5 | XL | M>100 OR F>5000 OR P>500 | 600–900 lines |
|
|
17587
17588
|
|
|
17588
|
-
If `schema.yaml` does not exist: default to tier 2 (180–280 lines).
|
|
17589
|
+
If `schema.yaml` does not exist (no graph) or `graph-arch.sh` reports `source: unavailable`: default to tier 2 (180–280 lines).
|
|
17589
17590
|
|
|
17590
17591
|
- Below tier minimum: incomplete condensation — ensure all sections are represented
|
|
17591
17592
|
- Above tier maximum: insufficient compression — apply prioritization rules below
|
|
@@ -17705,7 +17706,7 @@ Before writing `draft/.ai-context.md`, verify:
|
|
|
17705
17706
|
- [ ] No references to `architecture.md` (file must be self-contained)
|
|
17706
17707
|
- [ ] All invariants from architecture.md are preserved
|
|
17707
17708
|
- [ ] Extension cookbooks are complete (an agent can follow them without other files)
|
|
17708
|
-
- [ ] Output is within tier budget bounds (compute from
|
|
17709
|
+
- [ ] Output is within tier budget bounds (compute from `graph-arch.sh` or default tier 2)
|
|
17709
17710
|
- [ ] GRAPH:HOTSPOTS present (or note "No hotspot data available" if graph absent)
|
|
17710
17711
|
- [ ] GRAPH:CYCLES present ("None ✓" or cycle list; or note if graph absent)
|
|
17711
17712
|
- [ ] GRAPH:MODULE-HOTSPOTS present for tier ≥ 3 (or note if no hotspot data)
|
|
@@ -18204,7 +18205,7 @@ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}
|
|
|
18204
18205
|
|---|---|---|
|
|
18205
18206
|
| `bash "$DRAFT_TOOLS/hotspot-rank.sh" [--top N]` | complexity-weighted hotspots | Emits `{hotspots:[],source:"unavailable"}` and exits 2 |
|
|
18206
18207
|
| `bash "$DRAFT_TOOLS/cycle-detect.sh"` | call cycles | Emits `{cycles:[],source:"unavailable"}` and exits 2 |
|
|
18207
|
-
| `bash "$DRAFT_TOOLS/mermaid-from-graph.sh" [--diagram module-deps\|co-change\|proto-map]` | diagram text |
|
|
18208
|
+
| `bash "$DRAFT_TOOLS/mermaid-from-graph.sh" [--diagram module-deps\|co-change\|proto-map]` | diagram text | Unavailable stub (`graph not built`) vs empty-graph stub (`no edges`); both exit 2 |
|
|
18208
18209
|
| `bash "$DRAFT_TOOLS/graph-callers.sh" --symbol N [--transitive[=N]] [--prod-only] [--qualified]` | callers | `{callers:[],status:"unavailable",source:"unavailable"}`, exit 2 |
|
|
18209
18210
|
| `bash "$DRAFT_TOOLS/graph-snippet.sh" --qualified N` | verified source + caller/callee counts | `{status:"unavailable",source:"unavailable"}`, exit 2 |
|
|
18210
18211
|
| `bash "$DRAFT_TOOLS/graph-search.sh" --query "STR" [--limit N]` | semantic/ranked search | `{results:[],source:"unavailable"}`, exit 2 |
|
|
@@ -18216,7 +18217,7 @@ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}
|
|
|
18216
18217
|
| `bash "$DRAFT_TOOLS/graph-query.sh" (--cypher STR \| --tool NAME --json '{...}')` | generic read-only passthrough | `{source:"unavailable"}`, exit 2 |
|
|
18217
18218
|
| `bash "$DRAFT_TOOLS/graph-traces.sh" ingest --file F --experimental` | runtime traces (experimental write) | `{source:"unavailable"}`, exit 2 |
|
|
18218
18219
|
|
|
18219
|
-
For
|
|
18220
|
+
For an engine tool without a dedicated wrapper, use the read-only passthrough `graph-query.sh --repo . --tool <name> --json '{...}'` (project injected, write tools refused, `source:"unavailable"` on failure). Never call the engine binary directly — that skips engine resolution, the index refresh before each query, and the fail-loud contract.
|
|
18220
18221
|
|
|
18221
18222
|
### Capability wrappers & dialect limits (graph-tooling-v2)
|
|
18222
18223
|
|
|
@@ -18224,8 +18225,9 @@ All Cypher lives in `scripts/tools/_graph_queries.sh` (the single source of quer
|
|
|
18224
18225
|
truth). Wrappers are thin arg-parse → builder → fail-loud JSON. Three contracts
|
|
18225
18226
|
matter when consuming them:
|
|
18226
18227
|
|
|
18227
|
-
**Fail-loud status.** Symbol-scoped wrappers (`graph-callers`, `graph-
|
|
18228
|
-
`graph-tests --symbol`, `graph-hierarchy --symbol/--derived`,
|
|
18228
|
+
**Fail-loud status.** Symbol-scoped wrappers (`graph-callers`, `graph-impact`,
|
|
18229
|
+
`graph-snippet`, `graph-tests --symbol`, `graph-hierarchy --symbol/--derived`,
|
|
18230
|
+
`graph-errors`)
|
|
18229
18231
|
emit a `status` field that distinguishes the three real outcomes — never read a
|
|
18230
18232
|
bare `[]` as a confirmed true negative:
|
|
18231
18233
|
|
|
@@ -18234,9 +18236,11 @@ bare `[]` as a confirmed true negative:
|
|
|
18234
18236
|
| `ok` | node found, edges returned |
|
|
18235
18237
|
| `no-edges` | node exists but has no matching edge (a *real* negative) |
|
|
18236
18238
|
| `no-match` | the named symbol was not found at all (check the name / try `--qualified`) |
|
|
18237
|
-
| `unavailable` | engine could not be resolved (exit 2) |
|
|
18239
|
+
| `unavailable` | engine could not be resolved, or engine returned shapeless/non-row JSON (exit 2) |
|
|
18238
18240
|
|
|
18239
|
-
**
|
|
18241
|
+
**Shapeless JSON is unavailable.** `gq_run` requires `has("rows") and (.rows|type=="array")`. A bare `{}` (or any object without a `.rows` array) is not a measured empty result — wrappers emit `source:"unavailable"` and a non-zero exit. Do not read `{}` as "no callers / no cycles / no edges". `graph-impact`, `graph-callers`, and `mermaid-from-graph` also require their tool-shaped object; a failed snapshot refresh does not rewrite `schema.yaml`.
|
|
18242
|
+
|
|
18243
|
+
**Verified engine param shapes** (engine v0.9.0 — the runtime source of truth is
|
|
18240
18244
|
`get_graph_schema`; do not hardcode a property set):
|
|
18241
18245
|
|
|
18242
18246
|
```bash
|
|
@@ -18249,13 +18253,18 @@ get_graph_schema '{"project":P}' # → {node_labels:[{label,count,properties}
|
|
|
18249
18253
|
|
|
18250
18254
|
**Cypher dialect — keep queries inside the SAFE set:**
|
|
18251
18255
|
|
|
18252
|
-
- ✅ SAFE:
|
|
18253
|
-
`
|
|
18254
|
-
`[:
|
|
18255
|
-
|
|
18256
|
-
|
|
18257
|
-
|
|
18256
|
+
- ✅ SAFE: `=`, `<>`/`!=`, `<`, `>`, `<=`, `>=` against a literal; `STARTS WITH`,
|
|
18257
|
+
`NOT x STARTS WITH`, `AND`, `OR`; explicit and variable-length patterns
|
|
18258
|
+
(`[:R*1..3]`, fixed depth `[:R*2..2]`); relationship-type alternation `[:A|B]`;
|
|
18259
|
+
`coalesce()`; `DISTINCT`; `count(x)`, `count(DISTINCT x)`; `WITH`-grouping
|
|
18260
|
+
aggregation.
|
|
18261
|
+
- ❌ UNSAFE: comparing one property against another (`a.x < b.x`), `NOT EXISTS(...)`,
|
|
18262
|
+
`NOT (pattern)`, path variables (`p=(...)`, `length(p)`) — all rejected; and
|
|
18263
|
+
multi-pattern joins (`MATCH (a)…, (b)…`), which parse but ignore `RETURN` and
|
|
18264
|
+
`LIMIT`. `graph-query.sh --cypher` returns the engine's raw error, not a silent
|
|
18258
18265
|
empty — but the builders never emit these forms.
|
|
18266
|
+
- ⚠️ `LIMIT` applies before `DISTINCT`: `RETURN DISTINCT … LIMIT n` can return
|
|
18267
|
+
fewer than n rows while more exist. Judge truncation on raw rows.
|
|
18259
18268
|
|
|
18260
18269
|
**Caveats consumers must respect:**
|
|
18261
18270
|
|
|
@@ -18290,22 +18299,22 @@ The only committed file is the gate marker:
|
|
|
18290
18299
|
|
|
18291
18300
|
| File | Role |
|
|
18292
18301
|
|------|------|
|
|
18293
|
-
| `draft/graph/schema.yaml` | Engine
|
|
18302
|
+
| `draft/graph/schema.yaml` | Engine metadata and point-of-index counts (provenance, not authoritative). Carries **no graph data**. Its presence is the **gate** (see Pre-Check) — it signals the engine is wired for this repo. Written by `scripts/tools/graph-snapshot.sh`. |
|
|
18294
18303
|
|
|
18295
|
-
All structural data is obtained live
|
|
18304
|
+
All structural data is obtained live through the query-tool wrappers under `scripts/tools/`; `graph-query.sh --tool` covers every read-only engine tool that has no dedicated wrapper. The wrappers refresh the repo's index in the engine's own cache before each query, so no committed files are required.
|
|
18296
18305
|
|
|
18297
18306
|
### How skills query (engine is the interface; jq is optional)
|
|
18298
18307
|
|
|
18299
|
-
- **The engine is the query
|
|
18308
|
+
- **The engine is the query; the wrappers are the interface.** Every wrapper drives the engine's CLI and returns JSON. There is no other query surface.
|
|
18300
18309
|
- **Prefer the wrappers — they resolve the engine for you.** `graph-arch.sh` (architecture view: packages/routes/layers/hotspots), `graph-callers.sh`, `hotspot-rank.sh`, `graph-impact.sh`, `cycle-detect.sh`, `mermaid-from-graph.sh` return already-shaped JSON. The engine binary is usually **not on `$PATH`** (it lives under `~/.cache/draft/bin/`); the wrappers locate it via `_lib.sh:find_memory_bin`, so a skill using a wrapper needs no resolution step.
|
|
18301
|
-
- **
|
|
18310
|
+
- **Tools without a dedicated wrapper go through `graph-query.sh`:** `"$DRAFT_TOOLS/graph-query.sh" --repo . --tool search_code --json '{"pattern":"..."}'` (likewise `trace_path`, `get_graph_schema`, `index_status`). `search_graph` has its own wrapper, `graph-search.sh`.
|
|
18302
18311
|
- **`jq` is not a query tool — it only trims output.** Reach for it solely to slice a *large* response (chiefly the `get_architecture` blob) down to the field you need, for token economy. The agent can read raw JSON directly; jq is an optimization, not a requirement. Don't pipe wrapper output through jq unless you genuinely need a sub-field.
|
|
18303
18312
|
|
|
18304
18313
|
The engine uses a **unified, language-agnostic** node model — `Function`, `Method`, `Class`, `Module`, `File`, `Folder`, `Route`, `Section`, `Variable` (language is inferred from file extension) — and edges `CALLS`, `DEFINES`, `CONTAINS_FILE`, `IMPORTS`, `HTTP_CALLS`, `FILE_CHANGES_WITH`, `SEMANTICALLY_RELATED`, `SIMILAR_TO`. Each node carries `file_path` + `start_line`/`end_line` and rich `properties` (complexity, signature, parent_class), and the engine exposes full-text (`search_code`) and semantic search — none of which a committed snapshot reproduced.
|
|
18305
18314
|
|
|
18306
18315
|
## Query Tools
|
|
18307
18316
|
|
|
18308
|
-
Live queries go through the shell tools under `scripts/tools/`, which drive the engine and shape results into stable JSON. Each tool resolves the engine (see Finding the Engine), indexes the repo on demand, and emits `source: "memory-graph"` on success or `source: "unavailable"` (non-zero exit) when the engine cannot be resolved. Set `DRAFT_MEMORY_DISABLE=1` to force the engine off; all tools then degrade
|
|
18317
|
+
Live queries go through the shell tools under `scripts/tools/`, which drive the engine and shape results into stable JSON. Each tool resolves the engine (see Finding the Engine), indexes the repo on demand, and emits `source: "memory-graph"` on success or `source: "unavailable"` (non-zero exit) when the engine cannot be resolved **or returns shapeless JSON** (missing `.rows` array). Set `DRAFT_MEMORY_DISABLE=1` to force the engine off; all tools then degrade to `unavailable` rather than inventing empty results.
|
|
18309
18318
|
|
|
18310
18319
|
### Callers — who calls this function?
|
|
18311
18320
|
|
|
@@ -18318,11 +18327,11 @@ Output: `{symbol, callers[{name, file}], source}`. Use when enumerating call sit
|
|
|
18318
18327
|
### Impact — blast radius of a file or symbol
|
|
18319
18328
|
|
|
18320
18329
|
```bash
|
|
18321
|
-
"$DRAFT_TOOLS/graph-impact.sh" --repo . --file <path> #
|
|
18322
|
-
"$DRAFT_TOOLS/graph-impact.sh" --repo . --symbol <name> # transitive callers of a function
|
|
18330
|
+
"$DRAFT_TOOLS/graph-impact.sh" --repo . --file <path> # dependents of a file: its symbols' callers + its importers
|
|
18331
|
+
"$DRAFT_TOOLS/graph-impact.sh" --repo . --symbol <name> # dependents (transitive callers) of a function
|
|
18323
18332
|
```
|
|
18324
18333
|
|
|
18325
|
-
Output: `{target, kind, impacted[{name, file, hop}], source}`. Use when sizing risk before modifying a file or symbol, especially high-fan-in hotspots.
|
|
18334
|
+
Output: `{target, kind, impacted[{name, file, qualified, hop}], downstream_files, affected_modules, max_depth, by_category{code,test}, status, truncated, source}`. `impacted` lists each dependent once at its nearest hop (default depth 3), capped at 200 with `truncated:true`; the aggregates always cover the full set. `status` is `ok`, `no-edges` (target known, nothing depends on it), or `no-match` (target unknown to the graph — check the path). Use when sizing risk before modifying a file or symbol, especially high-fan-in hotspots.
|
|
18326
18335
|
|
|
18327
18336
|
### Hotspots — fan-in ranking
|
|
18328
18337
|
|
|
@@ -18433,7 +18442,7 @@ Unlocks any edge type or node property without a purpose-built wrapper. Write ve
|
|
|
18433
18442
|
"$DRAFT_TOOLS/graph-snapshot.sh" --repo .
|
|
18434
18443
|
```
|
|
18435
18444
|
|
|
18436
|
-
Indexes the repo into the engine and writes the `draft/graph/schema.yaml` gate marker
|
|
18445
|
+
Indexes the repo into the engine and writes the `draft/graph/schema.yaml` gate marker, and prints the `detect_changes` delta (`changed_files`/`impacted_symbols`) without committing it. It writes **no** graph data. Run during `draft init` and `draft graph`, or whenever the index should be refreshed.
|
|
18437
18446
|
|
|
18438
18447
|
## Finding the Engine (Resolution + Usage Report)
|
|
18439
18448
|
|
|
@@ -18472,9 +18481,9 @@ The engine indexes C/C++, Go, Python, TypeScript/JS, and more (tree-sitter, 159
|
|
|
18472
18481
|
| Scenario | Behavior |
|
|
18473
18482
|
|----------|----------|
|
|
18474
18483
|
| No engine resolvable (or `DRAFT_MEMORY_DISABLE=1`) | Skip graph indexing in init; all skills proceed without graph data; tools emit `source: unavailable` |
|
|
18475
|
-
| Engine present but a query fails |
|
|
18484
|
+
| Engine present but a query fails, or returns shapeless `{}` | Treat as unavailable — never as a true-negative empty result; skills proceed without graph data |
|
|
18476
18485
|
| `draft/graph/schema.yaml` exists | Engine is wired — use live query tools as needed during the run |
|
|
18477
|
-
| Engine index out of date |
|
|
18486
|
+
| Engine index out of date | Every wrapper re-indexes incrementally (content-based, git-aware) before it queries — ~0.1 s on an unchanged repo — so live answers track the working tree, including the run's own edits. `graph-snapshot.sh` (or init) also refreshes the `schema.yaml` marker. |
|
|
18478
18487
|
|
|
18479
18488
|
</core-file>
|
|
18480
18489
|
|
|
@@ -20431,7 +20440,7 @@ graph:
|
|
|
20431
20440
|
cpp: "{high}"
|
|
20432
20441
|
go: "{approximate | high}"
|
|
20433
20442
|
stats:
|
|
20434
|
-
modules: "{N from
|
|
20443
|
+
modules: "{N from engine: get_architecture .packages}"
|
|
20435
20444
|
edges: "{total_edges from engine: get_architecture .edges}"
|
|
20436
20445
|
hotspots: "{N}"
|
|
20437
20446
|
notes: "{explicit fidelity summary from engine: get_architecture .languages/.packages}"
|
|
@@ -6025,7 +6025,7 @@ After a phase passes review, refresh `metadata.json.impact` so future tracks can
|
|
|
6025
6025
|
"$DRAFT_TOOLS/graph-impact.sh" --repo . --file <path>
|
|
6026
6026
|
```
|
|
6027
6027
|
|
|
6028
|
-
Aggregate across all files: `downstream_files` =
|
|
6028
|
+
Aggregate across all files: `downstream_files` = count of the union of each query's `downstream_files` array, `downstream_modules` = union of `affected_modules`, `max_depth` = max across queries, `by_category` = sum of each query's `by_category`. If the graph is absent, leave these fields as zeros / empty arrays — the snapshot still records the directly-touched files.
|
|
6029
6029
|
|
|
6030
6030
|
3. **Write metadata.json** with the populated `impact` block and `computed_at` set to the current timestamp.
|
|
6031
6031
|
|
|
@@ -9604,7 +9604,7 @@ Prefer `draft docs` going forward for all authoring requests. The legacy direct
|
|
|
9604
9604
|
|
|
9605
9605
|
## Discover Router
|
|
9606
9606
|
|
|
9607
|
-
When user says "discover debug" or "draft discover <intent>" (debug, bughunt, reviews, coverage, learn,
|
|
9607
|
+
When user says "discover debug" or "draft discover <intent>" (debug, bughunt, reviews, coverage, learn, tour, impact, etc.):
|
|
9608
9608
|
|
|
9609
9609
|
`draft discover` is the single front door for all investigation, auditing, pattern learning, and quality exploration activities.
|
|
9610
9610
|
|
|
@@ -17030,7 +17030,7 @@ If `draft/graph/schema.yaml` exists, the project has automated graph analysis da
|
|
|
17030
17030
|
|
|
17031
17031
|
| File | Purpose | Content |
|
|
17032
17032
|
|------|---------|---------|
|
|
17033
|
-
| `draft/graph/schema.yaml` | Gate marker (engine
|
|
17033
|
+
| `draft/graph/schema.yaml` | Gate marker (engine metadata + point-of-index counts); presence gates graph use | YAML, ~10 lines |
|
|
17034
17034
|
|
|
17035
17035
|
Note: `.ai-context.md` embeds a condensed graph summary (`GRAPH:MODULES`, `GRAPH:HOTSPOTS`, `GRAPH:CYCLES`) for first-pass structural ground truth. Deep structural data is queried live from the engine (see Live structural queries below).
|
|
17036
17036
|
|
|
@@ -17558,7 +17558,7 @@ Any skill that mutates `architecture.md` should execute this subroutine afterwar
|
|
|
17558
17558
|
| Input | Path | Description |
|
|
17559
17559
|
|-------|------|-------------|
|
|
17560
17560
|
| architecture.md | `draft/architecture.md` | Comprehensive human-readable engineering reference (source of truth) |
|
|
17561
|
-
|
|
|
17561
|
+
| Architecture view | `scripts/tools/graph-arch.sh --repo .` | Live graph metrics for tier computation (optional — skip when `draft/graph/schema.yaml` is absent) |
|
|
17562
17562
|
|
|
17563
17563
|
## Outputs
|
|
17564
17564
|
|
|
@@ -17571,11 +17571,12 @@ Any skill that mutates `architecture.md` should execute this subroutine afterwar
|
|
|
17571
17571
|
|
|
17572
17572
|
## Target Size
|
|
17573
17573
|
|
|
17574
|
-
Compute tier from `draft
|
|
17574
|
+
Compute tier from the live architecture view (the same metrics as `draft init` Step 1.4.5 — `schema.yaml` carries only counts, not these):
|
|
17575
17575
|
|
|
17576
|
-
|
|
17577
|
-
|
|
17578
|
-
|
|
17576
|
+
ARCH=$("$DRAFT_TOOLS/graph-arch.sh" --repo .) (DRAFT_TOOLS: resolver below)
|
|
17577
|
+
M = $ARCH | jq '.packages | length' (modules)
|
|
17578
|
+
F = $ARCH | jq '[.node_labels[] | select(.label=="Function" or .label=="Method") | .count] | add // 0' (functions + methods)
|
|
17579
|
+
P = $ARCH | jq '.routes | length' (routes / RPCs)
|
|
17579
17580
|
|
|
17580
17581
|
| Tier | Label | Condition | Budget |
|
|
17581
17582
|
|------|--------|----------------------------------------|---------------|
|
|
@@ -17585,7 +17586,7 @@ Compute tier from `draft/graph/schema.yaml` after graph build:
|
|
|
17585
17586
|
| 4 | large | M≤100 AND F≤5000 AND P≤500 | 400–600 lines |
|
|
17586
17587
|
| 5 | XL | M>100 OR F>5000 OR P>500 | 600–900 lines |
|
|
17587
17588
|
|
|
17588
|
-
If `schema.yaml` does not exist: default to tier 2 (180–280 lines).
|
|
17589
|
+
If `schema.yaml` does not exist (no graph) or `graph-arch.sh` reports `source: unavailable`: default to tier 2 (180–280 lines).
|
|
17589
17590
|
|
|
17590
17591
|
- Below tier minimum: incomplete condensation — ensure all sections are represented
|
|
17591
17592
|
- Above tier maximum: insufficient compression — apply prioritization rules below
|
|
@@ -17705,7 +17706,7 @@ Before writing `draft/.ai-context.md`, verify:
|
|
|
17705
17706
|
- [ ] No references to `architecture.md` (file must be self-contained)
|
|
17706
17707
|
- [ ] All invariants from architecture.md are preserved
|
|
17707
17708
|
- [ ] Extension cookbooks are complete (an agent can follow them without other files)
|
|
17708
|
-
- [ ] Output is within tier budget bounds (compute from
|
|
17709
|
+
- [ ] Output is within tier budget bounds (compute from `graph-arch.sh` or default tier 2)
|
|
17709
17710
|
- [ ] GRAPH:HOTSPOTS present (or note "No hotspot data available" if graph absent)
|
|
17710
17711
|
- [ ] GRAPH:CYCLES present ("None ✓" or cycle list; or note if graph absent)
|
|
17711
17712
|
- [ ] GRAPH:MODULE-HOTSPOTS present for tier ≥ 3 (or note if no hotspot data)
|
|
@@ -18204,7 +18205,7 @@ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}
|
|
|
18204
18205
|
|---|---|---|
|
|
18205
18206
|
| `bash "$DRAFT_TOOLS/hotspot-rank.sh" [--top N]` | complexity-weighted hotspots | Emits `{hotspots:[],source:"unavailable"}` and exits 2 |
|
|
18206
18207
|
| `bash "$DRAFT_TOOLS/cycle-detect.sh"` | call cycles | Emits `{cycles:[],source:"unavailable"}` and exits 2 |
|
|
18207
|
-
| `bash "$DRAFT_TOOLS/mermaid-from-graph.sh" [--diagram module-deps\|co-change\|proto-map]` | diagram text |
|
|
18208
|
+
| `bash "$DRAFT_TOOLS/mermaid-from-graph.sh" [--diagram module-deps\|co-change\|proto-map]` | diagram text | Unavailable stub (`graph not built`) vs empty-graph stub (`no edges`); both exit 2 |
|
|
18208
18209
|
| `bash "$DRAFT_TOOLS/graph-callers.sh" --symbol N [--transitive[=N]] [--prod-only] [--qualified]` | callers | `{callers:[],status:"unavailable",source:"unavailable"}`, exit 2 |
|
|
18209
18210
|
| `bash "$DRAFT_TOOLS/graph-snippet.sh" --qualified N` | verified source + caller/callee counts | `{status:"unavailable",source:"unavailable"}`, exit 2 |
|
|
18210
18211
|
| `bash "$DRAFT_TOOLS/graph-search.sh" --query "STR" [--limit N]` | semantic/ranked search | `{results:[],source:"unavailable"}`, exit 2 |
|
|
@@ -18216,7 +18217,7 @@ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}
|
|
|
18216
18217
|
| `bash "$DRAFT_TOOLS/graph-query.sh" (--cypher STR \| --tool NAME --json '{...}')` | generic read-only passthrough | `{source:"unavailable"}`, exit 2 |
|
|
18217
18218
|
| `bash "$DRAFT_TOOLS/graph-traces.sh" ingest --file F --experimental` | runtime traces (experimental write) | `{source:"unavailable"}`, exit 2 |
|
|
18218
18219
|
|
|
18219
|
-
For
|
|
18220
|
+
For an engine tool without a dedicated wrapper, use the read-only passthrough `graph-query.sh --repo . --tool <name> --json '{...}'` (project injected, write tools refused, `source:"unavailable"` on failure). Never call the engine binary directly — that skips engine resolution, the index refresh before each query, and the fail-loud contract.
|
|
18220
18221
|
|
|
18221
18222
|
### Capability wrappers & dialect limits (graph-tooling-v2)
|
|
18222
18223
|
|
|
@@ -18224,8 +18225,9 @@ All Cypher lives in `scripts/tools/_graph_queries.sh` (the single source of quer
|
|
|
18224
18225
|
truth). Wrappers are thin arg-parse → builder → fail-loud JSON. Three contracts
|
|
18225
18226
|
matter when consuming them:
|
|
18226
18227
|
|
|
18227
|
-
**Fail-loud status.** Symbol-scoped wrappers (`graph-callers`, `graph-
|
|
18228
|
-
`graph-tests --symbol`, `graph-hierarchy --symbol/--derived`,
|
|
18228
|
+
**Fail-loud status.** Symbol-scoped wrappers (`graph-callers`, `graph-impact`,
|
|
18229
|
+
`graph-snippet`, `graph-tests --symbol`, `graph-hierarchy --symbol/--derived`,
|
|
18230
|
+
`graph-errors`)
|
|
18229
18231
|
emit a `status` field that distinguishes the three real outcomes — never read a
|
|
18230
18232
|
bare `[]` as a confirmed true negative:
|
|
18231
18233
|
|
|
@@ -18234,9 +18236,11 @@ bare `[]` as a confirmed true negative:
|
|
|
18234
18236
|
| `ok` | node found, edges returned |
|
|
18235
18237
|
| `no-edges` | node exists but has no matching edge (a *real* negative) |
|
|
18236
18238
|
| `no-match` | the named symbol was not found at all (check the name / try `--qualified`) |
|
|
18237
|
-
| `unavailable` | engine could not be resolved (exit 2) |
|
|
18239
|
+
| `unavailable` | engine could not be resolved, or engine returned shapeless/non-row JSON (exit 2) |
|
|
18238
18240
|
|
|
18239
|
-
**
|
|
18241
|
+
**Shapeless JSON is unavailable.** `gq_run` requires `has("rows") and (.rows|type=="array")`. A bare `{}` (or any object without a `.rows` array) is not a measured empty result — wrappers emit `source:"unavailable"` and a non-zero exit. Do not read `{}` as "no callers / no cycles / no edges". `graph-impact`, `graph-callers`, and `mermaid-from-graph` also require their tool-shaped object; a failed snapshot refresh does not rewrite `schema.yaml`.
|
|
18242
|
+
|
|
18243
|
+
**Verified engine param shapes** (engine v0.9.0 — the runtime source of truth is
|
|
18240
18244
|
`get_graph_schema`; do not hardcode a property set):
|
|
18241
18245
|
|
|
18242
18246
|
```bash
|
|
@@ -18249,13 +18253,18 @@ get_graph_schema '{"project":P}' # → {node_labels:[{label,count,properties}
|
|
|
18249
18253
|
|
|
18250
18254
|
**Cypher dialect — keep queries inside the SAFE set:**
|
|
18251
18255
|
|
|
18252
|
-
- ✅ SAFE:
|
|
18253
|
-
`
|
|
18254
|
-
`[:
|
|
18255
|
-
|
|
18256
|
-
|
|
18257
|
-
|
|
18256
|
+
- ✅ SAFE: `=`, `<>`/`!=`, `<`, `>`, `<=`, `>=` against a literal; `STARTS WITH`,
|
|
18257
|
+
`NOT x STARTS WITH`, `AND`, `OR`; explicit and variable-length patterns
|
|
18258
|
+
(`[:R*1..3]`, fixed depth `[:R*2..2]`); relationship-type alternation `[:A|B]`;
|
|
18259
|
+
`coalesce()`; `DISTINCT`; `count(x)`, `count(DISTINCT x)`; `WITH`-grouping
|
|
18260
|
+
aggregation.
|
|
18261
|
+
- ❌ UNSAFE: comparing one property against another (`a.x < b.x`), `NOT EXISTS(...)`,
|
|
18262
|
+
`NOT (pattern)`, path variables (`p=(...)`, `length(p)`) — all rejected; and
|
|
18263
|
+
multi-pattern joins (`MATCH (a)…, (b)…`), which parse but ignore `RETURN` and
|
|
18264
|
+
`LIMIT`. `graph-query.sh --cypher` returns the engine's raw error, not a silent
|
|
18258
18265
|
empty — but the builders never emit these forms.
|
|
18266
|
+
- ⚠️ `LIMIT` applies before `DISTINCT`: `RETURN DISTINCT … LIMIT n` can return
|
|
18267
|
+
fewer than n rows while more exist. Judge truncation on raw rows.
|
|
18259
18268
|
|
|
18260
18269
|
**Caveats consumers must respect:**
|
|
18261
18270
|
|
|
@@ -18290,22 +18299,22 @@ The only committed file is the gate marker:
|
|
|
18290
18299
|
|
|
18291
18300
|
| File | Role |
|
|
18292
18301
|
|------|------|
|
|
18293
|
-
| `draft/graph/schema.yaml` | Engine
|
|
18302
|
+
| `draft/graph/schema.yaml` | Engine metadata and point-of-index counts (provenance, not authoritative). Carries **no graph data**. Its presence is the **gate** (see Pre-Check) — it signals the engine is wired for this repo. Written by `scripts/tools/graph-snapshot.sh`. |
|
|
18294
18303
|
|
|
18295
|
-
All structural data is obtained live
|
|
18304
|
+
All structural data is obtained live through the query-tool wrappers under `scripts/tools/`; `graph-query.sh --tool` covers every read-only engine tool that has no dedicated wrapper. The wrappers refresh the repo's index in the engine's own cache before each query, so no committed files are required.
|
|
18296
18305
|
|
|
18297
18306
|
### How skills query (engine is the interface; jq is optional)
|
|
18298
18307
|
|
|
18299
|
-
- **The engine is the query
|
|
18308
|
+
- **The engine is the query; the wrappers are the interface.** Every wrapper drives the engine's CLI and returns JSON. There is no other query surface.
|
|
18300
18309
|
- **Prefer the wrappers — they resolve the engine for you.** `graph-arch.sh` (architecture view: packages/routes/layers/hotspots), `graph-callers.sh`, `hotspot-rank.sh`, `graph-impact.sh`, `cycle-detect.sh`, `mermaid-from-graph.sh` return already-shaped JSON. The engine binary is usually **not on `$PATH`** (it lives under `~/.cache/draft/bin/`); the wrappers locate it via `_lib.sh:find_memory_bin`, so a skill using a wrapper needs no resolution step.
|
|
18301
|
-
- **
|
|
18310
|
+
- **Tools without a dedicated wrapper go through `graph-query.sh`:** `"$DRAFT_TOOLS/graph-query.sh" --repo . --tool search_code --json '{"pattern":"..."}'` (likewise `trace_path`, `get_graph_schema`, `index_status`). `search_graph` has its own wrapper, `graph-search.sh`.
|
|
18302
18311
|
- **`jq` is not a query tool — it only trims output.** Reach for it solely to slice a *large* response (chiefly the `get_architecture` blob) down to the field you need, for token economy. The agent can read raw JSON directly; jq is an optimization, not a requirement. Don't pipe wrapper output through jq unless you genuinely need a sub-field.
|
|
18303
18312
|
|
|
18304
18313
|
The engine uses a **unified, language-agnostic** node model — `Function`, `Method`, `Class`, `Module`, `File`, `Folder`, `Route`, `Section`, `Variable` (language is inferred from file extension) — and edges `CALLS`, `DEFINES`, `CONTAINS_FILE`, `IMPORTS`, `HTTP_CALLS`, `FILE_CHANGES_WITH`, `SEMANTICALLY_RELATED`, `SIMILAR_TO`. Each node carries `file_path` + `start_line`/`end_line` and rich `properties` (complexity, signature, parent_class), and the engine exposes full-text (`search_code`) and semantic search — none of which a committed snapshot reproduced.
|
|
18305
18314
|
|
|
18306
18315
|
## Query Tools
|
|
18307
18316
|
|
|
18308
|
-
Live queries go through the shell tools under `scripts/tools/`, which drive the engine and shape results into stable JSON. Each tool resolves the engine (see Finding the Engine), indexes the repo on demand, and emits `source: "memory-graph"` on success or `source: "unavailable"` (non-zero exit) when the engine cannot be resolved. Set `DRAFT_MEMORY_DISABLE=1` to force the engine off; all tools then degrade
|
|
18317
|
+
Live queries go through the shell tools under `scripts/tools/`, which drive the engine and shape results into stable JSON. Each tool resolves the engine (see Finding the Engine), indexes the repo on demand, and emits `source: "memory-graph"` on success or `source: "unavailable"` (non-zero exit) when the engine cannot be resolved **or returns shapeless JSON** (missing `.rows` array). Set `DRAFT_MEMORY_DISABLE=1` to force the engine off; all tools then degrade to `unavailable` rather than inventing empty results.
|
|
18309
18318
|
|
|
18310
18319
|
### Callers — who calls this function?
|
|
18311
18320
|
|
|
@@ -18318,11 +18327,11 @@ Output: `{symbol, callers[{name, file}], source}`. Use when enumerating call sit
|
|
|
18318
18327
|
### Impact — blast radius of a file or symbol
|
|
18319
18328
|
|
|
18320
18329
|
```bash
|
|
18321
|
-
"$DRAFT_TOOLS/graph-impact.sh" --repo . --file <path> #
|
|
18322
|
-
"$DRAFT_TOOLS/graph-impact.sh" --repo . --symbol <name> # transitive callers of a function
|
|
18330
|
+
"$DRAFT_TOOLS/graph-impact.sh" --repo . --file <path> # dependents of a file: its symbols' callers + its importers
|
|
18331
|
+
"$DRAFT_TOOLS/graph-impact.sh" --repo . --symbol <name> # dependents (transitive callers) of a function
|
|
18323
18332
|
```
|
|
18324
18333
|
|
|
18325
|
-
Output: `{target, kind, impacted[{name, file, hop}], source}`. Use when sizing risk before modifying a file or symbol, especially high-fan-in hotspots.
|
|
18334
|
+
Output: `{target, kind, impacted[{name, file, qualified, hop}], downstream_files, affected_modules, max_depth, by_category{code,test}, status, truncated, source}`. `impacted` lists each dependent once at its nearest hop (default depth 3), capped at 200 with `truncated:true`; the aggregates always cover the full set. `status` is `ok`, `no-edges` (target known, nothing depends on it), or `no-match` (target unknown to the graph — check the path). Use when sizing risk before modifying a file or symbol, especially high-fan-in hotspots.
|
|
18326
18335
|
|
|
18327
18336
|
### Hotspots — fan-in ranking
|
|
18328
18337
|
|
|
@@ -18433,7 +18442,7 @@ Unlocks any edge type or node property without a purpose-built wrapper. Write ve
|
|
|
18433
18442
|
"$DRAFT_TOOLS/graph-snapshot.sh" --repo .
|
|
18434
18443
|
```
|
|
18435
18444
|
|
|
18436
|
-
Indexes the repo into the engine and writes the `draft/graph/schema.yaml` gate marker
|
|
18445
|
+
Indexes the repo into the engine and writes the `draft/graph/schema.yaml` gate marker, and prints the `detect_changes` delta (`changed_files`/`impacted_symbols`) without committing it. It writes **no** graph data. Run during `draft init` and `draft graph`, or whenever the index should be refreshed.
|
|
18437
18446
|
|
|
18438
18447
|
## Finding the Engine (Resolution + Usage Report)
|
|
18439
18448
|
|
|
@@ -18472,9 +18481,9 @@ The engine indexes C/C++, Go, Python, TypeScript/JS, and more (tree-sitter, 159
|
|
|
18472
18481
|
| Scenario | Behavior |
|
|
18473
18482
|
|----------|----------|
|
|
18474
18483
|
| No engine resolvable (or `DRAFT_MEMORY_DISABLE=1`) | Skip graph indexing in init; all skills proceed without graph data; tools emit `source: unavailable` |
|
|
18475
|
-
| Engine present but a query fails |
|
|
18484
|
+
| Engine present but a query fails, or returns shapeless `{}` | Treat as unavailable — never as a true-negative empty result; skills proceed without graph data |
|
|
18476
18485
|
| `draft/graph/schema.yaml` exists | Engine is wired — use live query tools as needed during the run |
|
|
18477
|
-
| Engine index out of date |
|
|
18486
|
+
| Engine index out of date | Every wrapper re-indexes incrementally (content-based, git-aware) before it queries — ~0.1 s on an unchanged repo — so live answers track the working tree, including the run's own edits. `graph-snapshot.sh` (or init) also refreshes the `schema.yaml` marker. |
|
|
18478
18487
|
|
|
18479
18488
|
</core-file>
|
|
18480
18489
|
|
|
@@ -20431,7 +20440,7 @@ graph:
|
|
|
20431
20440
|
cpp: "{high}"
|
|
20432
20441
|
go: "{approximate | high}"
|
|
20433
20442
|
stats:
|
|
20434
|
-
modules: "{N from
|
|
20443
|
+
modules: "{N from engine: get_architecture .packages}"
|
|
20435
20444
|
edges: "{total_edges from engine: get_architecture .edges}"
|
|
20436
20445
|
hotspots: "{N}"
|
|
20437
20446
|
notes: "{explicit fidelity summary from engine: get_architecture .languages/.packages}"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@drafthq/draft",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.1",
|
|
4
4
|
"description": "Context-Driven Development for AI coding agents — install Draft into Claude Code, Cursor, Codex, or opencode.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"draft": "cli/bin/draft.js"
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
],
|
|
26
26
|
"scripts": {
|
|
27
27
|
"test": "bash tests/test-cli.sh",
|
|
28
|
-
"version": "bash scripts/sync-version.sh
|
|
28
|
+
"version": "bash scripts/sync-version.sh --stage",
|
|
29
29
|
"prepublishOnly": "bash scripts/build-integrations.sh"
|
|
30
30
|
},
|
|
31
31
|
"repository": {
|
|
@@ -37,7 +37,11 @@
|
|
|
37
37
|
"url": "https://github.com/drafthq/draft/issues"
|
|
38
38
|
},
|
|
39
39
|
"license": "MIT",
|
|
40
|
-
"author":
|
|
40
|
+
"author": {
|
|
41
|
+
"name": "Mayur Pise",
|
|
42
|
+
"email": "mayur@getdraft.dev",
|
|
43
|
+
"url": "https://github.com/mayurpise"
|
|
44
|
+
},
|
|
41
45
|
"publishConfig": {
|
|
42
46
|
"access": "public"
|
|
43
47
|
},
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
#
|
|
4
4
|
# The engine is the codebase-memory-mcp single static binary. This script fetches
|
|
5
5
|
# the release archive for the host OS/arch from GitHub Releases, verifies its
|
|
6
|
-
# SHA-256 against
|
|
7
|
-
#
|
|
6
|
+
# SHA-256 (against hashes pinned below for the default version, else against the
|
|
7
|
+
# release's checksums.txt), extracts it, and installs the binary to the
|
|
8
|
+
# Draft-managed location (~/.cache/draft/bin/codebase-memory-mcp),
|
|
8
9
|
# which scripts/tools/_lib.sh:find_memory_bin resolves.
|
|
9
10
|
#
|
|
10
11
|
# Pinned by default for reproducibility; override with CMM_VERSION (a tag, e.g.
|
|
@@ -44,9 +45,15 @@ while [[ $# -gt 0 ]]; do
|
|
|
44
45
|
done
|
|
45
46
|
|
|
46
47
|
BIN_PATH="$DEST/codebase-memory-mcp"
|
|
48
|
+
# Keep an existing install only at the requested version, so a pin bump upgrades
|
|
49
|
+
# it. "latest" cannot be compared offline; any existing binary satisfies it.
|
|
47
50
|
if [[ -x "$BIN_PATH" && $FORCE -eq 0 ]]; then
|
|
48
|
-
|
|
49
|
-
|
|
51
|
+
have="$("$BIN_PATH" --version 2>/dev/null | awk '{print $NF}' || true)"
|
|
52
|
+
if [[ "$VERSION" == "latest" || "$have" == "${VERSION#v}" ]]; then
|
|
53
|
+
echo "codebase-memory-mcp already installed at $BIN_PATH (${have:-unknown})"
|
|
54
|
+
exit 0
|
|
55
|
+
fi
|
|
56
|
+
echo "Installed engine is ${have:-unknown}; replacing it with ${VERSION}."
|
|
50
57
|
fi
|
|
51
58
|
|
|
52
59
|
# --- Detect OS / arch (mirrors the engine's own install.sh naming) ---
|
|
@@ -80,7 +87,7 @@ TMP="$(mktemp -d)"
|
|
|
80
87
|
trap 'rm -rf "$TMP"' EXIT
|
|
81
88
|
|
|
82
89
|
echo "Fetching ${ARCHIVE} (${VERSION})..."
|
|
83
|
-
if ! curl -fSL --max-time 300 -o "$TMP/$ARCHIVE" "$BASE/$ARCHIVE"; then
|
|
90
|
+
if ! curl -fSL --proto '=https' --proto-redir '=https' --max-time 300 -o "$TMP/$ARCHIVE" "$BASE/$ARCHIVE"; then
|
|
84
91
|
echo "error: download failed: $BASE/$ARCHIVE" >&2
|
|
85
92
|
exit 2
|
|
86
93
|
fi
|
|
@@ -89,6 +96,28 @@ fi
|
|
|
89
96
|
# A mismatch is always fatal. An *absent* checksum is fatal only under
|
|
90
97
|
# DRAFT_STRICT_VERIFY=1 — otherwise it warns, so that a release without a
|
|
91
98
|
# checksums.txt does not brick the install for everyone.
|
|
99
|
+
#
|
|
100
|
+
# checksums.txt ships in the same release as the archive, so it proves only that
|
|
101
|
+
# the download is intact: a replaced release asset passes it. The pinned
|
|
102
|
+
# version's archives are checked against SHA-256 values recorded here instead
|
|
103
|
+
# (copied from its checksums.txt when the pin was bumped) — update them with
|
|
104
|
+
# DEFAULT_VERSION.
|
|
105
|
+
pinned_sha256() {
|
|
106
|
+
[[ "$VERSION" == "$DEFAULT_VERSION" ]] || return 0
|
|
107
|
+
case "$1" in
|
|
108
|
+
codebase-memory-mcp-darwin-amd64.tar.gz) echo 6af3d02a27f589901fa763d3971089337bc8c9838bbed5d0cf543ca9f1a9e543 ;;
|
|
109
|
+
codebase-memory-mcp-darwin-arm64.tar.gz) echo faa02f0404230c451a9812230394481948f80183801fa5bf67044b41c2f25ed4 ;;
|
|
110
|
+
codebase-memory-mcp-linux-amd64-portable.tar.gz) echo 8459d5c9d1457f2c82de3de307ffc7641ecbba2dde893427be1e62eca8ef9b25 ;;
|
|
111
|
+
codebase-memory-mcp-linux-arm64-portable.tar.gz) echo b0a43fdaf534073c16707d72726b73b149d4c1212034b281ee8b7b2dac755107 ;;
|
|
112
|
+
esac
|
|
113
|
+
}
|
|
114
|
+
sha256_of() {
|
|
115
|
+
if command -v sha256sum >/dev/null 2>&1; then
|
|
116
|
+
sha256sum "$1" | awk '{print $1}'
|
|
117
|
+
else
|
|
118
|
+
shasum -a 256 "$1" | awk '{print $1}'
|
|
119
|
+
fi
|
|
120
|
+
}
|
|
92
121
|
STRICT="${DRAFT_STRICT_VERIFY:-0}"
|
|
93
122
|
unverified() {
|
|
94
123
|
if [[ "$STRICT" == "1" ]]; then
|
|
@@ -98,14 +127,18 @@ unverified() {
|
|
|
98
127
|
echo " warning: $1 — skipping verification (set DRAFT_STRICT_VERIFY=1 to make this fatal)" >&2
|
|
99
128
|
}
|
|
100
129
|
|
|
101
|
-
|
|
130
|
+
pinned="$(pinned_sha256 "$ARCHIVE")"
|
|
131
|
+
if [[ -n "$pinned" ]]; then
|
|
132
|
+
actual="$(sha256_of "$TMP/$ARCHIVE")"
|
|
133
|
+
if [[ "$pinned" != "$actual" ]]; then
|
|
134
|
+
echo "error: $ARCHIVE does not match the SHA-256 pinned for $VERSION (expected $pinned, got $actual)" >&2
|
|
135
|
+
exit 2
|
|
136
|
+
fi
|
|
137
|
+
echo " checksum OK (pinned $pinned)"
|
|
138
|
+
elif curl -fsSL --proto '=https' --proto-redir '=https' --max-time 60 -o "$TMP/checksums.txt" "$BASE/checksums.txt" 2>/dev/null; then
|
|
102
139
|
expected="$(grep " $ARCHIVE\$" "$TMP/checksums.txt" 2>/dev/null | awk '{print $1}' | head -1 || true)"
|
|
103
140
|
if [[ -n "$expected" ]]; then
|
|
104
|
-
|
|
105
|
-
actual="$(sha256sum "$TMP/$ARCHIVE" | awk '{print $1}')"
|
|
106
|
-
else
|
|
107
|
-
actual="$(shasum -a 256 "$TMP/$ARCHIVE" | awk '{print $1}')"
|
|
108
|
-
fi
|
|
141
|
+
actual="$(sha256_of "$TMP/$ARCHIVE")"
|
|
109
142
|
if [[ "$expected" != "$actual" ]]; then
|
|
110
143
|
echo "error: checksum mismatch for $ARCHIVE (expected $expected, got $actual)" >&2
|
|
111
144
|
exit 2
|
package/scripts/lib.sh
CHANGED
|
@@ -84,7 +84,7 @@ SKILL_META=(
|
|
|
84
84
|
'plan|Plan Router|"plan feature" or "draft plan <intent>" (new-track, decompose, adr, tech-debt, change)'
|
|
85
85
|
'ops|Ops Router|"ops deploy" or "draft ops <intent>" (deploy-checklist, incident, standup, status, revert)'
|
|
86
86
|
'docs|Docs Router|"write docs" or "draft docs <intent>" (documentation)'
|
|
87
|
-
'discover|Discover Router|"discover debug" or "draft discover <intent>" (debug, bughunt, reviews, coverage, learn,
|
|
87
|
+
'discover|Discover Router|"discover debug" or "draft discover <intent>" (debug, bughunt, reviews, coverage, learn, tour, impact, etc.)'
|
|
88
88
|
'jira|Jira Router|"jira preview", "jira create", or "jira review <ID>"'
|
|
89
89
|
'integrations|Integrations Router|"integrations", "integrations jira-preview", or "integrations jira-create"'
|
|
90
90
|
'quick-review|Quick Review Command|"quick review" or "draft quick-review [file|pr <number>]"'
|