@drafthq/draft 3.5.3 → 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/hosts/cursor.js +3 -0
- package/cli/src/installer.js +8 -4
- package/cli/src/lib/cursor-registry.js +10 -0
- package/cli/src/lib/fsx.js +3 -0
- package/cli/src/lib/marker.js +8 -3
- 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 +28 -18
- 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 +2 -1
- package/core/shared/graph-query.md +24 -26
- 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/tool-resolver.md +20 -15
- 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/plan.md +1 -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 +1449 -817
- package/integrations/copilot/.github/copilot-instructions.md +1449 -817
- package/package.json +1 -1
- package/scripts/fetch-memory-engine.sh +25 -7
- package/scripts/lib.sh +90 -6
- package/scripts/tools/_graph_queries.sh +22 -8
- package/scripts/tools/_lib.sh +81 -11
- package/scripts/tools/adr-index.sh +1 -1
- package/scripts/tools/check-repo-size.sh +125 -0
- package/scripts/tools/check-skill-line-caps.sh +3 -4
- package/scripts/tools/check-template-noop.sh +0 -1
- package/scripts/tools/check-track-hygiene.sh +41 -21
- package/scripts/tools/classify-files.sh +3 -3
- package/scripts/tools/cycle-detect.sh +18 -17
- package/scripts/tools/detect-test-framework.sh +1 -1
- package/scripts/tools/emit-skill-metrics.sh +7 -2
- package/scripts/tools/fix-whitespace.sh +3 -0
- package/scripts/tools/freshness-check.sh +2 -2
- package/scripts/tools/git-metadata.sh +12 -6
- package/scripts/tools/graph-arch.sh +5 -11
- package/scripts/tools/graph-callers.sh +10 -15
- package/scripts/tools/graph-deps.sh +3 -10
- package/scripts/tools/graph-errors.sh +4 -11
- package/scripts/tools/graph-hierarchy.sh +4 -11
- package/scripts/tools/graph-impact.sh +21 -19
- package/scripts/tools/graph-init.sh +13 -9
- package/scripts/tools/graph-preflight.sh +4 -1
- package/scripts/tools/graph-query.sh +74 -18
- package/scripts/tools/graph-risk.sh +3 -10
- package/scripts/tools/graph-search.sh +4 -11
- package/scripts/tools/graph-snapshot.sh +38 -9
- package/scripts/tools/graph-snippet.sh +3 -10
- package/scripts/tools/graph-tests.sh +3 -10
- package/scripts/tools/graph-traces.sh +3 -10
- package/scripts/tools/hotspot-rank.sh +6 -12
- package/scripts/tools/install-smoke-test.sh +223 -0
- package/scripts/tools/mermaid-from-graph.sh +5 -11
- package/scripts/tools/migrate-track-frontmatter.sh +11 -10
- package/scripts/tools/okf-coverage-check.sh +8 -7
- package/scripts/tools/okf-emit-catalog.sh +256 -0
- package/scripts/tools/okf-fix-links.sh +251 -0
- package/scripts/tools/okf-plan-concepts.sh +242 -14
- package/scripts/tools/okf-render-views.sh +63 -21
- package/scripts/tools/okf-validate-all.sh +20 -9
- package/scripts/tools/okf-validate-quality.sh +15 -10
- package/scripts/tools/okf-validate.sh +20 -6
- package/scripts/tools/parse-git-log.sh +23 -5
- package/scripts/tools/parse-reports.sh +1 -1
- package/scripts/tools/render-track.sh +1 -1
- package/scripts/tools/resolve-tools.sh +24 -8
- package/scripts/tools/run-coverage.sh +1 -1
- package/scripts/tools/scan-markers.sh +4 -4
- package/scripts/tools/validate-frontmatter.sh +2 -2
- package/scripts/tools/verify-citations.sh +3 -4
- package/scripts/tools/verify-doc-anchors.sh +14 -34
- package/scripts/tools/verify-graph-binary.sh +15 -5
- package/skills/GRAPH.md +21 -10
- package/skills/adr/SKILL.md +25 -7
- package/skills/assist-review/SKILL.md +2 -1
- package/skills/bughunt/SKILL.md +55 -12
- package/skills/bughunt/references/regression-tests.md +14 -4
- package/skills/change/SKILL.md +19 -9
- package/skills/coverage/SKILL.md +28 -12
- package/skills/debug/SKILL.md +13 -3
- package/skills/decompose/SKILL.md +42 -12
- package/skills/deep-review/SKILL.md +19 -6
- package/skills/deploy-checklist/SKILL.md +10 -3
- 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 +2 -2
- package/skills/impact/SKILL.md +4 -2
- package/skills/implement/SKILL.md +62 -20
- package/skills/incident-response/SKILL.md +5 -2
- package/skills/init/SKILL.md +112 -30
- package/skills/init/references/architecture-spec.md +32 -8
- package/skills/init/references/okf-emitter.md +42 -78
- package/skills/jira/SKILL.md +33 -13
- package/skills/jira/references/review.md +61 -19
- package/skills/learn/SKILL.md +30 -7
- package/skills/new-track/SKILL.md +73 -18
- package/skills/quick-review/SKILL.md +8 -3
- package/skills/revert/SKILL.md +11 -5
- package/skills/review/SKILL.md +126 -27
- package/skills/review/references/zero-setup-mode.md +117 -0
- package/skills/standup/SKILL.md +10 -2
- package/skills/status/SKILL.md +7 -7
- package/skills/tech-debt/SKILL.md +9 -3
- package/skills/testing-strategy/SKILL.md +10 -2
- package/skills/tour/SKILL.md +2 -1
- package/skills/upload/SKILL.md +4 -3
- package/core/templates/track-architecture.md +0 -311
|
@@ -66,7 +66,7 @@ EOF
|
|
|
66
66
|
|
|
67
67
|
while [[ $# -gt 0 ]]; do
|
|
68
68
|
case "$1" in
|
|
69
|
-
--path-index) PATH_INDEX="$2"; shift 2;;
|
|
69
|
+
--path-index) PATH_INDEX="${2:?--path-index requires a value}"; shift 2;;
|
|
70
70
|
--reverse) REVERSE=1; shift;;
|
|
71
71
|
--structure-only) STRUCTURE_ONLY=1; shift;;
|
|
72
72
|
--json) JSON=1; shift;;
|
|
@@ -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)
|
|
@@ -237,12 +248,14 @@ if [[ -n "$PATH_INDEX" ]]; then
|
|
|
237
248
|
# themselves end in .md (e.g. grounding to docs/INVARIANTS.md) — those are
|
|
238
249
|
# not bundle pages, so we extract strings *inside* the [ ... ] value arrays
|
|
239
250
|
# and ignore keys entirely. Each page must exist in the bundle.
|
|
251
|
+
# Flatten first: the index may be pretty-printed, so value arrays can
|
|
252
|
+
# span lines and a line-oriented match would silently skip them.
|
|
240
253
|
while IFS= read -r ref; do
|
|
241
254
|
[[ -z "$ref" ]] && continue
|
|
242
255
|
if [[ ! -f "$BUNDLE/$ref" ]]; then
|
|
243
256
|
add_error "path-index references missing concept page: $ref"
|
|
244
257
|
fi
|
|
245
|
-
done < <(
|
|
258
|
+
done < <(tr '\n' ' ' < "$PATH_INDEX" 2>/dev/null | grep -oE '\[[^]]*\]' \
|
|
246
259
|
| grep -oE '"[^"]+\.md"' | tr -d '"' | sort -u)
|
|
247
260
|
fi
|
|
248
261
|
fi
|
|
@@ -251,9 +264,10 @@ fi
|
|
|
251
264
|
# Forward proves the index doesn't name ghosts; reverse proves no page is an
|
|
252
265
|
# orphan with no source mapping (a symptom of hand-written / off-plan pages).
|
|
253
266
|
if [[ $REVERSE -eq 1 && $STRUCTURE_ONLY -eq 0 && -n "$PATH_INDEX" && -f "$PATH_INDEX" ]]; then
|
|
254
|
-
# All pages the index maps to (its array values).
|
|
267
|
+
# All pages the index maps to (its array values). Flattened for the same
|
|
268
|
+
# pretty-printed-array reason as the forward check above.
|
|
255
269
|
INDEXED_FILE="$(mktemp)"
|
|
256
|
-
|
|
270
|
+
tr '\n' ' ' < "$PATH_INDEX" 2>/dev/null | grep -oE '\[[^]]*\]' \
|
|
257
271
|
| grep -oE '"[^"]+\.md"' | tr -d '"' | sort -u > "$INDEXED_FILE" || true
|
|
258
272
|
while IFS= read -r -d '' page; do
|
|
259
273
|
rel="${page#"$BUNDLE/"}"
|
|
@@ -49,10 +49,10 @@ EOF
|
|
|
49
49
|
|
|
50
50
|
while [[ $# -gt 0 ]]; do
|
|
51
51
|
case "$1" in
|
|
52
|
-
--since) SINCE="$2"; shift 2;;
|
|
53
|
-
--limit) LIMIT="$2"; shift 2;;
|
|
54
|
-
--scope-pattern) SCOPE_PATTERN="$2"; shift 2;;
|
|
55
|
-
--branch) BRANCH="$2"; shift 2;;
|
|
52
|
+
--since) SINCE="${2:?--since requires a value}"; shift 2;;
|
|
53
|
+
--limit) LIMIT="${2:?--limit requires a value}"; shift 2;;
|
|
54
|
+
--scope-pattern) SCOPE_PATTERN="${2:?--scope-pattern requires a value}"; shift 2;;
|
|
55
|
+
--branch) BRANCH="${2:?--branch requires a value}"; shift 2;;
|
|
56
56
|
--help|-h) usage; exit 0;;
|
|
57
57
|
*) echo "Unknown flag: $1" >&2; usage >&2; exit 1;;
|
|
58
58
|
esac
|
|
@@ -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
|
|
@@ -48,7 +48,7 @@ TO_STDOUT=0
|
|
|
48
48
|
while (($#)); do
|
|
49
49
|
case "$1" in
|
|
50
50
|
-h|--help) USAGE_HELP_MODE=1 usage ;;
|
|
51
|
-
--out) OUT_PATH="$2"; shift 2 ;;
|
|
51
|
+
--out) OUT_PATH="${2:?--out requires a value}"; shift 2 ;;
|
|
52
52
|
--stdout) TO_STDOUT=1; shift ;;
|
|
53
53
|
-*) printf 'Unknown flag: %s\n' "$1" >&2; usage ;;
|
|
54
54
|
*) TRACK_DIR="$1"; shift ;;
|
|
@@ -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
|
}
|
|
@@ -51,7 +51,7 @@ EOF
|
|
|
51
51
|
|
|
52
52
|
while [[ $# -gt 0 ]]; do
|
|
53
53
|
case "$1" in
|
|
54
|
-
--path) COVERAGE_PATH="$2"; shift 2;;
|
|
54
|
+
--path) COVERAGE_PATH="${2:?--path requires a value}"; shift 2;;
|
|
55
55
|
--schema-check) SCHEMA_CHECK="true"; shift;;
|
|
56
56
|
--help|-h) usage; exit 0;;
|
|
57
57
|
-*) echo "Unknown flag: $1" >&2; usage >&2; exit 1;;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
#
|
|
7
7
|
# Usage:
|
|
8
8
|
# scripts/tools/scan-markers.sh [--root DIR] [--markers LIST]
|
|
9
|
-
# [--min-age-days N]
|
|
9
|
+
# [--min-age-days N]
|
|
10
10
|
#
|
|
11
11
|
# Exit codes: 0 OK (even with zero hits), 1 invocation error, 2 not a git repo
|
|
12
12
|
# (emits [] on stdout so consumers can still parse).
|
|
@@ -38,9 +38,9 @@ EOF
|
|
|
38
38
|
|
|
39
39
|
while [[ $# -gt 0 ]]; do
|
|
40
40
|
case "$1" in
|
|
41
|
-
--root) ROOT="$2"; shift 2;;
|
|
42
|
-
--markers) MARKERS="$2"; shift 2;;
|
|
43
|
-
--min-age-days) MIN_AGE="$2"; shift 2;;
|
|
41
|
+
--root) ROOT="${2:?--root requires a value}"; shift 2;;
|
|
42
|
+
--markers) MARKERS="${2:?--markers requires a value}"; shift 2;;
|
|
43
|
+
--min-age-days) MIN_AGE="${2:?--min-age-days requires a value}"; shift 2;;
|
|
44
44
|
--help|-h) usage; exit 0;;
|
|
45
45
|
*) echo "Unknown flag: $1" >&2; usage >&2; exit 1;;
|
|
46
46
|
esac
|
|
@@ -43,8 +43,8 @@ REQUIRED="name,description"
|
|
|
43
43
|
|
|
44
44
|
while [[ $# -gt 0 ]]; do
|
|
45
45
|
case "$1" in
|
|
46
|
-
--require) REQUIRED="$2"; shift 2;;
|
|
47
|
-
--mode) MODE="$2"; shift 2;;
|
|
46
|
+
--require) REQUIRED="${2:?--require requires a value}"; shift 2;;
|
|
47
|
+
--mode) MODE="${2:?--mode requires a value}"; shift 2;;
|
|
48
48
|
--help|-h) usage; exit 0;;
|
|
49
49
|
-*) echo "Unknown flag: $1" >&2; usage >&2; exit 1;;
|
|
50
50
|
*)
|
|
@@ -48,7 +48,7 @@ while (($#)); do
|
|
|
48
48
|
case "$1" in
|
|
49
49
|
-h|--help) USAGE_HELP_MODE=1 usage ;;
|
|
50
50
|
--json) EMIT_JSON=1; shift ;;
|
|
51
|
-
--tolerance) TOLERANCE="$2"; shift 2 ;;
|
|
51
|
+
--tolerance) TOLERANCE="${2:?--tolerance requires a value}"; shift 2 ;;
|
|
52
52
|
-*) printf 'Unknown flag: %s\n' "$1" >&2; usage ;;
|
|
53
53
|
*) TRACK_PATHS+=("$1"); shift ;;
|
|
54
54
|
esac
|
|
@@ -83,7 +83,7 @@ extract_citations() {
|
|
|
83
83
|
# bracket expression prematurely terminates a regex literal in
|
|
84
84
|
# POSIX/BSD awk ("nonterminated character class"), though gawk is
|
|
85
85
|
# lenient. The string form is portable across awk implementations.
|
|
86
|
-
while (match(s, "[A-Za-z0-9_][A-Za-z0-9_./-]*\\.[A-Za-z0-9]+:[0-9]+")) {
|
|
86
|
+
while (match(s, "[A-Za-z0-9_][A-Za-z0-9_./-]*\\.[A-Za-z0-9]+:[0-9]+(-[0-9]+)?")) {
|
|
87
87
|
cite = substr(s, RSTART, RLENGTH)
|
|
88
88
|
printf("%s\t%d\t%s\n", FILENAME, NR, cite)
|
|
89
89
|
s = substr(s, RSTART + RLENGTH)
|
|
@@ -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
|
|
@@ -150,7 +130,7 @@ scan_md() {
|
|
|
150
130
|
# token the `(planned)` annotation owns.
|
|
151
131
|
if echo "$line" | grep -qE '\(planned\)|\[New file'; then
|
|
152
132
|
local paths
|
|
153
|
-
paths="$(echo "$line" | grep -oE '[A-Za-z][A-Za-z0-9_./-]*\.[A-Za-z]+' | sort -u)"
|
|
133
|
+
paths="$(echo "$line" | grep -oE '[A-Za-z][A-Za-z0-9_./-]*\.[A-Za-z]+' | sort -u || true)"
|
|
154
134
|
local path_count
|
|
155
135
|
path_count="$(printf '%s\n' "$paths" | grep -c . || true)"
|
|
156
136
|
if (( path_count == 1 )); then
|
|
@@ -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 .)
|
|
@@ -51,8 +53,8 @@ EOF
|
|
|
51
53
|
|
|
52
54
|
while [[ $# -gt 0 ]]; do
|
|
53
55
|
case "$1" in
|
|
54
|
-
--repo) REPO="$2"; shift 2 ;;
|
|
55
|
-
--plugin-root) PLUGIN_ROOT="$2"; shift 2 ;;
|
|
56
|
+
--repo) REPO="${2:?--repo requires a value}"; shift 2 ;;
|
|
57
|
+
--plugin-root) PLUGIN_ROOT="${2:?--plugin-root requires a value}"; shift 2 ;;
|
|
56
58
|
--json) EMIT_JSON=1; shift ;;
|
|
57
59
|
--verbose) VERBOSE=1; shift ;;
|
|
58
60
|
--strict) STRICT=1; shift ;;
|
|
@@ -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 │
|