@drafthq/draft 3.6.0 → 3.7.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 +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/README.md +28 -49
- package/bin/README.md +47 -1
- package/cli/src/installer.js +1 -1
- package/cli/src/lib/cursor-registry.js +10 -0
- package/core/agents/architect.md +21 -9
- package/core/agents/debugger.md +5 -0
- package/core/agents/ops.md +7 -2
- package/core/agents/planner.md +7 -0
- package/core/agents/rca.md +14 -3
- package/core/agents/reviewer.md +1 -0
- package/core/agents/writer.md +6 -0
- package/core/knowledge-base.md +22 -3
- package/core/methodology.md +30 -5
- package/core/shared/condensation.md +27 -17
- package/core/shared/context-verify.md +3 -1
- package/core/shared/cross-skill-dispatch.md +7 -3
- package/core/shared/draft-context-loading.md +3 -0
- package/core/shared/git-report-metadata.md +1 -0
- package/core/shared/graph-query.md +0 -2
- package/core/shared/graph-usage-report.md +1 -1
- package/core/shared/jira-sync.md +10 -6
- package/core/shared/okf-retrieval.md +1 -1
- package/core/shared/parallel-analysis.md +14 -7
- package/core/shared/pattern-learning.md +2 -0
- package/core/shared/template-contract.md +1 -1
- package/core/shared/vcs-commands.md +5 -2
- package/core/templates/ai-context.md +3 -2
- package/core/templates/ai-profile.md +7 -0
- package/core/templates/architecture.md +6 -2
- package/core/templates/discovery.md +1 -1
- package/core/templates/guardrails.md +9 -0
- package/core/templates/hld.md +5 -4
- package/core/templates/intake-questions.md +45 -0
- package/core/templates/jira.md +11 -2
- package/core/templates/lld.md +8 -5
- package/core/templates/okf/concept.md +0 -1
- package/core/templates/product.md +11 -2
- package/core/templates/rca.md +6 -0
- package/core/templates/service-index.md +1 -0
- package/core/templates/spec.md +15 -0
- package/core/templates/tech-stack.md +12 -0
- package/core/templates/workflow.md +20 -0
- package/integrations/agents/AGENTS.md +1272 -292
- package/integrations/copilot/.github/copilot-instructions.md +1272 -292
- package/package.json +1 -1
- package/scripts/fetch-memory-engine.sh +24 -6
- package/scripts/lib.sh +11 -4
- package/scripts/tools/_graph_queries.sh +10 -3
- package/scripts/tools/_lib.sh +33 -11
- package/scripts/tools/check-repo-size.sh +125 -0
- package/scripts/tools/check-skill-line-caps.sh +1 -2
- package/scripts/tools/check-template-noop.sh +0 -1
- package/scripts/tools/classify-files.sh +2 -2
- package/scripts/tools/cycle-detect.sh +16 -8
- package/scripts/tools/fix-whitespace.sh +3 -0
- package/scripts/tools/git-metadata.sh +6 -0
- package/scripts/tools/graph-arch.sh +1 -1
- package/scripts/tools/graph-callers.sh +6 -3
- package/scripts/tools/graph-impact.sh +4 -2
- package/scripts/tools/graph-init.sh +12 -8
- package/scripts/tools/graph-preflight.sh +3 -0
- package/scripts/tools/graph-query.sh +70 -7
- package/scripts/tools/graph-snapshot.sh +29 -5
- package/scripts/tools/hotspot-rank.sh +2 -1
- package/scripts/tools/install-smoke-test.sh +223 -0
- package/scripts/tools/mermaid-from-graph.sh +2 -1
- package/scripts/tools/migrate-track-frontmatter.sh +9 -10
- package/scripts/tools/okf-coverage-check.sh +4 -3
- package/scripts/tools/okf-fix-links.sh +18 -93
- package/scripts/tools/okf-plan-concepts.sh +5 -8
- package/scripts/tools/okf-render-views.sh +19 -14
- package/scripts/tools/okf-validate-quality.sh +13 -2
- package/scripts/tools/okf-validate.sh +13 -2
- package/scripts/tools/parse-git-log.sh +19 -1
- package/scripts/tools/resolve-tools.sh +24 -8
- package/scripts/tools/verify-citations.sh +1 -2
- package/scripts/tools/verify-doc-anchors.sh +13 -33
- package/scripts/tools/verify-graph-binary.sh +13 -3
- package/skills/GRAPH.md +21 -10
- package/skills/adr/SKILL.md +24 -6
- package/skills/assist-review/SKILL.md +2 -1
- package/skills/bughunt/SKILL.md +54 -11
- package/skills/bughunt/references/regression-tests.md +14 -4
- package/skills/change/SKILL.md +19 -9
- package/skills/coverage/SKILL.md +26 -10
- package/skills/debug/SKILL.md +12 -2
- package/skills/decompose/SKILL.md +39 -9
- package/skills/deep-review/SKILL.md +17 -4
- package/skills/deploy-checklist/SKILL.md +9 -2
- package/skills/documentation/SKILL.md +12 -1
- package/skills/draft/SKILL.md +40 -29
- package/skills/draft/context-files.md +8 -1
- package/skills/draft/quality-guide.md +10 -2
- package/skills/graph/SKILL.md +1 -1
- package/skills/impact/SKILL.md +3 -1
- package/skills/implement/SKILL.md +60 -18
- package/skills/incident-response/SKILL.md +5 -2
- package/skills/init/SKILL.md +102 -23
- package/skills/init/references/architecture-spec.md +31 -7
- package/skills/init/references/okf-emitter.md +3 -3
- package/skills/jira/SKILL.md +33 -13
- package/skills/jira/references/review.md +61 -19
- package/skills/learn/SKILL.md +29 -6
- package/skills/new-track/SKILL.md +73 -18
- package/skills/quick-review/SKILL.md +7 -2
- package/skills/revert/SKILL.md +11 -5
- package/skills/review/SKILL.md +123 -24
- package/skills/review/references/zero-setup-mode.md +117 -0
- package/skills/standup/SKILL.md +9 -1
- package/skills/status/SKILL.md +6 -6
- package/skills/tech-debt/SKILL.md +7 -1
- package/skills/testing-strategy/SKILL.md +10 -2
- package/skills/tour/SKILL.md +2 -1
- package/skills/upload/SKILL.md +3 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# okf-render-views.sh — render the demoted views from an OKF taxonomy bundle.
|
|
3
3
|
#
|
|
4
|
-
# The wiki/ bundle is the source of truth. This produces the
|
|
4
|
+
# The wiki/ bundle is the source of truth. This produces the derived,
|
|
5
5
|
# human-facing views deterministically (so they never drift from the bundle and
|
|
6
6
|
# carry zero extra maintenance):
|
|
7
7
|
# 1. architecture.md — a single linear concatenation of every concept page,
|
|
@@ -24,6 +24,11 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
24
24
|
# shellcheck source=scripts/tools/_lib.sh
|
|
25
25
|
source "$SCRIPT_DIR/_lib.sh"
|
|
26
26
|
|
|
27
|
+
command -v python3 >/dev/null 2>&1 || {
|
|
28
|
+
echo "ERROR: python3 is required by ${0##*/} (link rewriting in rendered views)" >&2
|
|
29
|
+
exit 2
|
|
30
|
+
}
|
|
31
|
+
|
|
27
32
|
BUNDLE=""
|
|
28
33
|
ARCH_OUT=""
|
|
29
34
|
WEB_OUT=""
|
|
@@ -56,7 +61,7 @@ Flags:
|
|
|
56
61
|
this tool has no clock dependency).
|
|
57
62
|
--help Show this help.
|
|
58
63
|
|
|
59
|
-
Requires jq (
|
|
64
|
+
Requires jq (for --web) and python3 (link rewriting). Exit 0 ok, 1 error, 2 bundle not found.
|
|
60
65
|
EOF
|
|
61
66
|
}
|
|
62
67
|
|
|
@@ -100,8 +105,6 @@ ordered_pages() {
|
|
|
100
105
|
done
|
|
101
106
|
}
|
|
102
107
|
|
|
103
|
-
# Strip YAML frontmatter from a page (leading --- ... --- block on line 1).
|
|
104
|
-
|
|
105
108
|
# Rewrite markdown links so concatenated architecture.md (at draft/) resolves them.
|
|
106
109
|
# stdin body; $1 = bundle-relative path e.g. systems/foo.md
|
|
107
110
|
rewrite_body_links() {
|
|
@@ -133,6 +136,7 @@ sys.stdout.write(re.sub(r"\[([^\]]*)\]\(([^)]+)\)", repl, text))
|
|
|
133
136
|
' "$sec"
|
|
134
137
|
}
|
|
135
138
|
|
|
139
|
+
# Strip YAML frontmatter from a page (leading --- ... --- block on line 1).
|
|
136
140
|
strip_frontmatter() {
|
|
137
141
|
awk '
|
|
138
142
|
NR==1 && /^---$/ { fm=1; next }
|
|
@@ -217,6 +221,7 @@ render_architecture() {
|
|
|
217
221
|
strip_frontmatter "$BUNDLE/$rel" | rewrite_body_links "$rel"
|
|
218
222
|
done < <(ordered_pages)
|
|
219
223
|
} >"$tmp"
|
|
224
|
+
apply_dest_mode "$tmp" "$out" # mktemp is 0600; mv would strip the dest's mode
|
|
220
225
|
mv "$tmp" "$out"
|
|
221
226
|
if [[ -x "$SCRIPT_DIR/okf-fix-links.sh" ]]; then
|
|
222
227
|
draft_dir="$(cd "$(dirname "$out")" && pwd)"
|
|
@@ -243,12 +248,7 @@ build_concept_map() {
|
|
|
243
248
|
[[ -n "$type" ]] || continue
|
|
244
249
|
title="$(get_yaml_field "$page" title)"
|
|
245
250
|
[[ -n "$title" ]] || title="$rel"
|
|
246
|
-
|
|
247
|
-
desc="$(awk '
|
|
248
|
-
NR==1&&/^---$/{fm=1;next} fm&&/^---$/{exit}
|
|
249
|
-
fm && /^description:/ { collect=1; sub(/^description:[[:space:]]*>?[[:space:]]*/,""); if($0!=""){print; exit} next }
|
|
250
|
-
fm && collect { sub(/^[[:space:]]+/,""); if($0!=""){print; exit} }
|
|
251
|
-
' "$page")"
|
|
251
|
+
desc="$(page_desc "$page")"
|
|
252
252
|
echo "| [${title}](${rel}) | ${type} | ${desc} |"
|
|
253
253
|
done < <(find "$BUNDLE" -type f -name '*.md' -print0 | sort -z)
|
|
254
254
|
}
|
|
@@ -313,14 +313,18 @@ inject_concept_map() {
|
|
|
313
313
|
/<!-- CONCEPT-MAP:END -->/ { skip=0 }
|
|
314
314
|
!skip { print }
|
|
315
315
|
' "$target" >"$tmp"
|
|
316
|
+
apply_dest_mode "$tmp" "$target" # mktemp is 0600; mv would strip the dest's mode
|
|
316
317
|
mv "$tmp" "$target"
|
|
317
318
|
echo "injected Concept Map → $target"
|
|
318
319
|
}
|
|
319
320
|
|
|
320
321
|
# --- 3. Render a self-contained offline HTML viewer (single file) ---
|
|
321
322
|
# All pages are inlined as JSON; a small built-in markdown renderer draws them in
|
|
322
|
-
# the browser. No server, no internet, no CDN. jq encodes page content safely
|
|
323
|
-
#
|
|
323
|
+
# the browser. No server, no internet, no CDN. jq encodes page content safely,
|
|
324
|
+
# and the whole emitted data block is passed through a `</` → `<\/` filter: JSON
|
|
325
|
+
# escaping does NOT stop a literal "</script>" from closing the <script> element,
|
|
326
|
+
# and page titles/types/paths come from repo-derived frontmatter, so every field
|
|
327
|
+
# has to be neutralized, not just the markdown body.
|
|
324
328
|
render_web() {
|
|
325
329
|
local out="$1"
|
|
326
330
|
command -v jq >/dev/null 2>&1 || { echo "ERROR: --web requires jq" >&2; return 1; }
|
|
@@ -388,14 +392,14 @@ HTML_HEAD
|
|
|
388
392
|
"$(jq -Rn --arg v "$rel" '$v')" \
|
|
389
393
|
"$(jq -Rn --arg v "$title" '$v')" \
|
|
390
394
|
"$(jq -Rn --arg v "$type" '$v')" \
|
|
391
|
-
"$(strip_frontmatter "$page" | jq -Rs .
|
|
395
|
+
"$(strip_frontmatter "$page" | jq -Rs .)"
|
|
392
396
|
done < <(find "$BUNDLE" -type f -name '*.md' -print0 | sort -z)
|
|
393
397
|
echo "};"
|
|
394
398
|
# ORDER: bundle root index.md first, then everything else sorted.
|
|
395
399
|
echo "const ORDER = Object.keys(PAGES).sort(function(a,b){"
|
|
396
400
|
echo " if(a==='index.md') return -1; if(b==='index.md') return 1;"
|
|
397
401
|
echo " return a<b?-1:a>b?1:0; });"
|
|
398
|
-
} >>"$tmp"
|
|
402
|
+
} | sed 's#</#<\\/#g' >>"$tmp"
|
|
399
403
|
|
|
400
404
|
cat >>"$tmp" <<'HTML_TAIL'
|
|
401
405
|
function esc(s){return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');}
|
|
@@ -487,6 +491,7 @@ show(decodeURIComponent(location.hash.slice(1)) || ORDER[0]);
|
|
|
487
491
|
HTML_TAIL
|
|
488
492
|
|
|
489
493
|
mkdir -p "$(dirname "$out")"
|
|
494
|
+
apply_dest_mode "$tmp" "$out" # mktemp is 0600; mv would strip the dest's mode
|
|
490
495
|
mv "$tmp" "$out"
|
|
491
496
|
echo "rendered offline HTML viewer → $out ($(find "$BUNDLE" -type f -name '*.md' | grep -c .) pages)"
|
|
492
497
|
}
|
|
@@ -73,6 +73,17 @@ body_of() {
|
|
|
73
73
|
awk 'NR==1&&/^---$/{fm=1;next} fm&&/^---$/{fm=0;next} !fm{print}' "$1"
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
# Body text the Q-TEMPLATE scan is allowed to see: fenced code blocks and
|
|
77
|
+
# shell-style ${VAR} expansions removed. Both legitimately carry {ALL_CAPS}
|
|
78
|
+
# spans that are not unreplaced placeholders (a page quoting `${HOME}` or a CI
|
|
79
|
+
# snippet would otherwise fail).
|
|
80
|
+
template_scan_body() {
|
|
81
|
+
body_of "$1" | awk '
|
|
82
|
+
/^[[:space:]]*```/ { fence = !fence; next }
|
|
83
|
+
!fence { gsub(/\$\{[A-Za-z_][A-Za-z0-9_]*\}/, ""); print }
|
|
84
|
+
'
|
|
85
|
+
}
|
|
86
|
+
|
|
76
87
|
# Count body lines after the frontmatter close (Q-LEN = "lines after frontmatter").
|
|
77
88
|
body_lines() { body_of "$1" | wc -l | tr -d ' '; }
|
|
78
89
|
|
|
@@ -114,7 +125,7 @@ mermaid_lint() {
|
|
|
114
125
|
echo "unicode arrow in mermaid (use --> not →)"; return 1
|
|
115
126
|
fi
|
|
116
127
|
# '&' node chaining (common breaker).
|
|
117
|
-
if printf '%s' "$blocks" | grep -qE '[A-Za-z0-9_]
|
|
128
|
+
if printf '%s' "$blocks" | grep -qE '[A-Za-z0-9_][[:space:]]*&[[:space:]]*[A-Za-z0-9_]'; then
|
|
118
129
|
echo "'&' node chaining in mermaid"; return 1
|
|
119
130
|
fi
|
|
120
131
|
# Reserved bareword node ids.
|
|
@@ -235,7 +246,7 @@ while IFS= read -r -d '' page; do
|
|
|
235
246
|
fi
|
|
236
247
|
|
|
237
248
|
# Q-TEMPLATE: unreplaced {TOKEN} placeholders.
|
|
238
|
-
if
|
|
249
|
+
if template_scan_body "$page" | grep -qE "$TOKEN_RE"; then
|
|
239
250
|
fail "$rel" "Q-TEMPLATE" "unreplaced template token {PLACEHOLDER}"
|
|
240
251
|
fi
|
|
241
252
|
|
|
@@ -176,14 +176,25 @@ while IFS= read -r -d '' page; do
|
|
|
176
176
|
fi
|
|
177
177
|
done < <(find "$BUNDLE" -type f -name '*.md' -print0 | sort -z)
|
|
178
178
|
|
|
179
|
+
# Page text the {ALL_CAPS} template-token scan is allowed to see. Fenced code
|
|
180
|
+
# blocks and shell-style ${VAR} expansions are removed first: both legitimately
|
|
181
|
+
# contain {ALL_CAPS} spans that are NOT unreplaced placeholders, and a wiki page
|
|
182
|
+
# quoting `${HOME}` or a CI snippet would otherwise fail the whole bundle.
|
|
183
|
+
template_scan_text() {
|
|
184
|
+
awk '
|
|
185
|
+
/^[[:space:]]*```/ { fence = !fence; next }
|
|
186
|
+
!fence { gsub(/\$\{[A-Za-z_][A-Za-z0-9_]*\}/, ""); print }
|
|
187
|
+
' "$1"
|
|
188
|
+
}
|
|
189
|
+
|
|
179
190
|
# --- 3b. Unreplaced template tokens (any page, including index pages) ---
|
|
180
191
|
# Quality checks skip index.md pages, so a leftover {SECTION_TITLE}/{PROJECT_NAME}
|
|
181
192
|
# placeholder in a hand-seeded index would otherwise survive. Match {ALL_CAPS}
|
|
182
193
|
# tokens (safe: real prose almost never contains them).
|
|
183
194
|
while IFS= read -r -d '' page; do
|
|
184
195
|
prel="${page#"$BUNDLE/"}"
|
|
185
|
-
|
|
186
|
-
|
|
196
|
+
tok="$(template_scan_text "$page" 2>/dev/null | grep -oE '\{[A-Z][A-Z0-9_]+\}' | head -1 || true)"
|
|
197
|
+
if [[ -n "$tok" ]]; then
|
|
187
198
|
add_error "$prel: unreplaced template token '$tok'"
|
|
188
199
|
fi
|
|
189
200
|
done < <(find "$BUNDLE" -type f -name '*.md' -print0 | sort -z)
|
|
@@ -63,6 +63,13 @@ if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
|
63
63
|
exit 1
|
|
64
64
|
fi
|
|
65
65
|
|
|
66
|
+
# `git log -n <non-numeric>` parses the count as 0 and exits 0, so a typo'd
|
|
67
|
+
# --limit silently yields an empty stream. Reject it here instead.
|
|
68
|
+
if [[ -n "$LIMIT" && ! "$LIMIT" =~ ^[0-9]+$ ]]; then
|
|
69
|
+
echo "ERROR: --limit must be a non-negative integer (got '$LIMIT')" >&2
|
|
70
|
+
exit 1
|
|
71
|
+
fi
|
|
72
|
+
|
|
66
73
|
# Format: delimiter-separated metadata line, then --name-only file list, blank line separator.
|
|
67
74
|
GIT_ARGS=(log --pretty=tformat:'COMMIT%x1f%H%x1f%an%x1f%aI%x1f%s' --name-only --no-merges)
|
|
68
75
|
[[ -n "$SINCE" ]] && GIT_ARGS+=(--since="$SINCE")
|
|
@@ -118,6 +125,17 @@ process_commit() {
|
|
|
118
125
|
|
|
119
126
|
# Single git log stream: each commit is `COMMIT<US>sha<US>author<US>ts<US>subject`
|
|
120
127
|
# followed by its file paths (one per line) and a blank separator.
|
|
128
|
+
#
|
|
129
|
+
# Staged through a temp file rather than `< <(git ...)`: a process substitution
|
|
130
|
+
# swallows git's exit status, so a bad --branch/--since/--limit produced an empty
|
|
131
|
+
# JSONL stream and exit 0 — indistinguishable from "this range has no commits".
|
|
132
|
+
GIT_OUT="$(mktemp)"
|
|
133
|
+
trap 'rm -f "$GIT_OUT"' EXIT
|
|
134
|
+
if ! git "${GIT_ARGS[@]}" >"$GIT_OUT"; then
|
|
135
|
+
echo "ERROR: git log failed (check --branch / --since / --limit)" >&2
|
|
136
|
+
exit 1
|
|
137
|
+
fi
|
|
138
|
+
|
|
121
139
|
cur_sha=""; cur_author=""; cur_ts=""; cur_subject=""; cur_files=0
|
|
122
140
|
while IFS= read -r line; do
|
|
123
141
|
if [[ "$line" == COMMIT$'\x1f'* ]]; then
|
|
@@ -129,7 +147,7 @@ while IFS= read -r line; do
|
|
|
129
147
|
elif [[ -n "$line" ]]; then
|
|
130
148
|
cur_files=$((cur_files + 1))
|
|
131
149
|
fi
|
|
132
|
-
done <
|
|
150
|
+
done < "$GIT_OUT"
|
|
133
151
|
if [[ -n "$cur_sha" ]]; then
|
|
134
152
|
process_commit "$cur_sha" "$cur_author" "$cur_ts" "$cur_subject" "$cur_files"
|
|
135
153
|
fi
|
|
@@ -7,6 +7,14 @@
|
|
|
7
7
|
# See core/shared/tool-resolver.md for the canonical procedure and the inline preamble
|
|
8
8
|
# skills embed (this script is the single source of truth for the resolution order).
|
|
9
9
|
#
|
|
10
|
+
# Resolution order is deliberately "authoritative install first, cwd last":
|
|
11
|
+
# skills execute whatever this prints, and the cwd is the repository under review,
|
|
12
|
+
# which Draft routinely runs against untrusted code. A project that ships its own
|
|
13
|
+
# scripts/tools/ must never shadow the installed plugin.
|
|
14
|
+
#
|
|
15
|
+
# Working on Draft itself? Export DRAFT_PLUGIN_ROOT="$PWD" — the explicit override
|
|
16
|
+
# is step 1 and always wins.
|
|
17
|
+
#
|
|
10
18
|
# Usage:
|
|
11
19
|
# DRAFT_TOOLS="$(scripts/tools/resolve-tools.sh)" # prints the dir, exit 0 if found
|
|
12
20
|
# scripts/tools/resolve-tools.sh || echo "tools not found" # exit 1 if none exist
|
|
@@ -21,8 +29,18 @@ esac
|
|
|
21
29
|
|
|
22
30
|
newest() {
|
|
23
31
|
# Echo the lexically-newest existing match of a glob (by version sort), or nothing.
|
|
32
|
+
# `|| true` is load-bearing: on a glob miss `ls` exits non-zero, pipefail
|
|
33
|
+
# propagates it, and errexit would abort the whole resolver instead of letting
|
|
34
|
+
# the remaining fallbacks run.
|
|
24
35
|
# shellcheck disable=SC2086
|
|
25
|
-
ls -d $1 2>/dev/null | sort -V | tail -1
|
|
36
|
+
ls -d $1 2>/dev/null | sort -V | tail -1 || true
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# Is DIR Draft's own source checkout? Checked before trusting the cwd at all.
|
|
40
|
+
is_draft_checkout() {
|
|
41
|
+
[ -f "$1/scripts/tools/resolve-tools.sh" ] || return 1
|
|
42
|
+
[ -f "$1/.claude-plugin/plugin.json" ] || return 1
|
|
43
|
+
grep -q '"name"[[:space:]]*:[[:space:]]*"draft"' "$1/.claude-plugin/plugin.json" 2>/dev/null
|
|
26
44
|
}
|
|
27
45
|
|
|
28
46
|
resolve() {
|
|
@@ -32,10 +50,6 @@ resolve() {
|
|
|
32
50
|
d="${DRAFT_PLUGIN_ROOT:-}/scripts/tools"
|
|
33
51
|
[ -n "${DRAFT_PLUGIN_ROOT:-}" ] && [ -d "$d" ] && { printf '%s' "$d"; return 0; }
|
|
34
52
|
|
|
35
|
-
# 1b. Dev / dogfooding: cwd IS the draft repo. Guarded by this script's own
|
|
36
|
-
# presence so it can never misfire in a user project (which has no resolve-tools.sh).
|
|
37
|
-
[ -f "$PWD/scripts/tools/resolve-tools.sh" ] && { printf '%s' "$PWD/scripts/tools"; return 0; }
|
|
38
|
-
|
|
39
53
|
# 2. Install marker written by `draft install` (authoritative).
|
|
40
54
|
local marker="$HOME/.cache/draft/plugin-root"
|
|
41
55
|
if [ -f "$marker" ]; then
|
|
@@ -68,9 +82,11 @@ resolve() {
|
|
|
68
82
|
d="$HOME/.cursor/plugins/local/draft/scripts/tools"
|
|
69
83
|
[ -d "$d" ] && { printf '%s' "$d"; return 0; }
|
|
70
84
|
|
|
71
|
-
# 8.
|
|
72
|
-
|
|
73
|
-
|
|
85
|
+
# 8. Last resort — dev / dogfooding inside Draft's own checkout. Deliberately
|
|
86
|
+
# after every install location, and gated on the plugin manifest rather than on
|
|
87
|
+
# a same-named file: a bare `$PWD/scripts/tools` test matched any project using
|
|
88
|
+
# that very common layout and handed it script execution.
|
|
89
|
+
is_draft_checkout "$PWD" && { printf '%s' "$PWD/scripts/tools"; return 0; }
|
|
74
90
|
|
|
75
91
|
return 1
|
|
76
92
|
}
|
|
@@ -189,8 +189,7 @@ scan_one_track() {
|
|
|
189
189
|
|
|
190
190
|
while IFS= read -r f; do
|
|
191
191
|
local rel_md="${f#"$track_dir/"}"
|
|
192
|
-
while IFS=$'\t' read -r
|
|
193
|
-
local md_line="$md_file"
|
|
192
|
+
while IFS=$'\t' read -r _md_file lineno cite; do
|
|
194
193
|
local result rc=0
|
|
195
194
|
# set +e to capture rc; set -e would exit on a non-zero return.
|
|
196
195
|
set +e
|
|
@@ -3,12 +3,16 @@
|
|
|
3
3
|
|
|
4
4
|
#
|
|
5
5
|
# Verify cross-document references in a track:
|
|
6
|
-
# - §X.Y or §X numbered-section references → target document must contain
|
|
7
|
-
# a heading whose text starts with that number.
|
|
8
6
|
# - <doc>.md#<anchor> markdown anchors → resolve <anchor> against the
|
|
9
7
|
# target file's header slugs.
|
|
10
8
|
# - (planned) / [New file ...] annotations → file MUST NOT exist locally.
|
|
11
9
|
#
|
|
10
|
+
# Plain-prose `§X.Y` references are deliberately NOT validated: authors use them
|
|
11
|
+
# as shorthand for an external doc (`architecture.md §20.2`) without naming the
|
|
12
|
+
# file on the same line, so attribution is guesswork. A track that wants a
|
|
13
|
+
# machine-checkable §-reference writes it as a markdown link to the heading,
|
|
14
|
+
# which the anchor check above already covers.
|
|
15
|
+
#
|
|
12
16
|
# Skips content inside <!-- VERIFIER:IGNORE START --> ... END --> blocks.
|
|
13
17
|
#
|
|
14
18
|
# Usage:
|
|
@@ -35,7 +39,7 @@ TRACK_PATHS=()
|
|
|
35
39
|
usage() {
|
|
36
40
|
local stream=2 code=2
|
|
37
41
|
if [[ "${USAGE_HELP_MODE:-0}" == 1 ]]; then stream=1; code=0; fi
|
|
38
|
-
sed -n '2,
|
|
42
|
+
sed -n '2,26p' "$0" >&$stream
|
|
39
43
|
exit "$code"
|
|
40
44
|
}
|
|
41
45
|
|
|
@@ -72,24 +76,15 @@ md_slugs() {
|
|
|
72
76
|
s = tolower(s)
|
|
73
77
|
# Replace spaces with dashes
|
|
74
78
|
gsub(/ +/, "-", s)
|
|
75
|
-
# Strip punctuation except dashes
|
|
76
|
-
|
|
79
|
+
# Strip punctuation except dashes and underscores. GitHub keeps `_`
|
|
80
|
+
# in a heading slug (and so does _lib.sh:gfm_slug) — stripping it
|
|
81
|
+
# here reported every valid #foo_bar-style anchor as missing.
|
|
82
|
+
gsub(/[^a-z0-9_-]/, "", s)
|
|
77
83
|
print s
|
|
78
84
|
}
|
|
79
85
|
' "$1" | sort -u
|
|
80
86
|
}
|
|
81
87
|
|
|
82
|
-
# Extract numbered headers (e.g. "## 7 Parallel SST transfer" or "## 20.2 ...").
|
|
83
|
-
md_numbered_headers() {
|
|
84
|
-
awk '
|
|
85
|
-
/^#{1,6} +[0-9]+(\.[0-9]+)*[ .]/ {
|
|
86
|
-
s = $0
|
|
87
|
-
sub(/^#+ +/, "", s)
|
|
88
|
-
print s
|
|
89
|
-
}
|
|
90
|
-
' "$1"
|
|
91
|
-
}
|
|
92
|
-
|
|
93
88
|
scan_md() {
|
|
94
89
|
local track_dir="$1" md="$2"
|
|
95
90
|
local rel_track="${track_dir#"$REPO_ROOT/"}"
|
|
@@ -101,22 +96,7 @@ scan_md() {
|
|
|
101
96
|
if [[ "$line" == *"<!-- VERIFIER:IGNORE END -->"* ]]; then ignore=0; continue; fi
|
|
102
97
|
(( ignore )) && continue
|
|
103
98
|
|
|
104
|
-
# 1.
|
|
105
|
-
# Plain-prose `§X.Y` is too ambiguous in practice — authors commonly
|
|
106
|
-
# use it as shorthand for an external doc (e.g. `architecture.md §20.2`)
|
|
107
|
-
# without naming the file on the same line. To keep this validator
|
|
108
|
-
# focused on machine-verifiable cross-references, we only check
|
|
109
|
-
# §X.Y when it appears INSIDE a markdown link target — i.e. the
|
|
110
|
-
# author has structurally committed to an in-track reference.
|
|
111
|
-
# Example that IS validated:
|
|
112
|
-
# [see §3.1](./hld.md#detailed-design) ← anchor check below
|
|
113
|
-
# Example that is NOT validated (prose only):
|
|
114
|
-
# The §20.2 layout matches architecture.md.
|
|
115
|
-
# If a track wants stricter intra-track §-checks, it can use
|
|
116
|
-
# markdown links pointing to numbered headers explicitly.
|
|
117
|
-
: # §-ref prose validation disabled — see comment above.
|
|
118
|
-
|
|
119
|
-
# 2. Markdown anchor references like ./hld.md#section-name
|
|
99
|
+
# 1. Markdown anchor references like ./hld.md#section-name
|
|
120
100
|
if echo "$line" | grep -qE '\([^)]*\.md#[A-Za-z0-9_-]+\)'; then
|
|
121
101
|
local m
|
|
122
102
|
while IFS= read -r m; do
|
|
@@ -141,7 +121,7 @@ scan_md() {
|
|
|
141
121
|
done < <(echo "$line" | grep -oE '\([^)]*\.md#[A-Za-z0-9_-]+\)')
|
|
142
122
|
fi
|
|
143
123
|
|
|
144
|
-
#
|
|
124
|
+
# 2. (planned) / [New file ...] annotations: the path mentioned on the
|
|
145
125
|
# same line must NOT yet exist relative to the track.
|
|
146
126
|
#
|
|
147
127
|
# Only fire when the line has EXACTLY one path-looking token. Lines
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
# verify-graph-binary.sh — validate and select the Draft knowledge-graph engine.
|
|
3
3
|
#
|
|
4
4
|
# The engine is the codebase-memory-mcp binary. Resolution order (see _lib.sh:find_memory_bin):
|
|
5
|
+
# 0. DRAFT_MEMORY_DISABLE — hard off; resolution stops here and reports "none"
|
|
5
6
|
# 1. DRAFT_MEMORY_BIN override
|
|
6
7
|
# 2. codebase-memory-mcp on $PATH
|
|
7
8
|
# 3. Draft-managed install (~/.cache/draft/bin/)
|
|
@@ -32,7 +33,8 @@ usage() {
|
|
|
32
33
|
verify-graph-binary.sh — Draft knowledge-graph engine resolver + verifier
|
|
33
34
|
|
|
34
35
|
Engine: codebase-memory-mcp
|
|
35
|
-
Resolution:
|
|
36
|
+
Resolution: DRAFT_MEMORY_DISABLE (hard off) > DRAFT_MEMORY_BIN > PATH
|
|
37
|
+
> ~/.cache/draft/bin > bin/<arch>/
|
|
36
38
|
|
|
37
39
|
Options:
|
|
38
40
|
--repo DIR Repo root for context (default .)
|
|
@@ -95,15 +97,23 @@ classify_source() {
|
|
|
95
97
|
|
|
96
98
|
MEMORY_BIN=""
|
|
97
99
|
if ! find_memory_bin "$REPO_ABS" "$SELF_REPO"; then
|
|
98
|
-
|
|
100
|
+
# DRAFT_MEMORY_DISABLE short-circuits resolution, so say so — "install it or
|
|
101
|
+
# put it on PATH" is the wrong remedy when an env var turned the engine off.
|
|
102
|
+
if [[ -n "${DRAFT_MEMORY_DISABLE:-}" ]]; then
|
|
103
|
+
local_msg="Graph engine disabled by DRAFT_MEMORY_DISABLE (unset it to re-enable resolution)"
|
|
104
|
+
else
|
|
99
105
|
local_msg="No codebase-memory-mcp engine found in DRAFT_MEMORY_BIN, PATH, ~/.cache/draft/bin, or bin/<arch>/"
|
|
106
|
+
fi
|
|
107
|
+
if [[ $EMIT_JSON -eq 1 ]]; then
|
|
100
108
|
if [[ $STRICT -eq 1 ]]; then
|
|
101
109
|
printf '{"status":"none","engine_bin":null,"source":null,"arch":"%s","message":"strict mode: %s"}\n' "$ARCH" "$local_msg"
|
|
102
110
|
else
|
|
103
111
|
printf '{"status":"unavailable","engine_bin":null,"source":null,"arch":"%s","message":"%s"}\n' "$ARCH" "$local_msg"
|
|
104
112
|
fi
|
|
105
113
|
elif [[ $STRICT -eq 1 ]]; then
|
|
106
|
-
echo "STRICT:
|
|
114
|
+
echo "STRICT: $local_msg" >&2
|
|
115
|
+
elif [[ -n "${DRAFT_MEMORY_DISABLE:-}" ]]; then
|
|
116
|
+
echo "ERROR: $local_msg" >&2
|
|
107
117
|
else
|
|
108
118
|
echo "ERROR: No Draft graph engine located (codebase-memory-mcp)." >&2
|
|
109
119
|
echo " Install it (scripts/fetch-memory-engine.sh) or put it on PATH." >&2
|
package/skills/GRAPH.md
CHANGED
|
@@ -8,16 +8,19 @@
|
|
|
8
8
|
## Two-Tier Architecture
|
|
9
9
|
|
|
10
10
|
### Primary Workflow (4 commands)
|
|
11
|
-
|
|
11
|
+
|
|
12
|
+
```text
|
|
12
13
|
init → new-track → implement → review
|
|
13
14
|
↑ |
|
|
14
15
|
└───────────┘ (auto-invoked at phase boundaries)
|
|
15
16
|
```
|
|
16
17
|
|
|
17
18
|
### Routed Core Workflows (5 routers)
|
|
19
|
+
|
|
18
20
|
The 5 routers (`/draft:plan`, `/draft:ops`, `/draft:docs`, `/draft:discover`, `/draft:jira`) provide intent analysis and dispatch to the leaf specialist skills. Primary commands and routers are the public surface; leaves remain for compatibility and direct scripting.
|
|
19
21
|
|
|
20
22
|
### Specialist Leaf Commands
|
|
23
|
+
|
|
21
24
|
Grouped into subsystems dispatched by the routers (or primary commands).
|
|
22
25
|
|
|
23
26
|
---
|
|
@@ -215,7 +218,8 @@ graph TD
|
|
|
215
218
|
## Execution Chains
|
|
216
219
|
|
|
217
220
|
### Standard Development Flow
|
|
218
|
-
|
|
221
|
+
|
|
222
|
+
```text
|
|
219
223
|
init → new-track → implement → review → (git push + PR)
|
|
220
224
|
↑ |
|
|
221
225
|
└───────────┘
|
|
@@ -223,33 +227,38 @@ init → new-track → implement → review → (git push + PR)
|
|
|
223
227
|
```
|
|
224
228
|
|
|
225
229
|
### Bug Fix Flow
|
|
226
|
-
|
|
230
|
+
|
|
231
|
+
```text
|
|
227
232
|
new-track (bug) → debug → implement → review
|
|
228
233
|
↑ |
|
|
229
234
|
└──────────────────────┘ (iterate if fix incomplete)
|
|
230
235
|
```
|
|
231
236
|
|
|
232
237
|
### Incident Response Flow
|
|
233
|
-
|
|
238
|
+
|
|
239
|
+
```text
|
|
234
240
|
incident-response → debug → implement → review
|
|
235
241
|
|
|
|
236
242
|
└→ documentation (post-incident report)
|
|
237
243
|
```
|
|
238
244
|
|
|
239
245
|
### Operations Flow
|
|
240
|
-
|
|
246
|
+
|
|
247
|
+
```text
|
|
241
248
|
standup ←── status (reads tracks + git log)
|
|
242
249
|
deep-review ──→ tech-debt ──→ new-track (prioritized items)
|
|
243
250
|
```
|
|
244
251
|
|
|
245
252
|
### Monorepo Flow
|
|
246
|
-
|
|
253
|
+
|
|
254
|
+
```text
|
|
247
255
|
init (root) → whole-repo code-graph spine + sparse root map
|
|
248
256
|
init (sub-module) → module snapshot + root-link.json → cross-module context via the root spine
|
|
249
257
|
```
|
|
250
258
|
|
|
251
259
|
### Quality Audit Flow
|
|
252
|
-
|
|
260
|
+
|
|
261
|
+
```text
|
|
253
262
|
init → quick-review (fast sanity check)
|
|
254
263
|
init → review (full three-stage)
|
|
255
264
|
init → bughunt (14-dimension sweep)
|
|
@@ -259,14 +268,16 @@ init → decompose (optional pre-step for large modules)
|
|
|
259
268
|
```
|
|
260
269
|
|
|
261
270
|
### Jira Integration Flow
|
|
262
|
-
|
|
271
|
+
|
|
272
|
+
```text
|
|
263
273
|
new-track → jira (preview / create / review subcommands)
|
|
264
274
|
↑
|
|
265
275
|
bughunt + review reports (optional enrichment)
|
|
266
276
|
```
|
|
267
277
|
|
|
268
278
|
### Learning Flow
|
|
269
|
-
|
|
279
|
+
|
|
280
|
+
```text
|
|
270
281
|
init → learn → (updates guardrails.md)
|
|
271
282
|
↓
|
|
272
283
|
All quality skills read guardrails.md
|
|
@@ -290,7 +301,7 @@ init → learn → (updates guardrails.md)
|
|
|
290
301
|
|
|
291
302
|
## Artifact Flow
|
|
292
303
|
|
|
293
|
-
```
|
|
304
|
+
```text
|
|
294
305
|
┌─────────────────────────────────────────────┐
|
|
295
306
|
│ draft/.state/ │
|
|
296
307
|
│ freshness.json signals.json run-memory │
|