@drafthq/draft 3.2.0 → 3.3.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.
Files changed (56) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.cursor-plugin/plugin.json +28 -0
  4. package/README.md +2 -2
  5. package/cli/src/hosts/cursor.js +35 -5
  6. package/cli/src/installer.js +20 -0
  7. package/cli/src/lib/cursor-registry.js +122 -0
  8. package/cli/src/lib/marker.js +93 -0
  9. package/cli/src/lib/plugin-manifest.js +20 -0
  10. package/core/methodology.md +1 -1
  11. package/core/shared/condensation.md +3 -2
  12. package/core/shared/git-report-metadata.md +3 -2
  13. package/core/shared/graph-query.md +4 -3
  14. package/core/shared/tool-resolver.md +71 -4
  15. package/core/templates/okf/ai-context-index.md +48 -0
  16. package/core/templates/okf/concept.md +54 -0
  17. package/core/templates/okf/index.md +40 -0
  18. package/core/templates/okf/section-index.md +25 -0
  19. package/core/templates/plan.md +3 -2
  20. package/integrations/agents/AGENTS.md +792 -102
  21. package/integrations/copilot/.github/copilot-instructions.md +792 -102
  22. package/package.json +3 -2
  23. package/scripts/lib.sh +10 -0
  24. package/scripts/tools/graph-preflight.sh +259 -0
  25. package/scripts/tools/okf-render-views.sh +373 -0
  26. package/scripts/tools/okf-validate.sh +204 -0
  27. package/scripts/tools/resolve-tools.sh +78 -0
  28. package/skills/adr/SKILL.md +3 -2
  29. package/skills/bughunt/SKILL.md +10 -1
  30. package/skills/coverage/SKILL.md +8 -3
  31. package/skills/debug/SKILL.md +16 -5
  32. package/skills/decompose/SKILL.md +29 -12
  33. package/skills/deep-review/SKILL.md +19 -6
  34. package/skills/deploy-checklist/SKILL.md +6 -5
  35. package/skills/graph/SKILL.md +15 -6
  36. package/skills/impact/SKILL.md +12 -1
  37. package/skills/implement/SKILL.md +20 -4
  38. package/skills/init/SKILL.md +36 -10
  39. package/skills/init/references/architecture-spec.md +17 -6
  40. package/skills/init/references/okf-emitter.md +223 -0
  41. package/skills/learn/SKILL.md +15 -4
  42. package/skills/quick-review/SKILL.md +13 -3
  43. package/skills/review/SKILL.md +32 -8
  44. package/skills/standup/SKILL.md +3 -2
  45. package/skills/status/SKILL.md +3 -2
  46. package/skills/tech-debt/SKILL.md +20 -6
  47. package/skills/upload/SKILL.md +3 -2
  48. package/integrations/copilot/.github/copilot-instructions.md.7iDz8X +0 -91
  49. package/integrations/copilot/.github/copilot-instructions.md.DoBdtd +0 -91
  50. package/integrations/copilot/.github/copilot-instructions.md.McGoBW +0 -122
  51. package/integrations/copilot/.github/copilot-instructions.md.VsPyLB +0 -91
  52. package/integrations/copilot/.github/copilot-instructions.md.XAVr7D +0 -91
  53. package/integrations/copilot/.github/copilot-instructions.md.YoFVFa +0 -91
  54. package/integrations/copilot/.github/copilot-instructions.md.a9DeW0 +0 -91
  55. package/integrations/copilot/.github/copilot-instructions.md.oxQs3B +0 -91
  56. package/integrations/copilot/.github/copilot-instructions.md.ww33Ly +0 -91
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drafthq/draft",
3
- "version": "3.2.0",
3
+ "version": "3.3.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"
@@ -14,6 +14,7 @@
14
14
  "skills/",
15
15
  "core/",
16
16
  ".claude-plugin/",
17
+ ".cursor-plugin/",
17
18
  "integrations/",
18
19
  "bin/",
19
20
  "scripts/tools/",
@@ -24,7 +25,7 @@
24
25
  ],
