@drafthq/draft 3.7.2 → 4.0.0
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 +1 -1
- 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/graph-query.md +6 -4
- package/integrations/agents/AGENTS.md +7 -5
- package/integrations/copilot/.github/copilot-instructions.md +7 -5
- package/package.json +6 -2
- package/scripts/fetch-memory-engine.sh +2 -2
- package/scripts/lib.sh +1 -1
- package/scripts/tools/_graph_queries.sh +3 -1
- package/scripts/tools/check-repo-size.sh +5 -1
- package/scripts/tools/cycle-detect.sh +2 -2
- package/scripts/tools/graph-callers.sh +1 -1
- package/scripts/tools/graph-impact.sh +4 -2
- package/scripts/tools/graph-snapshot.sh +5 -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/skills/draft/intent-mapping.md +1 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "draft-plugins",
|
|
3
3
|
"owner": {
|
|
4
|
-
"name": "
|
|
4
|
+
"name": "Mayur Pise",
|
|
5
|
+
"email": "mayur@getdraft.dev",
|
|
5
6
|
"url": "https://github.com/mayurpise"
|
|
6
7
|
},
|
|
7
8
|
"metadata": {
|
|
@@ -12,9 +13,11 @@
|
|
|
12
13
|
"name": "draft",
|
|
13
14
|
"source": "./",
|
|
14
15
|
"description": "Context-Driven Development: draft specs and plans before implementation. Structured workflows for features and fixes.",
|
|
15
|
-
"version": "
|
|
16
|
+
"version": "4.0.0",
|
|
16
17
|
"author": {
|
|
17
|
-
"name": "
|
|
18
|
+
"name": "Mayur Pise",
|
|
19
|
+
"email": "mayur@getdraft.dev",
|
|
20
|
+
"url": "https://github.com/mayurpise"
|
|
18
21
|
},
|
|
19
22
|
"homepage": "https://github.com/drafthq/draft",
|
|
20
23
|
"license": "MIT",
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "draft",
|
|
3
3
|
"description": "Context-Driven Development: draft specs and plans before implementation. Structured workflows for features and fixes.",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "4.0.0",
|
|
5
5
|
"author": {
|
|
6
|
-
"name": "
|
|
6
|
+
"name": "Mayur Pise",
|
|
7
|
+
"email": "mayur@getdraft.dev",
|
|
8
|
+
"url": "https://github.com/mayurpise"
|
|
7
9
|
},
|
|
8
10
|
"homepage": "https://github.com/drafthq/draft",
|
|
9
11
|
"license": "MIT",
|
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
"name": "draft",
|
|
3
3
|
"displayName": "Draft",
|
|
4
4
|
"description": "Context-Driven Development: draft specs and plans before implementation. Structured workflows for features and fixes.",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "4.0.0",
|
|
6
6
|
"skills": "./skills/",
|
|
7
7
|
"agents": "./core/agents/",
|
|
8
8
|
"author": {
|
|
9
|
-
"name": "
|
|
9
|
+
"name": "Mayur Pise",
|
|
10
|
+
"email": "mayur@getdraft.dev",
|
|
11
|
+
"url": "https://github.com/mayurpise"
|
|
10
12
|
},
|
|
11
13
|
"homepage": "https://github.com/drafthq/draft",
|
|
12
14
|
"license": "MIT",
|
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -68,12 +68,12 @@ Each host installs the way that host actually loads extensions — no manual ste
|
|
|
68
68
|
|
|
69
69
|
| Host | `draft install …` | What it does |
|
|
70
70
|
|------|-------------------|--------------|
|
|
71
|
-
| **Claude Code** | `claude-code` | Registers the plugin via `claude plugin marketplace add` + `claude plugin install` (user scope). Restart Claude Code. |
|
|
72
|
-
| **Cursor** | `cursor` | Copies the plugin into `~/.cursor/plugins/local/draft/`, writes `.cursor-plugin/plugin.json`, registers `draft@draft-plugins` in Cursor's plugin registry, and enables it. Restart Cursor (or Developer: Reload Window). Existing installs upgrade with `draft install cursor --force`. |
|
|
73
|
-
| **Codex** | `codex` | Writes `./AGENTS.md`, which Codex reads automatically. |
|
|
74
|
-
| **opencode** | `opencode` | Writes `./AGENTS.md` + `~/.agents/skills/draft/`, both auto-discovered. |
|
|
71
|
+
| **Claude Code** | `claude-code` | Registers the plugin via `claude plugin marketplace add` + `claude plugin install` (default `--global` / user scope). Restart Claude Code. |
|
|
72
|
+
| **Cursor** | `cursor` | Default `--global`. Copies the plugin into `~/.cursor/plugins/local/draft/`, writes `.cursor-plugin/plugin.json`, registers `draft@draft-plugins` in Cursor's plugin registry, and enables it. Restart Cursor (or Developer: Reload Window). Existing installs upgrade with `draft install cursor --force`. |
|
|
73
|
+
| **Codex** | `codex` | Default `--project`. Writes `./AGENTS.md`, which Codex reads automatically. |
|
|
74
|
+
| **opencode** | `opencode` | Default `--project`. Writes `./AGENTS.md` + `~/.agents/skills/draft/`, both auto-discovered. |
|
|
75
75
|
|
|
76
|
-
Flags: `--global` / `--project` to pick scope, `--dry-run` to preview, `--force` to overwrite, `--no-graph` to skip the graph-engine fetch.
|
|
76
|
+
Flags: `--global` / `--project` to pick scope (`--global` is the default for `claude-code` and `cursor`; `--project` is the default for `codex` and `opencode`), `--dry-run` to preview, `--force` to overwrite, `--no-graph` to skip the graph-engine fetch.
|
|
77
77
|
|
|
78
78
|
Then, in Claude Code (after restarting):
|
|
79
79
|
|
|
@@ -164,7 +164,7 @@ The graph powers `/draft:graph` and `/draft:impact`, enriches `/draft:bughunt` a
|
|
|
164
164
|
|
|
165
165
|
### Deterministic helper tools
|
|
166
166
|
|
|
167
|
-
Skills also call into **shell helpers** under `scripts/tools/` for mechanical work — git metadata, file classification, test-framework detection, hotspot ranking, freshness checks, ADR indexing, and live graph queries (`graph-callers.sh`, `graph-impact.sh`, `hotspot-rank.sh`, `cycle-detect.sh`, `mermaid-from-graph.sh`). All emit JSON or markdown
|
|
167
|
+
Skills also call into **shell helpers** under `scripts/tools/` for mechanical work — git metadata, file classification, test-framework detection, hotspot ranking, freshness checks, ADR indexing, and live graph queries (`graph-callers.sh`, `graph-impact.sh`, `hotspot-rank.sh`, `cycle-detect.sh`, `mermaid-from-graph.sh`). All emit JSON or markdown and follow a uniform exit-code contract. Graph wrappers fail loud: shapeless `{}` (no `.rows` array) is `source:"unavailable"` with a non-zero exit, not a measured empty result.
|
|
168
168
|
|
|
169
169
|
---
|
|
170
170
|
|
|
@@ -270,7 +270,7 @@ Each layer narrows the solution space. By the time AI writes code, decisions are
|
|
|
270
270
|
|
|
271
271
|
---
|
|
272
272
|
|
|
273
|
-
<p align="center">MIT License · Graph engine: <a href="https://github.com/DeusData/codebase-memory-mcp" target="_blank" rel="noopener noreferrer">codebase-memory-mcp</a> by <a href="https://github.com/DeusData" target="_blank" rel="noopener noreferrer">DeusData</a></p>
|
|
273
|
+
<p align="center">MIT License · Created & maintained by <a href="https://www.linkedin.com/in/mayurpise/" target="_blank" rel="noopener noreferrer">Mayur Pise</a> · Graph engine: <a href="https://github.com/DeusData/codebase-memory-mcp" target="_blank" rel="noopener noreferrer">codebase-memory-mcp</a> by <a href="https://github.com/DeusData" target="_blank" rel="noopener noreferrer">DeusData</a></p>
|
|
274
274
|
|
|
275
275
|
<p align="center">
|
|
276
276
|
<strong>Credits:</strong> Inspired by <a href="https://github.com/gemini-cli-extensions/conductor">gemini-cli-extensions/conductor</a>
|
package/bin/README.md
CHANGED
|
@@ -17,7 +17,7 @@ This installs the binary to the **Draft-managed location**:
|
|
|
17
17
|
~/.cache/draft/bin/codebase-memory-mcp
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
The fetch script picks the right release archive for the host OS/arch, verifies its SHA-256 against the published `checksums.txt`, extracts it, and installs it there. `draft install claude-code` / `draft install cursor` run this automatically (best-effort, network-gated); skip it with `--no-graph`.
|
|
20
|
+
The fetch script picks the right release archive for the host OS/arch, verifies its SHA-256 against the published `checksums.txt`, extracts it, and installs it there. Downloads pin `curl --proto '=https' --proto-redir '=https'` so a compromised redirect cannot downgrade to HTTP. `draft install claude-code` / `draft install cursor` run this automatically (best-effort, network-gated); skip it with `--no-graph`.
|
|
21
21
|
|
|
22
22
|
## Resolution order
|
|
23
23
|
|
package/cli/src/cli.js
CHANGED
|
@@ -47,8 +47,8 @@ Usage:
|
|
|
47
47
|
Hosts: ${hosts.map((h) => h.id).join(', ')}
|
|
48
48
|
|
|
49
49
|
Flags:
|
|
50
|
-
--global Install to the user-level location (default for cursor)
|
|
51
|
-
--project Install into the current project (default for
|
|
50
|
+
--global Install to the user-level location (default for claude-code, cursor)
|
|
51
|
+
--project Install into the current project (default for codex, opencode)
|
|
52
52
|
--dry-run Print planned writes without touching disk
|
|
53
53
|
--no-graph Skip the knowledge-graph engine fetch
|
|
54
54
|
--force Overwrite an existing target
|
package/cli/src/installer.js
CHANGED
|
@@ -15,9 +15,11 @@ const CHECK_TIMEOUT_MS = 10000;
|
|
|
15
15
|
const USE_SHELL = process.platform === 'win32';
|
|
16
16
|
|
|
17
17
|
function hasBinary(name) {
|
|
18
|
-
//
|
|
18
|
+
// Windows `.cmd` shims (shell: true) report a missing binary as status 127
|
|
19
|
+
// with no `error`. Treat any spawn error or non-zero status as absent.
|
|
19
20
|
const r = spawnSync(name, ['--version'], { stdio: 'ignore', timeout: CHECK_TIMEOUT_MS, shell: USE_SHELL });
|
|
20
|
-
|
|
21
|
+
if (r.error) return false;
|
|
22
|
+
return r.status === 0;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
// Per-step ceiling so a stalled network op (e.g. the `git clone` behind
|
|
@@ -78,7 +78,7 @@ function registerCursorPlugin(opts) {
|
|
|
78
78
|
// --- installed_plugins.json: merge our key, preserve installedAt on upgrade. ---
|
|
79
79
|
const ip = readJson(paths.ipPath, { version: 2, plugins: {} });
|
|
80
80
|
if (typeof ip.version !== 'number') ip.version = 2;
|
|
81
|
-
if (!ip.plugins || typeof ip.plugins !== 'object') ip.plugins = {};
|
|
81
|
+
if (!ip.plugins || typeof ip.plugins !== 'object' || Array.isArray(ip.plugins)) ip.plugins = {};
|
|
82
82
|
const existing = Array.isArray(ip.plugins[PLUGIN_KEY]) ? ip.plugins[PLUGIN_KEY][0] : null;
|
|
83
83
|
const installedAt = existing && existing.installedAt ? existing.installedAt : now;
|
|
84
84
|
ip.plugins[PLUGIN_KEY] = [
|
|
@@ -93,7 +93,7 @@ function registerCursorPlugin(opts) {
|
|
|
93
93
|
|
|
94
94
|
// --- settings.json: flip our enabledPlugins flag, preserve everything else. ---
|
|
95
95
|
const settings = readJson(paths.settingsPath, {});
|
|
96
|
-
if (!settings.enabledPlugins || typeof settings.enabledPlugins !== 'object') {
|
|
96
|
+
if (!settings.enabledPlugins || typeof settings.enabledPlugins !== 'object' || Array.isArray(settings.enabledPlugins)) {
|
|
97
97
|
settings.enabledPlugins = {};
|
|
98
98
|
}
|
|
99
99
|
settings.enabledPlugins[PLUGIN_KEY] = true;
|
package/cli/src/lib/graph.js
CHANGED
|
@@ -14,7 +14,8 @@ function fetchGraph() {
|
|
|
14
14
|
return;
|
|
15
15
|
}
|
|
16
16
|
log.note('Fetching knowledge-graph engine (best-effort)...');
|
|
17
|
-
const
|
|
17
|
+
const timeout = Number(process.env.DRAFT_INSTALL_TIMEOUT_MS) || 300000;
|
|
18
|
+
const result = spawnSync('bash', [script], { stdio: 'inherit', timeout });
|
|
18
19
|
if (result.status !== 0) {
|
|
19
20
|
log.warn('Graph engine fetch skipped (offline or unsupported platform) — features degrade gracefully.');
|
|
20
21
|
}
|
|
@@ -103,7 +103,7 @@ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}
|
|
|
103
103
|
|---|---|---|
|
|
104
104
|
| `bash "$DRAFT_TOOLS/hotspot-rank.sh" [--top N]` | complexity-weighted hotspots | Emits `{hotspots:[],source:"unavailable"}` and exits 2 |
|
|
105
105
|
| `bash "$DRAFT_TOOLS/cycle-detect.sh"` | call cycles | Emits `{cycles:[],source:"unavailable"}` and exits 2 |
|
|
106
|
-
| `bash "$DRAFT_TOOLS/mermaid-from-graph.sh" [--diagram module-deps\|co-change\|proto-map]` | diagram text |
|
|
106
|
+
| `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 |
|
|
107
107
|
| `bash "$DRAFT_TOOLS/graph-callers.sh" --symbol N [--transitive[=N]] [--prod-only] [--qualified]` | callers | `{callers:[],status:"unavailable",source:"unavailable"}`, exit 2 |
|
|
108
108
|
| `bash "$DRAFT_TOOLS/graph-snippet.sh" --qualified N` | verified source + caller/callee counts | `{status:"unavailable",source:"unavailable"}`, exit 2 |
|
|
109
109
|
| `bash "$DRAFT_TOOLS/graph-search.sh" --query "STR" [--limit N]` | semantic/ranked search | `{results:[],source:"unavailable"}`, exit 2 |
|
|
@@ -133,7 +133,9 @@ bare `[]` as a confirmed true negative:
|
|
|
133
133
|
| `ok` | node found, edges returned |
|
|
134
134
|
| `no-edges` | node exists but has no matching edge (a *real* negative) |
|
|
135
135
|
| `no-match` | the named symbol was not found at all (check the name / try `--qualified`) |
|
|
136
|
-
| `unavailable` | engine could not be resolved (exit 2) |
|
|
136
|
+
| `unavailable` | engine could not be resolved, or engine returned shapeless/non-row JSON (exit 2) |
|
|
137
|
+
|
|
138
|
+
**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`.
|
|
137
139
|
|
|
138
140
|
**Verified engine param shapes** (engine v0.8.x — the runtime source of truth is
|
|
139
141
|
`get_graph_schema`; do not hardcode a property set):
|
|
@@ -204,7 +206,7 @@ The engine uses a **unified, language-agnostic** node model — `Function`, `Met
|
|
|
204
206
|
|
|
205
207
|
## Query Tools
|
|
206
208
|
|
|
207
|
-
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
|
|
209
|
+
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.
|
|
208
210
|
|
|
209
211
|
### Callers — who calls this function?
|
|
210
212
|
|
|
@@ -371,6 +373,6 @@ The engine indexes C/C++, Go, Python, TypeScript/JS, and more (tree-sitter, 159
|
|
|
371
373
|
| Scenario | Behavior |
|
|
372
374
|
|----------|----------|
|
|
373
375
|
| No engine resolvable (or `DRAFT_MEMORY_DISABLE=1`) | Skip graph indexing in init; all skills proceed without graph data; tools emit `source: unavailable` |
|
|
374
|
-
| Engine present but a query fails |
|
|
376
|
+
| Engine present but a query fails, or returns shapeless `{}` | Treat as unavailable — never as a true-negative empty result; skills proceed without graph data |
|
|
375
377
|
| `draft/graph/schema.yaml` exists | Engine is wired — use live query tools as needed during the run |
|
|
376
378
|
| Engine index out of date | The engine indexes incrementally (content-based, git-aware) on each query, so it self-freshens. Re-run `graph-snapshot.sh` (or init) to force a reindex and refresh the marker. |
|
|
@@ -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
|
|
|
@@ -18204,7 +18204,7 @@ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}
|
|
|
18204
18204
|
|---|---|---|
|
|
18205
18205
|
| `bash "$DRAFT_TOOLS/hotspot-rank.sh" [--top N]` | complexity-weighted hotspots | Emits `{hotspots:[],source:"unavailable"}` and exits 2 |
|
|
18206
18206
|
| `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 |
|
|
18207
|
+
| `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
18208
|
| `bash "$DRAFT_TOOLS/graph-callers.sh" --symbol N [--transitive[=N]] [--prod-only] [--qualified]` | callers | `{callers:[],status:"unavailable",source:"unavailable"}`, exit 2 |
|
|
18209
18209
|
| `bash "$DRAFT_TOOLS/graph-snippet.sh" --qualified N` | verified source + caller/callee counts | `{status:"unavailable",source:"unavailable"}`, exit 2 |
|
|
18210
18210
|
| `bash "$DRAFT_TOOLS/graph-search.sh" --query "STR" [--limit N]` | semantic/ranked search | `{results:[],source:"unavailable"}`, exit 2 |
|
|
@@ -18234,7 +18234,9 @@ bare `[]` as a confirmed true negative:
|
|
|
18234
18234
|
| `ok` | node found, edges returned |
|
|
18235
18235
|
| `no-edges` | node exists but has no matching edge (a *real* negative) |
|
|
18236
18236
|
| `no-match` | the named symbol was not found at all (check the name / try `--qualified`) |
|
|
18237
|
-
| `unavailable` | engine could not be resolved (exit 2) |
|
|
18237
|
+
| `unavailable` | engine could not be resolved, or engine returned shapeless/non-row JSON (exit 2) |
|
|
18238
|
+
|
|
18239
|
+
**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`.
|
|
18238
18240
|
|
|
18239
18241
|
**Verified engine param shapes** (engine v0.8.x — the runtime source of truth is
|
|
18240
18242
|
`get_graph_schema`; do not hardcode a property set):
|
|
@@ -18305,7 +18307,7 @@ The engine uses a **unified, language-agnostic** node model — `Function`, `Met
|
|
|
18305
18307
|
|
|
18306
18308
|
## Query Tools
|
|
18307
18309
|
|
|
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
|
|
18310
|
+
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
18311
|
|
|
18310
18312
|
### Callers — who calls this function?
|
|
18311
18313
|
|
|
@@ -18472,7 +18474,7 @@ The engine indexes C/C++, Go, Python, TypeScript/JS, and more (tree-sitter, 159
|
|
|
18472
18474
|
| Scenario | Behavior |
|
|
18473
18475
|
|----------|----------|
|
|
18474
18476
|
| 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 |
|
|
18477
|
+
| 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
18478
|
| `draft/graph/schema.yaml` exists | Engine is wired — use live query tools as needed during the run |
|
|
18477
18479
|
| Engine index out of date | The engine indexes incrementally (content-based, git-aware) on each query, so it self-freshens. Re-run `graph-snapshot.sh` (or init) to force a reindex and refresh the marker. |
|
|
18478
18480
|
|
|
@@ -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
|
|
|
@@ -18204,7 +18204,7 @@ DRAFT_TOOLS="${DRAFT_PLUGIN_ROOT:-$(cat ~/.cache/draft/plugin-root 2>/dev/null)}
|
|
|
18204
18204
|
|---|---|---|
|
|
18205
18205
|
| `bash "$DRAFT_TOOLS/hotspot-rank.sh" [--top N]` | complexity-weighted hotspots | Emits `{hotspots:[],source:"unavailable"}` and exits 2 |
|
|
18206
18206
|
| `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 |
|
|
18207
|
+
| `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
18208
|
| `bash "$DRAFT_TOOLS/graph-callers.sh" --symbol N [--transitive[=N]] [--prod-only] [--qualified]` | callers | `{callers:[],status:"unavailable",source:"unavailable"}`, exit 2 |
|
|
18209
18209
|
| `bash "$DRAFT_TOOLS/graph-snippet.sh" --qualified N` | verified source + caller/callee counts | `{status:"unavailable",source:"unavailable"}`, exit 2 |
|
|
18210
18210
|
| `bash "$DRAFT_TOOLS/graph-search.sh" --query "STR" [--limit N]` | semantic/ranked search | `{results:[],source:"unavailable"}`, exit 2 |
|
|
@@ -18234,7 +18234,9 @@ bare `[]` as a confirmed true negative:
|
|
|
18234
18234
|
| `ok` | node found, edges returned |
|
|
18235
18235
|
| `no-edges` | node exists but has no matching edge (a *real* negative) |
|
|
18236
18236
|
| `no-match` | the named symbol was not found at all (check the name / try `--qualified`) |
|
|
18237
|
-
| `unavailable` | engine could not be resolved (exit 2) |
|
|
18237
|
+
| `unavailable` | engine could not be resolved, or engine returned shapeless/non-row JSON (exit 2) |
|
|
18238
|
+
|
|
18239
|
+
**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`.
|
|
18238
18240
|
|
|
18239
18241
|
**Verified engine param shapes** (engine v0.8.x — the runtime source of truth is
|
|
18240
18242
|
`get_graph_schema`; do not hardcode a property set):
|
|
@@ -18305,7 +18307,7 @@ The engine uses a **unified, language-agnostic** node model — `Function`, `Met
|
|
|
18305
18307
|
|
|
18306
18308
|
## Query Tools
|
|
18307
18309
|
|
|
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
|
|
18310
|
+
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
18311
|
|
|
18310
18312
|
### Callers — who calls this function?
|
|
18311
18313
|
|
|
@@ -18472,7 +18474,7 @@ The engine indexes C/C++, Go, Python, TypeScript/JS, and more (tree-sitter, 159
|
|
|
18472
18474
|
| Scenario | Behavior |
|
|
18473
18475
|
|----------|----------|
|
|
18474
18476
|
| 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 |
|
|
18477
|
+
| 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
18478
|
| `draft/graph/schema.yaml` exists | Engine is wired — use live query tools as needed during the run |
|
|
18477
18479
|
| Engine index out of date | The engine indexes incrementally (content-based, git-aware) on each query, so it self-freshens. Re-run `graph-snapshot.sh` (or init) to force a reindex and refresh the marker. |
|
|
18478
18480
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@drafthq/draft",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
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"
|
|
@@ -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
|
},
|
|
@@ -80,7 +80,7 @@ TMP="$(mktemp -d)"
|
|
|
80
80
|
trap 'rm -rf "$TMP"' EXIT
|
|
81
81
|
|
|
82
82
|
echo "Fetching ${ARCHIVE} (${VERSION})..."
|
|
83
|
-
if ! curl -fSL --max-time 300 -o "$TMP/$ARCHIVE" "$BASE/$ARCHIVE"; then
|
|
83
|
+
if ! curl -fSL --proto '=https' --proto-redir '=https' --max-time 300 -o "$TMP/$ARCHIVE" "$BASE/$ARCHIVE"; then
|
|
84
84
|
echo "error: download failed: $BASE/$ARCHIVE" >&2
|
|
85
85
|
exit 2
|
|
86
86
|
fi
|
|
@@ -98,7 +98,7 @@ unverified() {
|
|
|
98
98
|
echo " warning: $1 — skipping verification (set DRAFT_STRICT_VERIFY=1 to make this fatal)" >&2
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
if curl -fsSL --max-time 60 -o "$TMP/checksums.txt" "$BASE/checksums.txt" 2>/dev/null; then
|
|
101
|
+
if curl -fsSL --proto '=https' --proto-redir '=https' --max-time 60 -o "$TMP/checksums.txt" "$BASE/checksums.txt" 2>/dev/null; then
|
|
102
102
|
expected="$(grep " $ARCHIVE\$" "$TMP/checksums.txt" 2>/dev/null | awk '{print $1}' | head -1 || true)"
|
|
103
103
|
if [[ -n "$expected" ]]; then
|
|
104
104
|
if command -v sha256sum >/dev/null 2>&1; then
|
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>]"'
|
|
@@ -83,7 +83,9 @@ gq_run() {
|
|
|
83
83
|
payload="$(jq -n --arg p "$project" --arg q "$query" '{project:$p, query:$q}')" || return 3
|
|
84
84
|
res="$(memory_cli query_graph "$payload" 2>/dev/null || true)"
|
|
85
85
|
[[ -n "$res" ]] || return 3
|
|
86
|
-
|
|
86
|
+
# Shapeless JSON (`{}`) is not an empty result — it is a failed query.
|
|
87
|
+
# Callers must not treat it as a measured true-negative.
|
|
88
|
+
printf '%s' "$res" | jq -e 'has("rows") and (.rows | type == "array")' >/dev/null 2>&1 || return 3
|
|
87
89
|
printf '%s' "$res"
|
|
88
90
|
}
|
|
89
91
|
|
|
@@ -109,7 +109,11 @@ else
|
|
|
109
109
|
# `head` lets head close the pipe early, which under `pipefail` surfaces
|
|
110
110
|
# sort's SIGPIPE as a hard failure — non-deterministically, depending on
|
|
111
111
|
# whether the output fit in the pipe buffer.
|
|
112
|
-
|
|
112
|
+
# git ls-tree -l: "mode type sha size<TAB>path" — path may contain spaces.
|
|
113
|
+
largest="$(awk -F '\t' '$1 ~ / [0-9]+$/ {
|
|
114
|
+
n = split($1, a, " ")
|
|
115
|
+
printf " %8.2f MB %s\n", a[n] / 1048576, $2
|
|
116
|
+
}' <<< "$listing" | sort -rn)"
|
|
113
117
|
head -n "$TOP" <<< "$largest"
|
|
114
118
|
fi
|
|
115
119
|
fi
|
|
@@ -64,8 +64,8 @@ graph_bootstrap "$REPO" || unavailable
|
|
|
64
64
|
# derived from a query that never ran, which is exactly the true-negative
|
|
65
65
|
# confusion Guardrail 4 exists to prevent, and the one failure mode a caller
|
|
66
66
|
# cannot detect. Both queries must land for the sample to mean anything, so
|
|
67
|
-
# either failure routes to `unavailable`. gq_run
|
|
68
|
-
# JSON
|
|
67
|
+
# either failure routes to `unavailable`. gq_run requires a `.rows` array, so
|
|
68
|
+
# shapeless JSON (`{}`) is unavailable, not an empty sample.
|
|
69
69
|
R2="$(gq_run "$PROJECT" "$(gq_q_cycles2)")" || unavailable
|
|
70
70
|
R3="$(gq_run "$PROJECT" "$(gq_q_cycles3)")" || unavailable
|
|
71
71
|
|
|
@@ -88,7 +88,7 @@ if [[ "$TRANSITIVE" -eq 1 ]]; then
|
|
|
88
88
|
PAYLOAD="$(jq -n --arg p "$PROJECT" --arg f "$SYMBOL" --argjson d "$DEPTH" \
|
|
89
89
|
'{project:$p, function_name:$f, depth:$d, direction:"both"}')"
|
|
90
90
|
RES="$(memory_cli trace_path "$PAYLOAD" 2>/dev/null || true)"
|
|
91
|
-
echo "$RES" | jq -e . >/dev/null 2>&1 || unavailable
|
|
91
|
+
echo "$RES" | jq -e 'has("callers") and (.callers | type == "array")' >/dev/null 2>&1 || unavailable
|
|
92
92
|
N="$(echo "$RES" | jq -r '(.callers // []) | length' 2>/dev/null || echo 0)"
|
|
93
93
|
if [[ "$N" -gt 0 ]]; then STATUS="ok"; else
|
|
94
94
|
STATUS="$(gq_symbol_status "$PROJECT" "$SYM_ESC" '{"rows":[]}')"
|
|
@@ -77,7 +77,8 @@ if [[ -n "$SYMBOL" ]]; then
|
|
|
77
77
|
PAYLOAD="$(jq -n --arg p "$PROJECT" --arg f "$SYMBOL" --argjson d "$DEPTH" \
|
|
78
78
|
'{project:$p, function_name:$f, depth:$d, direction:"both"}')"
|
|
79
79
|
RES="$(memory_cli trace_path "$PAYLOAD" 2>/dev/null || true)"
|
|
80
|
-
echo "$RES" | jq -e . >/dev/null 2>&1
|
|
80
|
+
echo "$RES" | jq -e 'has("callers") and (.callers | type == "array")' >/dev/null 2>&1 \
|
|
81
|
+
|| unavailable "$TARGET" "$KIND"
|
|
81
82
|
echo "$RES" | jq --arg t "$TARGET" '
|
|
82
83
|
{target:$t, kind:"symbol",
|
|
83
84
|
impacted: [ (.callers // [])[] | {name:.name, file:(.file_path // ""), qualified:(.qualified_name // ""), hop:(.hop // 1)} ],
|
|
@@ -86,7 +87,8 @@ else
|
|
|
86
87
|
# File impact: detect_changes maps the working-tree diff to impacted symbols.
|
|
87
88
|
PAYLOAD="$(jq -n --arg p "$PROJECT" '{project:$p}')"
|
|
88
89
|
RES="$(memory_cli detect_changes "$PAYLOAD" 2>/dev/null || true)"
|
|
89
|
-
echo "$RES" | jq -e . >/dev/null 2>&1
|
|
90
|
+
echo "$RES" | jq -e 'has("impacted_symbols") and (.impacted_symbols | type == "array")' >/dev/null 2>&1 \
|
|
91
|
+
|| unavailable "$TARGET" "$KIND"
|
|
90
92
|
echo "$RES" | jq --arg t "$TARGET" '
|
|
91
93
|
{target:$t, kind:"file",
|
|
92
94
|
impacted: [ (.impacted_symbols // [])[]
|
|
@@ -80,7 +80,11 @@ PROJECT="$(memory_ensure_index "$REPO_ABS" || true)"
|
|
|
80
80
|
# one never appeared, and nothing in the output said so. Refreshing is this tool's
|
|
81
81
|
# entire job. The engine indexes incrementally, so the repeat call is cheap.
|
|
82
82
|
REFRESHED="$(memory_index_bounded "$REPO_ABS" 2>/dev/null | jq -r '.project // empty' 2>/dev/null || true)"
|
|
83
|
-
[[ -
|
|
83
|
+
if [[ -z "$REFRESHED" ]]; then
|
|
84
|
+
echo "index refresh failed — nothing written" >&2
|
|
85
|
+
exit 2
|
|
86
|
+
fi
|
|
87
|
+
PROJECT="$REFRESHED"
|
|
84
88
|
|
|
85
89
|
mkdir -p "$OUT"
|
|
86
90
|
|
|
@@ -108,7 +108,7 @@ render_co_change() {
|
|
|
108
108
|
render_proto_map() {
|
|
109
109
|
local res; res="$(memory_cli get_architecture \
|
|
110
110
|
"$(jq -n --arg p "$PROJECT" '{project:$p, aspects:["routes"]}')" || true)"
|
|
111
|
-
[[ -n "$res" ]] && echo "$res" | jq -e . >/dev/null 2>&1 || return 2
|
|
111
|
+
[[ -n "$res" ]] && echo "$res" | jq -e 'has("routes") and (.routes | type == "array")' >/dev/null 2>&1 || return 2
|
|
112
112
|
local edges; edges="$(echo "$res" | jq -r '(.routes // [])[] | " \"" + ((.method // "")|tostring) + " " + ((.path // "")|tostring) + "\" --> \"" + ((.handler // "?")|tostring) + "\""' 2>/dev/null || true)"
|
|
113
113
|
if [[ -z "$edges" ]]; then return 1; fi
|
|
114
114
|
printf '```mermaid\nflowchart LR\n%s\n```\n' "$edges"
|
|
@@ -82,6 +82,9 @@ sniff_desc() {
|
|
|
82
82
|
|
|
83
83
|
write_page() {
|
|
84
84
|
local cid="$1" ctype="$2" resource="$3" fan_in="$4"
|
|
85
|
+
case "$cid" in
|
|
86
|
+
''|/*|*..*) echo "ERROR: concept_id escapes bundle: $cid" >&2; return 1 ;;
|
|
87
|
+
esac
|
|
85
88
|
local out="$BUNDLE/$cid"
|
|
86
89
|
mkdir -p "$(dirname "$out")"
|
|
87
90
|
if [[ -f "$out" && $FORCE -eq 0 ]]; then
|
|
@@ -226,7 +226,7 @@ render_architecture() {
|
|
|
226
226
|
if [[ -x "$SCRIPT_DIR/okf-fix-links.sh" ]]; then
|
|
227
227
|
draft_dir="$(cd "$(dirname "$out")" && pwd)"
|
|
228
228
|
if [[ -d "$draft_dir/wiki" || "$(basename "$BUNDLE")" == "wiki" ]]; then
|
|
229
|
-
"$SCRIPT_DIR/okf-fix-links.sh" --file "$out" --wiki "$BUNDLE" --fix >/dev/null 2>&1 ||
|
|
229
|
+
"$SCRIPT_DIR/okf-fix-links.sh" --file "$out" --wiki "$BUNDLE" --fix >/dev/null 2>&1 || exit 1
|
|
230
230
|
fi
|
|
231
231
|
fi
|
|
232
232
|
echo "rendered architecture view → $out ($(ordered_pages | grep -c . ) pages)"
|
|
@@ -411,13 +411,15 @@ function resolve(base, href){
|
|
|
411
411
|
if(p==='..') out.pop(); else if(p!=='.'&&p!=='') out.push(p); }
|
|
412
412
|
return out.join('/');
|
|
413
413
|
}
|
|
414
|
+
function escAttr(s){return esc(s).replace(/"/g,'"');}
|
|
414
415
|
function inline(s, base){
|
|
415
416
|
s = s.replace(/`([^`]+)`/g, function(m,c){return '<code>'+esc(c)+'</code>';});
|
|
416
417
|
s = s.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g, function(m,t,u){
|
|
417
|
-
if(/^
|
|
418
|
+
if(/^(https?|mailto):/i.test(u)) return '<a href="'+escAttr(u)+'" target="_blank" rel="noopener">'+t+'</a>';
|
|
419
|
+
if(/^[a-z][a-z0-9+.-]*:/i.test(u)) return t;
|
|
418
420
|
var key=resolve(base,u);
|
|
419
421
|
if(PAGES[key]) return '<a href="#'+key+'" data-nav="'+key+'">'+t+'</a>';
|
|
420
|
-
return '<span title="'+
|
|
422
|
+
return '<span title="'+escAttr(u)+'">'+t+'</span>';
|
|
421
423
|
});
|
|
422
424
|
s = s.replace(/\*\*([^*]+)\*\*/g,'<strong>$1</strong>');
|
|
423
425
|
s = s.replace(/(^|[^*])\*([^*\n]+)\*/g,'$1<em>$2</em>');
|
|
@@ -438,7 +440,7 @@ function render(md, base){
|
|
|
438
440
|
out+='<table>';
|
|
439
441
|
rows.forEach(function(r,ri){
|
|
440
442
|
var cells=r.replace(/^\||\|$/g,'').split('|');
|
|
441
|
-
out+='<tr>'+cells.map(function(c){var t=ri===0?'th':'td';return '<'+t+'>'+inline(c.trim(),base)+'</'+t+'>';}).join('')+'</tr>';
|
|
443
|
+
out+='<tr>'+cells.map(function(c){var t=ri===0?'th':'td';return '<'+t+'>'+inline(esc(c.trim()),base)+'</'+t+'>';}).join('')+'</tr>';
|
|
442
444
|
});
|
|
443
445
|
out+='</table>'; tbl=[];
|
|
444
446
|
}
|
|
@@ -252,6 +252,11 @@ if [[ -n "$PATH_INDEX" ]]; then
|
|
|
252
252
|
# span lines and a line-oriented match would silently skip them.
|
|
253
253
|
while IFS= read -r ref; do
|
|
254
254
|
[[ -z "$ref" ]] && continue
|
|
255
|
+
case "$ref" in
|
|
256
|
+
/*|*..*)
|
|
257
|
+
add_error "path-index escapes the bundle: $ref"
|
|
258
|
+
continue ;;
|
|
259
|
+
esac
|
|
255
260
|
if [[ ! -f "$BUNDLE/$ref" ]]; then
|
|
256
261
|
add_error "path-index references missing concept page: $ref"
|
|
257
262
|
fi
|
|
@@ -53,8 +53,10 @@ resolve() {
|
|
|
53
53
|
# 2. Install marker written by `draft install` (authoritative).
|
|
54
54
|
local marker="$HOME/.cache/draft/plugin-root"
|
|
55
55
|
if [ -f "$marker" ]; then
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
local root
|
|
57
|
+
root="$(cat "$marker" 2>/dev/null || true)"
|
|
58
|
+
d="${root}/scripts/tools"
|
|
59
|
+
[ -n "$root" ] && [ -d "$d" ] && { printf '%s' "$d"; return 0; }
|
|
58
60
|
fi
|
|
59
61
|
|
|
60
62
|
# 3. ${CLAUDE_PLUGIN_ROOT} — set in hook/MCP contexts; harmless to probe.
|
|
@@ -66,7 +68,7 @@ resolve() {
|
|
|
66
68
|
if command -v jq >/dev/null 2>&1 && [ -f "$reg" ]; then
|
|
67
69
|
local ip
|
|
68
70
|
ip="$(jq -r '.plugins | to_entries[] | select(.key|startswith("draft@")) | .value[0].installPath' \
|
|
69
|
-
"$reg" 2>/dev/null | head -1)"
|
|
71
|
+
"$reg" 2>/dev/null | head -1 || true)"
|
|
70
72
|
[ -n "$ip" ] && [ -d "$ip/scripts/tools" ] && { printf '%s' "$ip/scripts/tools"; return 0; }
|
|
71
73
|
fi
|
|
72
74
|
|
|
@@ -78,7 +78,15 @@ emit_array() {
|
|
|
78
78
|
local first=true
|
|
79
79
|
printf '['
|
|
80
80
|
while IFS= read -r _ln; do
|
|
81
|
-
|
|
81
|
+
# Path may contain colons (e.g. src/foo:bar.js). The line number is the
|
|
82
|
+
# last :<digits>: separator git-grep/rg -n emit.
|
|
83
|
+
if [[ "$_ln" =~ ^(.+):([0-9]+):(.*)$ ]]; then
|
|
84
|
+
path="${BASH_REMATCH[1]}"
|
|
85
|
+
linenum="${BASH_REMATCH[2]}"
|
|
86
|
+
rest="${BASH_REMATCH[3]}"
|
|
87
|
+
else
|
|
88
|
+
continue
|
|
89
|
+
fi
|
|
82
90
|
[[ -z "$path" || -z "$linenum" ]] && continue
|
|
83
91
|
# Skip binaries or tool's own output directory.
|
|
84
92
|
[[ "$path" == */.git/* ]] && continue
|
|
@@ -27,7 +27,7 @@ Draft commands can be invoked using natural language. If you describe your goal
|
|
|
27
27
|
| "debug this issue", "investigate test failure", "fix crash" | `/draft:debug` | Structured 4-stage debugging workflow |
|
|
28
28
|
| "deploy checklist", "release checks", "pre-flight checks" | `/draft:deploy-checklist` | Pre-deployment verification checklist |
|
|
29
29
|
| "test strategy", "design test suite", "testing targets" | `/draft:testing-strategy` | Design standard testing plan |
|
|
30
|
-
| "tech debt analysis", "catalog debt", "code debt" | `/draft:tech-debt` | Technical debt audit across
|
|
30
|
+
| "tech debt analysis", "catalog debt", "code debt" | `/draft:tech-debt` | Technical debt audit across 7 dimensions |
|
|
31
31
|
| "weekly standup", "what did I do today", "activity summary" | `/draft:standup` | Summarize recent Git and file contributions |
|
|
32
32
|
| "incident", "production outage", "mitigate bug" | `/draft:incident-response` | Triage, mitigation, and postmortem incident flow |
|
|
33
33
|
| "write docs", "create readme", "api documentation" | `/draft:documentation` | Generate professional, structured docs |
|