25
26
  "scripts": {
26
27
  "test": "bash tests/test-cli.sh",
27
- "version": "bash scripts/sync-version.sh && git add .claude-plugin/plugin.json .claude-plugin/marketplace.json web/index.html",
28
+ "version": "bash scripts/sync-version.sh && git add .claude-plugin/plugin.json .claude-plugin/marketplace.json .cursor-plugin/plugin.json",
28
29
  "prepublishOnly": "bash scripts/build-integrations.sh"
29
30
  },
30
31
  "repository": {
package/scripts/lib.sh CHANGED
@@ -114,6 +114,11 @@ CORE_FILES=(
114
114
  "templates/discovery.md"
115
115
  "templates/hld.md"
116
116
  "templates/lld.md"
117
+ # OKF taxonomy bundle templates (DRAFT_INIT_MODE=okf)
118
+ "templates/okf/index.md"
119
+ "templates/okf/concept.md"
120
+ "templates/okf/section-index.md"
121
+ "templates/okf/ai-context-index.md"
117
122
  # Agents
118
123
  "agents/architect.md"
119
124
  "agents/debugger.md"
@@ -158,6 +163,7 @@ TOOLS=(
158
163
  "mermaid-from-graph.sh"
159
164
  "graph-snapshot.sh"
160
165
  "graph-init.sh"
166
+ "graph-preflight.sh"
161
167
  "graph-impact.sh"
162
168
  "graph-callers.sh"
163
169
  "graph-arch.sh"
@@ -186,6 +192,10 @@ TOOLS=(
186
192
  "verify-citations.sh"
187
193
  "verify-doc-anchors.sh"
188
194
  "verify-graph-binary.sh"
195
+ "resolve-tools.sh"
196
+ # OKF taxonomy emitter (DRAFT_INIT_MODE=okf)
197
+ "okf-validate.sh"
198
+ "okf-render-views.sh"
189
199
  )
190
200
 
191
201
  # ─────────────────────────────────────────────────────────
@@ -0,0 +1,259 @@
1
+ #!/usr/bin/env bash
2
+ # graph-preflight.sh — read-only go/no-go check before indexing a repo with the
3
+ # Draft knowledge-graph engine (codebase-memory-mcp).
4
+ #
5
+ # Indexes NOTHING. Walks git metadata + engine status only. Safe to run anywhere.
6
+ # Companion preflight for `scripts/tools/graph-init.sh` / `/draft:init --graph-only`.
7
+ #
8
+ # Usage: scripts/tools/graph-preflight.sh [--json] [REPO_PATH] (default repo: cwd)
9
+ # --json emit a machine-readable report on stdout (no human output)
10
+ # Exit: 0 = GO / GO-with-caution, 1 = NO-GO (blocking), 2 = bad invocation.
11
+ #
12
+ # Deliberately uses guard idioms (`|| true`, `|| echo 0`) rather than aborting:
13
+ # the report accumulates blockers/warnings and prints a verdict even under -e.
14
+ set -euo pipefail
15
+
16
+ TOOLS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
17
+ SELF_REPO="$(cd "$TOOLS_DIR/../.." && pwd)"
18
+ # shellcheck source=_lib.sh
19
+ source "$TOOLS_DIR/_lib.sh"
20
+
21
+ usage() {
22
+ cat <<'EOF'
23
+ graph-preflight.sh — read-only go/no-go check before knowledge-graph indexing.
24
+
25
+ Usage:
26
+ scripts/tools/graph-preflight.sh [--json] [REPO_PATH] (default repo: cwd)
27
+
28
+ Flags:
29
+ --json Emit a machine-readable report on stdout (no human output).
30
+ --help Show this help.
31
+
32
+ Indexes nothing — walks git metadata + engine status only.
33
+ Exit codes: 0 GO / GO-with-caution, 1 NO-GO (blocking), 2 bad invocation.
34
+ EOF
35
+ }
36
+
37
+ # --- args ---
38
+ JSON_MODE=0
39
+ REPO=""
40
+ while [[ $# -gt 0 ]]; do
41
+ case "$1" in
42
+ --json) JSON_MODE=1; shift;;
43
+ -h|--help) usage; exit 0;;
44
+ -*) echo "Unknown flag: $1" >&2; usage >&2; exit 2;;
45
+ *) if [[ -z "$REPO" ]]; then REPO="$1"; else echo "Unexpected arg: $1" >&2; exit 2; fi; shift;;
46
+ esac
47
+ done
48
+ REPO="${REPO:-.}"
49
+ [[ -d "$REPO" ]] || { echo "ERROR: '$REPO' is not a directory" >&2; exit 2; }
50
+ REPO_ABS="$(cd "$REPO" && pwd)"
51
+
52
+ # --- formatting (color only on a tty, and never in --json) ---
53
+ if [[ -t 1 && "$JSON_MODE" -eq 0 ]]; then B=$'\e[1m'; G=$'\e[32m'; Y=$'\e[33m'; R=$'\e[31m'; D=$'\e[0m'; else B=""; G=""; Y=""; R=""; D=""; fi
54
+ hr() { [[ "$JSON_MODE" -eq 0 ]] && printf '%s\n' "------------------------------------------------------------"; return 0; }
55
+ sec() { [[ "$JSON_MODE" -eq 0 ]] && { echo; printf '%s== %s ==%s\n' "$B" "$1" "$D"; }; return 0; }
56
+ ok() { [[ "$JSON_MODE" -eq 0 ]] && printf ' %s[ OK ]%s %s\n' "$G" "$D" "$1"; return 0; }
57
+ info() { [[ "$JSON_MODE" -eq 0 ]] && printf ' %s\n' "$1"; return 0; }
58
+ warn() { WARNINGS=$((WARNINGS+1)); WARN_J="${WARN_J:+$WARN_J,}\"$(json_escape "$1")\""; [[ "$JSON_MODE" -eq 0 ]] && printf ' %s[WARN]%s %s\n' "$Y" "$D" "$1"; return 0; }
59
+ fail() { BLOCKERS=$((BLOCKERS+1)); FAIL_J="${FAIL_J:+$FAIL_J,}\"$(json_escape "$1")\""; [[ "$JSON_MODE" -eq 0 ]] && printf ' %s[FAIL]%s %s\n' "$R" "$D" "$1"; return 0; }
60
+
61
+ WARNINGS=0; BLOCKERS=0; WARN_J=""; FAIL_J=""
62
+
63
+ # --- helpers ---
64
+ count_files() { { git -C "$REPO_ABS" ls-files -- "$@" 2>/dev/null || true; } | wc -l | tr -d ' '; }
65
+ count_loc() {
66
+ [[ -n "$(git -C "$REPO_ABS" ls-files -- "$@" 2>/dev/null | head -1)" ]] || { echo 0; return; }
67
+ # cat must run from the repo root so tracked paths resolve.
68
+ ( cd "$REPO_ABS" && git ls-files -z -- "$@" 2>/dev/null | xargs -0 cat 2>/dev/null ) | wc -l | tr -d ' ' || true
69
+ }
70
+ human() { awk -v n="$1" 'BEGIN{ v=n; split("K M B",u); if(v<1000){printf "%d",v;exit}
71
+ for(i=1;i<=3;i++){v/=1000; if(v<1000){printf "%.1f%s",v,u[i];exit}}}'; }
72
+
73
+ # --- collected fields (defaults so --json is always well-formed) ---
74
+ IS_GIT=false; AT_ROOT=false; GIT_TOP=""; COMMIT="none"
75
+ TRACKED=0; ALLDISK=0; TOTAL_LOC=0; CCGO_LOC=0; LANG_J=""
76
+ VEND_J=""; ENGINE=""; VER=""; LIMIT=""; ENGINE_FOUND=false
77
+ RAM_GB=""; FREE_GB=""
78
+
79
+ hr
80
+ [[ "$JSON_MODE" -eq 0 ]] && printf '%sDraft graph pre-flight%s — %s\n' "$B" "$D" "$REPO_ABS" || true
81
+ hr
82
+
83
+ # ============================================================
84
+ sec "1. Git boundary"
85
+ # ============================================================
86
+ GIT_TOP="$(git -C "$REPO_ABS" rev-parse --show-toplevel 2>/dev/null || true)"
87
+ if [[ -z "$GIT_TOP" ]]; then
88
+ fail "Not inside a git repo. The engine would raw-walk the filesystem (no .gitignore filter)."
89
+ info "Point this at a real git repo root, never a parent container dir."
90
+ GIT_OK=0
91
+ else
92
+ GIT_OK=1; IS_GIT=true
93
+ if [[ "$GIT_TOP" != "$REPO_ABS" ]]; then
94
+ warn "Not at the git root. Git top is: $GIT_TOP"
95
+ info "Run /draft:init --graph-only at the git root for whole-repo coverage."
96
+ else
97
+ AT_ROOT=true
98
+ ok "Git root: $GIT_TOP"
99
+ fi
100
+ COMMIT="$(git -C "$REPO_ABS" rev-parse --short HEAD 2>/dev/null || echo none)"
101
+ info "HEAD: $COMMIT"
102
+ [[ -f "$GIT_TOP/.gitmodules" ]] && warn "Submodules present — engine indexes the superproject's tracked tree; submodule contents may need separate indexing." || true
103
+ fi
104
+
105
+ # ============================================================
106
+ sec "2. Index scope (git-tracked = what actually gets indexed)"
107
+ # ============================================================
108
+ if [[ "$GIT_OK" -eq 1 ]]; then
109
+ TRACKED="$(count_files)"
110
+ ALLDISK="$({ find "$REPO_ABS" -type d -name .git -prune -o -type f -print 2>/dev/null || true; } | wc -l | tr -d ' ')"
111
+ ok "Git-tracked files: $TRACKED (on disk: $ALLDISK — the difference is gitignored and SKIPPED)"
112
+
113
+ [[ "$JSON_MODE" -eq 0 ]] && { echo; printf ' %-14s %10s %12s\n' "language" "files" "lines"; printf ' %-14s %10s %12s\n' "--------" "-----" "-----"; } || true
114
+ declare -A GLOBS=(
115
+ [C/C++]='*.c *.cc *.cpp *.cxx *.h *.hpp *.hh *.hxx'
116
+ [Go]='*.go'
117
+ [Python]='*.py'
118
+ [TS/JS]='*.ts *.tsx *.js *.jsx *.mjs'
119
+ [Rust]='*.rs'
120
+ [Java]='*.java'
121
+ )
122
+ for lang in "C/C++" Go Python TS/JS Rust Java; do
123
+ # shellcheck disable=SC2086
124
+ read -ra g <<< "${GLOBS[$lang]}"
125
+ f="$(count_files "${g[@]}")"
126
+ [[ "$f" -eq 0 ]] && continue
127
+ l="$(count_loc "${g[@]}")"
128
+ [[ "$JSON_MODE" -eq 0 ]] && printf ' %-14s %10s %12s\n' "$lang" "$f" "$l" || true
129
+ LANG_J="${LANG_J:+$LANG_J,}{\"lang\":\"$(json_escape "$lang")\",\"files\":$f,\"lines\":$l}"
130
+ TOTAL_LOC=$((TOTAL_LOC + l))
131
+ [[ "$lang" == "C/C++" || "$lang" == "Go" ]] && CCGO_LOC=$((CCGO_LOC + l)) || true
132
+ done
133
+ [[ "$JSON_MODE" -eq 0 ]] && printf ' %-14s %10s %12s\n' "TOTAL" "$TRACKED" "$TOTAL_LOC" || true
134
+ info "Source LOC total: $(human "$TOTAL_LOC") | C/C++/Go: $(human "$CCGO_LOC")"
135
+ else
136
+ warn "Skipped — no git repo."
137
+ fi
138
+
139
+ # ============================================================
140
+ sec "3. Committed vendor/generated trees (these WILL be indexed)"
141
+ # ============================================================
142
+ if [[ "$GIT_OK" -eq 1 ]]; then
143
+ # Match vendor/generated *directories* (token followed by /) and protobuf-generated
144
+ # file suffixes — not filenames that merely contain "gen"/"generate".
145
+ VEND="$(git -C "$REPO_ABS" ls-files 2>/dev/null \
146
+ | grep -iE '(^|/)(third_party|thirdparty|vendor|external|deps|generated)/|\.pb\.(cc|h|go)$|_pb2\.py$' \
147
+ | sed -E 's#(^.*/(third_party|thirdparty|vendor|external|deps|generated))/.*#\1/#' \
148
+ | sort -u | head -40 || true)"
149
+ if [[ -n "$VEND" ]]; then
150
+ warn "Committed vendor/generated paths found — gitignore to exclude, or accept index inflation:"
151
+ while IFS= read -r p; do
152
+ [[ -z "$p" ]] && continue
153
+ info "$p"
154
+ VEND_J="${VEND_J:+$VEND_J,}\"$(json_escape "$p")\""
155
+ done <<< "$VEND"
156
+ else
157
+ ok "No obvious committed vendor/generated trees."
158
+ fi
159
+ else
160
+ warn "Skipped — no git repo."
161
+ fi
162
+
163
+ # ============================================================
164
+ sec "4. Engine availability"
165
+ # ============================================================
166
+ if find_memory_bin "$REPO_ABS" "$SELF_REPO"; then
167
+ ENGINE="$MEMORY_BIN"
168
+ ENGINE_FOUND=true
169
+ VER="$("$ENGINE" --version 2>/dev/null | head -1 || echo '?')"
170
+ ok "Engine: $ENGINE ($VER)"
171
+ LIMIT="$("$ENGINE" config list 2>/dev/null | awk '/auto_index_limit/{print $3}' || true)"
172
+ [[ -n "$LIMIT" ]] && info "auto_index_limit: $LIMIT (governs AUTO-index only; explicit index_repository should bypass)" || true
173
+ if [[ "$GIT_OK" -eq 1 && -n "${LIMIT:-}" && "$TRACKED" -gt "$LIMIT" ]]; then
174
+ warn "Tracked files ($TRACKED) > auto_index_limit ($LIMIT) — confirm the explicit index isn't truncated near $LIMIT."
175
+ fi
176
+ else
177
+ ENGINE=""
178
+ fail "Engine 'codebase-memory-mcp' not found (checked \$DRAFT_MEMORY_BIN, PATH, ~/.cache/draft/bin/, vendored bin/<arch>/)."
179
+ info "Install: scripts/fetch-memory-engine.sh (or put the binary on PATH)"
180
+ fi
181
+
182
+ # ============================================================
183
+ sec "5. Machine headroom"
184
+ # ============================================================
185
+ if [[ -r /proc/meminfo ]]; then
186
+ RAM_GB="$(awk '/MemTotal/{printf "%d", $2/1024/1024}' /proc/meminfo)"
187
+ ok "Total RAM: ${RAM_GB} GB (engine self-budgets ~half)"
188
+ elif command -v sysctl >/dev/null 2>&1; then
189
+ RAM_GB="$(( $(sysctl -n hw.memsize 2>/dev/null || echo 0) / 1024 / 1024 / 1024 ))"
190
+ ok "Total RAM: ${RAM_GB} GB"
191
+ else
192
+ warn "Could not read total RAM."
193
+ fi
194
+ CACHE_DIR="$HOME/.cache"; mkdir -p "$CACHE_DIR" 2>/dev/null || true
195
+ FREE_K="$(df -Pk "$CACHE_DIR" 2>/dev/null | awk 'NR==2{print $4}' || true)"
196
+ if [[ -n "${FREE_K:-}" ]]; then
197
+ FREE_GB=$((FREE_K / 1024 / 1024))
198
+ if [[ "$FREE_GB" -lt 10 ]]; then warn "$CACHE_DIR free: ${FREE_GB} GB (low — index lives here)"; else ok "$CACHE_DIR free: ${FREE_GB} GB"; fi
199
+ fi
200
+
201
+ # ============================================================
202
+ # Scale heuristic for first-pass time expectation.
203
+ if [[ "$CCGO_LOC" -ge 5000000 || "$TOTAL_LOC" -ge 5000000 ]]; then
204
+ warn "Large codebase ($(human "$TOTAL_LOC") LOC) — expect a long first-pass index (likely hours). Run backgrounded; incremental thereafter."
205
+ fi
206
+
207
+ # --- verdict ---
208
+ if [[ "$BLOCKERS" -gt 0 ]]; then VERDICT="NO_GO"; VEXIT=1
209
+ elif [[ "$WARNINGS" -gt 0 ]]; then VERDICT="GO_WITH_CAUTION"; VEXIT=0
210
+ else VERDICT="GO"; VEXIT=0
211
+ fi
212
+
213
+ # ============================================================
214
+ # Output
215
+ # ============================================================
216
+ if [[ "$JSON_MODE" -eq 1 ]]; then
217
+ printf '{\n'
218
+ printf ' "repo": "%s",\n' "$(json_escape "$REPO_ABS")"
219
+ printf ' "is_git_repo": %s,\n' "$IS_GIT"
220
+ printf ' "git_root": %s,\n' "$([[ -n "$GIT_TOP" ]] && printf '"%s"' "$(json_escape "$GIT_TOP")" || printf 'null')"
221
+ printf ' "at_git_root": %s,\n' "$AT_ROOT"
222
+ printf ' "head": "%s",\n' "$(json_escape "$COMMIT")"
223
+ printf ' "tracked_files": %s,\n' "$TRACKED"
224
+ printf ' "files_on_disk": %s,\n' "$ALLDISK"
225
+ printf ' "languages": [%s],\n' "$LANG_J"
226
+ printf ' "total_source_loc": %s,\n' "$TOTAL_LOC"
227
+ printf ' "ccgo_loc": %s,\n' "$CCGO_LOC"
228
+ printf ' "committed_vendor_paths": [%s],\n' "$VEND_J"
229
+ printf ' "engine": {"found": %s, "path": %s, "version": %s, "auto_index_limit": %s},\n' \
230
+ "$ENGINE_FOUND" \
231
+ "$([[ -n "$ENGINE" ]] && printf '"%s"' "$(json_escape "$ENGINE")" || printf 'null')" \
232
+ "$([[ -n "$VER" ]] && printf '"%s"' "$(json_escape "$VER")" || printf 'null')" \
233
+ "${LIMIT:-null}"
234
+ printf ' "machine": {"ram_gb": %s, "cache_free_gb": %s},\n' "${RAM_GB:-null}" "${FREE_GB:-null}"
235
+ printf ' "warnings": [%s],\n' "$WARN_J"
236
+ printf ' "blockers": [%s],\n' "$FAIL_J"
237
+ printf ' "verdict": "%s",\n' "$VERDICT"
238
+ printf ' "exit_code": %s\n' "$VEXIT"
239
+ printf '}\n'
240
+ exit "$VEXIT"
241
+ fi
242
+
243
+ sec "Verdict"
244
+ echo
245
+ case "$VERDICT" in
246
+ NO_GO) printf '%s NO-GO %s — %d blocker(s), %d warning(s). Resolve blockers above first.\n' "$R" "$D" "$BLOCKERS" "$WARNINGS";;
247
+ GO_WITH_CAUTION) printf '%s GO (with caution) %s — %d warning(s). Review them, then proceed.\n' "$Y" "$D" "$WARNINGS";;
248
+ GO) printf '%s GO %s — clear to index.\n' "$G" "$D";;
249
+ esac
250
+
251
+ cat <<EOF
252
+
253
+ Next step (when ready, from the git root):
254
+ scripts/tools/graph-init.sh --scope . --json & # or: /draft:init --graph-only
255
+ ${ENGINE:-codebase-memory-mcp} cli list_projects '{}'
256
+ ${ENGINE:-codebase-memory-mcp} cli index_status '{"project":"<name>"}'
257
+ EOF
258
+ hr
259
+ exit "$VEXIT"