@drafthq/draft 2.7.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 +38 -0
- package/.claude-plugin/plugin.json +26 -0
- package/LICENSE +21 -0
- package/README.md +272 -0
- package/bin/README.md +49 -0
- package/cli/bin/draft.js +13 -0
- package/cli/src/cli.js +113 -0
- package/cli/src/hosts/claude-code.js +46 -0
- package/cli/src/hosts/codex.js +33 -0
- package/cli/src/hosts/cursor.js +50 -0
- package/cli/src/hosts/index.js +24 -0
- package/cli/src/hosts/opencode.js +39 -0
- package/cli/src/installer.js +61 -0
- package/cli/src/lib/fsx.js +34 -0
- package/cli/src/lib/graph.js +23 -0
- package/cli/src/lib/log.js +32 -0
- package/cli/src/lib/paths.js +14 -0
- package/core/agents/architect.md +338 -0
- package/core/agents/debugger.md +193 -0
- package/core/agents/ops.md +104 -0
- package/core/agents/planner.md +158 -0
- package/core/agents/rca.md +314 -0
- package/core/agents/reviewer.md +256 -0
- package/core/agents/writer.md +110 -0
- package/core/guardrails/README.md +4 -0
- package/core/guardrails/code-quality.md +4 -0
- package/core/guardrails/dependency-triage.md +4 -0
- package/core/guardrails/design-norms.md +4 -0
- package/core/guardrails/language-standards.md +4 -0
- package/core/guardrails/review-checks.md +4 -0
- package/core/guardrails/secure-patterns.md +4 -0
- package/core/guardrails/security.md +4 -0
- package/core/guardrails.md +22 -0
- package/core/knowledge-base.md +127 -0
- package/core/methodology.md +1221 -0
- package/core/shared/condensation.md +224 -0
- package/core/shared/context-verify.md +44 -0
- package/core/shared/cross-skill-dispatch.md +127 -0
- package/core/shared/discovery-schema.md +75 -0
- package/core/shared/draft-context-loading.md +282 -0
- package/core/shared/git-report-metadata.md +106 -0
- package/core/shared/graph-query.md +239 -0
- package/core/shared/graph-usage-report.md +22 -0
- package/core/shared/jira-sync.md +170 -0
- package/core/shared/parallel-analysis.md +386 -0
- package/core/shared/parallel-fanout.md +10 -0
- package/core/shared/pattern-learning.md +146 -0
- package/core/shared/red-flags.md +58 -0
- package/core/shared/template-contract.md +22 -0
- package/core/shared/template-hygiene.md +10 -0
- package/core/shared/tool-resolver.md +10 -0
- package/core/shared/vcs-commands.md +97 -0
- package/core/shared/verification-gates.md +47 -0
- package/core/templates/CHANGELOG.md +70 -0
- package/core/templates/ai-context-export.md +8 -0
- package/core/templates/ai-context.md +270 -0
- package/core/templates/ai-profile.md +41 -0
- package/core/templates/architecture.md +203 -0
- package/core/templates/dependency-graph.md +103 -0
- package/core/templates/discovery.md +79 -0
- package/core/templates/guardrails.md +143 -0
- package/core/templates/hld.md +327 -0
- package/core/templates/intake-questions.md +403 -0
- package/core/templates/jira.md +119 -0
- package/core/templates/lld.md +283 -0
- package/core/templates/metadata.json +66 -0
- package/core/templates/plan.md +130 -0
- package/core/templates/product.md +110 -0
- package/core/templates/rca.md +86 -0
- package/core/templates/root-architecture.md +127 -0
- package/core/templates/root-product.md +53 -0
- package/core/templates/root-tech-stack.md +117 -0
- package/core/templates/service-index.md +55 -0
- package/core/templates/session-summary.md +8 -0
- package/core/templates/spec.md +165 -0
- package/core/templates/tech-matrix.md +101 -0
- package/core/templates/tech-stack.md +169 -0
- package/core/templates/track-architecture.md +311 -0
- package/core/templates/workflow.md +187 -0
- package/integrations/agents/AGENTS.md +24384 -0
- package/integrations/copilot/.github/copilot-instructions.md +24384 -0
- package/integrations/gemini/.gemini.md +26 -0
- package/package.json +53 -0
- package/scripts/fetch-memory-engine.sh +116 -0
- package/scripts/lib.sh +256 -0
- package/scripts/tools/_lib.sh +220 -0
- package/scripts/tools/adr-index.sh +117 -0
- package/scripts/tools/check-graph-usage-report.sh +95 -0
- package/scripts/tools/check-scope-conflicts.sh +139 -0
- package/scripts/tools/check-skill-line-caps.sh +115 -0
- package/scripts/tools/check-template-noop.sh +87 -0
- package/scripts/tools/check-track-hygiene.sh +230 -0
- package/scripts/tools/classify-files.sh +231 -0
- package/scripts/tools/cycle-detect.sh +75 -0
- package/scripts/tools/detect-test-framework.sh +135 -0
- package/scripts/tools/diff-templates-vs-tracks.sh +176 -0
- package/scripts/tools/emit-skill-metrics.sh +71 -0
- package/scripts/tools/fix-whitespace.sh +192 -0
- package/scripts/tools/freshness-check.sh +143 -0
- package/scripts/tools/git-metadata.sh +203 -0
- package/scripts/tools/graph-callers.sh +74 -0
- package/scripts/tools/graph-impact.sh +93 -0
- package/scripts/tools/graph-snapshot.sh +102 -0
- package/scripts/tools/hotspot-rank.sh +75 -0
- package/scripts/tools/manage-symlinks.sh +85 -0
- package/scripts/tools/mermaid-from-graph.sh +92 -0
- package/scripts/tools/migrate-track-frontmatter.sh +241 -0
- package/scripts/tools/parse-git-log.sh +135 -0
- package/scripts/tools/parse-reports.sh +114 -0
- package/scripts/tools/render-track.sh +145 -0
- package/scripts/tools/run-coverage.sh +153 -0
- package/scripts/tools/scan-markers.sh +144 -0
- package/scripts/tools/skill-caps.conf +24 -0
- package/scripts/tools/validate-frontmatter.sh +125 -0
- package/scripts/tools/verify-citations.sh +250 -0
- package/scripts/tools/verify-doc-anchors.sh +204 -0
- package/scripts/tools/verify-graph-binary.sh +154 -0
- package/skills/GRAPH.md +332 -0
- package/skills/adr/SKILL.md +374 -0
- package/skills/assist-review/SKILL.md +49 -0
- package/skills/bughunt/SKILL.md +668 -0
- package/skills/bughunt/references/regression-tests.md +399 -0
- package/skills/change/SKILL.md +267 -0
- package/skills/coverage/SKILL.md +336 -0
- package/skills/debug/SKILL.md +201 -0
- package/skills/decompose/SKILL.md +656 -0
- package/skills/deep-review/SKILL.md +326 -0
- package/skills/deploy-checklist/SKILL.md +254 -0
- package/skills/discover/SKILL.md +66 -0
- package/skills/docs/SKILL.md +42 -0
- package/skills/documentation/SKILL.md +197 -0
- package/skills/draft/SKILL.md +177 -0
- package/skills/draft/context-files.md +57 -0
- package/skills/draft/intent-mapping.md +37 -0
- package/skills/draft/quality-guide.md +51 -0
- package/skills/graph/SKILL.md +107 -0
- package/skills/impact/SKILL.md +86 -0
- package/skills/implement/SKILL.md +794 -0
- package/skills/incident-response/SKILL.md +245 -0
- package/skills/index/SKILL.md +848 -0
- package/skills/init/SKILL.md +1784 -0
- package/skills/init/references/architecture-spec.md +1259 -0
- package/skills/integrations/SKILL.md +53 -0
- package/skills/jira/SKILL.md +577 -0
- package/skills/jira/references/review.md +1322 -0
- package/skills/learn/SKILL.md +478 -0
- package/skills/new-track/SKILL.md +841 -0
- package/skills/ops/SKILL.md +57 -0
- package/skills/plan/SKILL.md +60 -0
- package/skills/quick-review/SKILL.md +216 -0
- package/skills/revert/SKILL.md +178 -0
- package/skills/review/SKILL.md +1114 -0
- package/skills/standup/SKILL.md +183 -0
- package/skills/status/SKILL.md +183 -0
- package/skills/tech-debt/SKILL.md +318 -0
- package/skills/testing-strategy/SKILL.md +195 -0
- package/skills/tour/SKILL.md +38 -0
- package/skills/upload/SKILL.md +117 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Draft Methodology - Global Instructions
|
|
2
|
+
|
|
3
|
+
You are equipped with the **Draft Methodology** for Context-Driven Development.
|
|
4
|
+
|
|
5
|
+
**Core Principles:**
|
|
6
|
+
- **Measure twice, code once.**
|
|
7
|
+
- **Context -> Spec & Plan -> Implement.**
|
|
8
|
+
- Never implement without a plan.
|
|
9
|
+
- Never plan without a specification.
|
|
10
|
+
- Never specify without codebase context.
|
|
11
|
+
|
|
12
|
+
**Skill Locations:**
|
|
13
|
+
The authoritative Draft implementation skills are located at:
|
|
14
|
+
`~/.gemini/antigravity/skills/draft/skills`
|
|
15
|
+
|
|
16
|
+
**Automatic Workflow:**
|
|
17
|
+
1. If the current directory does NOT have a `draft/` folder, recommend running `draft-init` (alias) or `@draft init`.
|
|
18
|
+
2. Follow the protocols in `~/.gemini/antigravity/skills/draft/skills/<command>/SKILL.md` for all `@draft` commands.
|
|
19
|
+
3. Use the standard markers: `[ ]` (Pending), `[~]` (In Progress), `[x]` (Completed), `[!]` (Blocked).
|
|
20
|
+
|
|
21
|
+
**Project Context:**
|
|
22
|
+
Always prioritize information in:
|
|
23
|
+
- `draft/.ai-context.md` (Dense AI context)
|
|
24
|
+
- `draft/architecture.md` (Human-readable guide)
|
|
25
|
+
- `draft/product.md` (Vision)
|
|
26
|
+
- `draft/tech-stack.md` (Constraints)
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@drafthq/draft",
|
|
3
|
+
"version": "2.7.0",
|
|
4
|
+
"description": "Context-Driven Development for AI coding agents — install Draft into Claude Code, Cursor, Codex, or opencode.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"draft": "cli/bin/draft.js"
|
|
7
|
+
},
|
|
8
|
+
"type": "commonjs",
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=18"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"cli/",
|
|
14
|
+
"skills/",
|
|
15
|
+
"core/",
|
|
16
|
+
".claude-plugin/",
|
|
17
|
+
"integrations/",
|
|
18
|
+
"bin/",
|
|
19
|
+
"scripts/tools/",
|
|
20
|
+
"scripts/fetch-memory-engine.sh",
|
|
21
|
+
"scripts/lib.sh",
|
|
22
|
+
"LICENSE",
|
|
23
|
+
"README.md"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"test": "bash tests/test-cli.sh",
|
|
27
|
+
"prepublishOnly": "bash scripts/build-integrations.sh"
|
|
28
|
+
},
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/drafthq/draft.git"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://github.com/drafthq/draft",
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/drafthq/draft/issues"
|
|
36
|
+
},
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"author": "mayurpise",
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"keywords": [
|
|
43
|
+
"claude-code",
|
|
44
|
+
"cursor",
|
|
45
|
+
"codex",
|
|
46
|
+
"opencode",
|
|
47
|
+
"ai",
|
|
48
|
+
"agents",
|
|
49
|
+
"context-driven-development",
|
|
50
|
+
"draft",
|
|
51
|
+
"spec-driven-development"
|
|
52
|
+
]
|
|
53
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# fetch-memory-engine.sh — download and verify the Draft knowledge-graph engine.
|
|
3
|
+
#
|
|
4
|
+
# The engine is the codebase-memory-mcp single static binary. This script fetches
|
|
5
|
+
# the release archive for the host OS/arch from GitHub Releases, verifies its
|
|
6
|
+
# SHA-256 against the published checksums.txt, extracts it, and installs the
|
|
7
|
+
# binary to the Draft-managed location (~/.cache/draft/bin/codebase-memory-mcp),
|
|
8
|
+
# which scripts/tools/_lib.sh:find_memory_bin resolves.
|
|
9
|
+
#
|
|
10
|
+
# Pinned by default for reproducibility; override with CMM_VERSION (a tag, e.g.
|
|
11
|
+
# "v0.7.0", or "latest").
|
|
12
|
+
#
|
|
13
|
+
# Usage:
|
|
14
|
+
# scripts/fetch-memory-engine.sh [--dest DIR] [--force]
|
|
15
|
+
#
|
|
16
|
+
# Env:
|
|
17
|
+
# CMM_VERSION Release tag to fetch (default: pinned DEFAULT_VERSION).
|
|
18
|
+
# CMM_DOWNLOAD_URL Override the release base URL (testing).
|
|
19
|
+
#
|
|
20
|
+
# Exit codes: 0 installed/already-present, 1 invocation error, 2 fetch/verify failure.
|
|
21
|
+
set -euo pipefail
|
|
22
|
+
|
|
23
|
+
REPO="DeusData/codebase-memory-mcp"
|
|
24
|
+
DEFAULT_VERSION="v0.7.0" # pinned; bump deliberately
|
|
25
|
+
VERSION="${CMM_VERSION:-$DEFAULT_VERSION}"
|
|
26
|
+
DEST="$HOME/.cache/draft/bin"
|
|
27
|
+
FORCE=0
|
|
28
|
+
|
|
29
|
+
usage() { sed -n '2,22p' "$0" | sed 's/^# \{0,1\}//'; }
|
|
30
|
+
|
|
31
|
+
while [[ $# -gt 0 ]]; do
|
|
32
|
+
case "$1" in
|
|
33
|
+
--dest) DEST="$2"; shift 2 ;;
|
|
34
|
+
--force) FORCE=1; shift ;;
|
|
35
|
+
--help|-h) usage; exit 0 ;;
|
|
36
|
+
*) echo "Unknown flag: $1" >&2; usage >&2; exit 1 ;;
|
|
37
|
+
esac
|
|
38
|
+
done
|
|
39
|
+
|
|
40
|
+
BIN_PATH="$DEST/codebase-memory-mcp"
|
|
41
|
+
if [[ -x "$BIN_PATH" && $FORCE -eq 0 ]]; then
|
|
42
|
+
echo "codebase-memory-mcp already installed at $BIN_PATH ($("$BIN_PATH" --version 2>/dev/null || echo unknown))"
|
|
43
|
+
exit 0
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# --- Detect OS / arch (mirrors the engine's own install.sh naming) ---
|
|
47
|
+
case "$(uname -s)" in
|
|
48
|
+
Darwin) OS="darwin" ;;
|
|
49
|
+
Linux) OS="linux" ;;
|
|
50
|
+
*) echo "error: unsupported OS: $(uname -s)" >&2; exit 2 ;;
|
|
51
|
+
esac
|
|
52
|
+
case "$(uname -m)" in
|
|
53
|
+
x86_64|amd64) ARCH="amd64" ;;
|
|
54
|
+
arm64|aarch64) ARCH="arm64" ;;
|
|
55
|
+
*) echo "error: unsupported arch: $(uname -m)" >&2; exit 2 ;;
|
|
56
|
+
esac
|
|
57
|
+
|
|
58
|
+
# Linux ships a fully-static "-portable" build; macOS has no such variant.
|
|
59
|
+
PORTABLE=""
|
|
60
|
+
[[ "$OS" = "linux" ]] && PORTABLE="-portable"
|
|
61
|
+
ARCHIVE="codebase-memory-mcp-${OS}-${ARCH}${PORTABLE}.tar.gz"
|
|
62
|
+
|
|
63
|
+
if [[ -n "${CMM_DOWNLOAD_URL:-}" ]]; then
|
|
64
|
+
BASE="$CMM_DOWNLOAD_URL"
|
|
65
|
+
elif [[ "$VERSION" = "latest" ]]; then
|
|
66
|
+
BASE="https://github.com/${REPO}/releases/latest/download"
|
|
67
|
+
else
|
|
68
|
+
BASE="https://github.com/${REPO}/releases/download/${VERSION}"
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
case "$BASE" in https://*) ;; *) echo "error: refusing non-HTTPS URL: $BASE" >&2; exit 2 ;; esac
|
|
72
|
+
|
|
73
|
+
TMP="$(mktemp -d)"
|
|
74
|
+
trap 'rm -rf "$TMP"' EXIT
|
|
75
|
+
|
|
76
|
+
echo "Fetching ${ARCHIVE} (${VERSION})..."
|
|
77
|
+
if ! curl -fSL --max-time 300 -o "$TMP/$ARCHIVE" "$BASE/$ARCHIVE"; then
|
|
78
|
+
echo "error: download failed: $BASE/$ARCHIVE" >&2
|
|
79
|
+
exit 2
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
# --- Verify checksum (best-effort: hard-fail only if the archive is listed) ---
|
|
83
|
+
if curl -fsSL --max-time 60 -o "$TMP/checksums.txt" "$BASE/checksums.txt" 2>/dev/null; then
|
|
84
|
+
expected="$(grep " $ARCHIVE\$" "$TMP/checksums.txt" 2>/dev/null | awk '{print $1}' | head -1 || true)"
|
|
85
|
+
if [[ -n "$expected" ]]; then
|
|
86
|
+
if command -v sha256sum >/dev/null 2>&1; then
|
|
87
|
+
actual="$(sha256sum "$TMP/$ARCHIVE" | awk '{print $1}')"
|
|
88
|
+
else
|
|
89
|
+
actual="$(shasum -a 256 "$TMP/$ARCHIVE" | awk '{print $1}')"
|
|
90
|
+
fi
|
|
91
|
+
if [[ "$expected" != "$actual" ]]; then
|
|
92
|
+
echo "error: checksum mismatch for $ARCHIVE (expected $expected, got $actual)" >&2
|
|
93
|
+
exit 2
|
|
94
|
+
fi
|
|
95
|
+
echo " checksum OK"
|
|
96
|
+
else
|
|
97
|
+
echo " warning: $ARCHIVE not found in checksums.txt — skipping verification" >&2
|
|
98
|
+
fi
|
|
99
|
+
else
|
|
100
|
+
echo " warning: checksums.txt unavailable — skipping verification" >&2
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
# --- Extract and install ---
|
|
104
|
+
tar -xzf "$TMP/$ARCHIVE" -C "$TMP"
|
|
105
|
+
SRC="$(find "$TMP" -maxdepth 2 -type f -name codebase-memory-mcp | head -1)"
|
|
106
|
+
if [[ -z "$SRC" ]]; then
|
|
107
|
+
echo "error: codebase-memory-mcp binary not found in archive" >&2
|
|
108
|
+
exit 2
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
mkdir -p "$DEST"
|
|
112
|
+
install -m 0755 "$SRC" "$BIN_PATH" 2>/dev/null || { cp -f "$SRC" "$BIN_PATH"; chmod +x "$BIN_PATH"; }
|
|
113
|
+
|
|
114
|
+
echo "Installed: $("$BIN_PATH" --version 2>/dev/null || echo "$BIN_PATH")"
|
|
115
|
+
echo " -> $BIN_PATH"
|
|
116
|
+
exit 0
|
package/scripts/lib.sh
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Shared validation library for Draft skill files.
|
|
4
|
+
#
|
|
5
|
+
# Sourced by test suites. Defines constants and validation functions
|
|
6
|
+
# but does not execute anything when sourced.
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# source scripts/lib.sh
|
|
10
|
+
#
|
|
11
|
+
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
15
|
+
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
16
|
+
SKILLS_DIR="$ROOT_DIR/skills"
|
|
17
|
+
CORE_DIR="$ROOT_DIR/core"
|
|
18
|
+
TOOLS_DIR="$ROOT_DIR/scripts/tools"
|
|
19
|
+
|
|
20
|
+
# ─────────────────────────────────────────────────────────
|
|
21
|
+
# Skill ordering (canonical order for all references)
|
|
22
|
+
# ─────────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
SKILL_ORDER=(
|
|
25
|
+
draft
|
|
26
|
+
init
|
|
27
|
+
index
|
|
28
|
+
graph
|
|
29
|
+
new-track
|
|
30
|
+
decompose
|
|
31
|
+
implement
|
|
32
|
+
coverage
|
|
33
|
+
deploy-checklist
|
|
34
|
+
bughunt
|
|
35
|
+
review
|
|
36
|
+
upload
|
|
37
|
+
plan
|
|
38
|
+
ops
|
|
39
|
+
docs
|
|
40
|
+
discover
|
|
41
|
+
jira
|
|
42
|
+
integrations
|
|
43
|
+
quick-review
|
|
44
|
+
deep-review
|
|
45
|
+
testing-strategy
|
|
46
|
+
learn
|
|
47
|
+
adr
|
|
48
|
+
debug
|
|
49
|
+
standup
|
|
50
|
+
tech-debt
|
|
51
|
+
incident-response
|
|
52
|
+
documentation
|
|
53
|
+
status
|
|
54
|
+
revert
|
|
55
|
+
change
|
|
56
|
+
tour
|
|
57
|
+
impact
|
|
58
|
+
assist-review
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# ─────────────────────────────────────────────────────────
|
|
62
|
+
# Core reference files (inlined by Claude plugin at runtime)
|
|
63
|
+
# ─────────────────────────────────────────────────────────
|
|
64
|
+
|
|
65
|
+
CORE_FILES=(
|
|
66
|
+
# Methodology
|
|
67
|
+
"methodology.md"
|
|
68
|
+
"knowledge-base.md"
|
|
69
|
+
# Shared procedures
|
|
70
|
+
"shared/draft-context-loading.md"
|
|
71
|
+
"shared/git-report-metadata.md"
|
|
72
|
+
"shared/pattern-learning.md"
|
|
73
|
+
"shared/condensation.md"
|
|
74
|
+
"shared/cross-skill-dispatch.md"
|
|
75
|
+
"shared/jira-sync.md"
|
|
76
|
+
"shared/graph-query.md"
|
|
77
|
+
"shared/parallel-analysis.md"
|
|
78
|
+
# Foundations additions (Phase 0)
|
|
79
|
+
"shared/context-verify.md"
|
|
80
|
+
"shared/discovery-schema.md"
|
|
81
|
+
"shared/graph-usage-report.md"
|
|
82
|
+
"shared/parallel-fanout.md"
|
|
83
|
+
"shared/red-flags.md"
|
|
84
|
+
"shared/template-contract.md"
|
|
85
|
+
"shared/template-hygiene.md"
|
|
86
|
+
"shared/tool-resolver.md"
|
|
87
|
+
"shared/verification-gates.md"
|
|
88
|
+
# Templates
|
|
89
|
+
"templates/guardrails.md"
|
|
90
|
+
"templates/intake-questions.md"
|
|
91
|
+
"templates/ai-context.md"
|
|
92
|
+
"templates/ai-profile.md"
|
|
93
|
+
"templates/architecture.md"
|
|
94
|
+
"templates/track-architecture.md"
|
|
95
|
+
"templates/jira.md"
|
|
96
|
+
"templates/product.md"
|
|
97
|
+
"templates/tech-stack.md"
|
|
98
|
+
"templates/workflow.md"
|
|
99
|
+
"templates/spec.md"
|
|
100
|
+
"templates/plan.md"
|
|
101
|
+
"templates/metadata.json"
|
|
102
|
+
# Foundations additions
|
|
103
|
+
"templates/ai-context-export.md"
|
|
104
|
+
"templates/session-summary.md"
|
|
105
|
+
# Index templates (monorepo)
|
|
106
|
+
"templates/service-index.md"
|
|
107
|
+
"templates/dependency-graph.md"
|
|
108
|
+
"templates/tech-matrix.md"
|
|
109
|
+
"templates/root-product.md"
|
|
110
|
+
"templates/root-architecture.md"
|
|
111
|
+
"templates/root-tech-stack.md"
|
|
112
|
+
"templates/rca.md"
|
|
113
|
+
# Foundations / internal design templates (added during quality tooling work)
|
|
114
|
+
"templates/CHANGELOG.md"
|
|
115
|
+
"templates/discovery.md"
|
|
116
|
+
"templates/hld.md"
|
|
117
|
+
"templates/lld.md"
|
|
118
|
+
# Agents
|
|
119
|
+
"agents/architect.md"
|
|
120
|
+
"agents/debugger.md"
|
|
121
|
+
"agents/planner.md"
|
|
122
|
+
"agents/rca.md"
|
|
123
|
+
"agents/reviewer.md"
|
|
124
|
+
"agents/writer.md"
|
|
125
|
+
"agents/ops.md"
|
|
126
|
+
# VCS abstraction
|
|
127
|
+
"shared/vcs-commands.md"
|
|
128
|
+
# Guardrails system (Foundations)
|
|
129
|
+
"guardrails.md"
|
|
130
|
+
"guardrails/README.md"
|
|
131
|
+
"guardrails/security.md"
|
|
132
|
+
"guardrails/code-quality.md"
|
|
133
|
+
"guardrails/design-norms.md"
|
|
134
|
+
"guardrails/review-checks.md"
|
|
135
|
+
"guardrails/secure-patterns.md"
|
|
136
|
+
"guardrails/dependency-triage.md"
|
|
137
|
+
"guardrails/language-standards.md"
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# ─────────────────────────────────────────────────────────
|
|
141
|
+
# Deterministic tool scripts (under scripts/tools/)
|
|
142
|
+
# Skills invoke these for mechanical work — git metadata,
|
|
143
|
+
# file classification, TODO aging, hotspot ranking, etc.
|
|
144
|
+
# ─────────────────────────────────────────────────────────
|
|
145
|
+
|
|
146
|
+
TOOLS=(
|
|
147
|
+
"git-metadata.sh"
|
|
148
|
+
"classify-files.sh"
|
|
149
|
+
"parse-git-log.sh"
|
|
150
|
+
"scan-markers.sh"
|
|
151
|
+
"hotspot-rank.sh"
|
|
152
|
+
"cycle-detect.sh"
|
|
153
|
+
"parse-reports.sh"
|
|
154
|
+
"detect-test-framework.sh"
|
|
155
|
+
"run-coverage.sh"
|
|
156
|
+
"freshness-check.sh"
|
|
157
|
+
"adr-index.sh"
|
|
158
|
+
"manage-symlinks.sh"
|
|
159
|
+
"mermaid-from-graph.sh"
|
|
160
|
+
"graph-snapshot.sh"
|
|
161
|
+
"graph-impact.sh"
|
|
162
|
+
"graph-callers.sh"
|
|
163
|
+
"validate-frontmatter.sh"
|
|
164
|
+
# Foundations hygiene/verification tools
|
|
165
|
+
"check-graph-usage-report.sh"
|
|
166
|
+
"check-scope-conflicts.sh"
|
|
167
|
+
"check-skill-line-caps.sh"
|
|
168
|
+
"check-template-noop.sh"
|
|
169
|
+
"check-track-hygiene.sh"
|
|
170
|
+
"diff-templates-vs-tracks.sh"
|
|
171
|
+
"emit-skill-metrics.sh"
|
|
172
|
+
"fix-whitespace.sh"
|
|
173
|
+
"migrate-track-frontmatter.sh"
|
|
174
|
+
"render-track.sh"
|
|
175
|
+
"verify-citations.sh"
|
|
176
|
+
"verify-doc-anchors.sh"
|
|
177
|
+
"verify-graph-binary.sh"
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
# ─────────────────────────────────────────────────────────
|
|
181
|
+
# Validation functions
|
|
182
|
+
# ─────────────────────────────────────────────────────────
|
|
183
|
+
|
|
184
|
+
# Validate a skill name against kebab-case regex.
|
|
185
|
+
# Prevents path traversal, uppercase, special chars.
|
|
186
|
+
is_valid_skill_name() {
|
|
187
|
+
local name="$1"
|
|
188
|
+
[[ "$name" =~ ^[a-z][a-z0-9]*(-[a-z0-9]+)*$ ]]
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
# Extract body content from a SKILL.md file (strip YAML frontmatter).
|
|
192
|
+
# Returns non-zero and prints to stderr on validation failure.
|
|
193
|
+
extract_body() {
|
|
194
|
+
local file="$1"
|
|
195
|
+
|
|
196
|
+
if [[ "$(sed -n '1p' "$file")" != "---" ]]; then
|
|
197
|
+
echo "ERROR: Missing YAML frontmatter in $file" >&2
|
|
198
|
+
echo " Skill files must start with --- delimiter on line 1" >&2
|
|
199
|
+
return 1
|
|
200
|
+
fi
|
|
201
|
+
|
|
202
|
+
if ! awk 'NR > 1 && /^---$/ { found=1; exit } END { exit !found }' "$file"; then
|
|
203
|
+
echo "ERROR: Missing closing YAML frontmatter delimiter in $file" >&2
|
|
204
|
+
return 1
|
|
205
|
+
fi
|
|
206
|
+
|
|
207
|
+
local frontmatter
|
|
208
|
+
frontmatter=$(awk '
|
|
209
|
+
NR == 1 && /^---$/ { in_frontmatter=1; next }
|
|
210
|
+
/^---$/ && in_frontmatter { exit }
|
|
211
|
+
in_frontmatter { print }
|
|
212
|
+
' "$file")
|
|
213
|
+
|
|
214
|
+
if ! printf '%s\n' "$frontmatter" | grep -q "^name:"; then
|
|
215
|
+
echo "ERROR: Missing 'name:' field in frontmatter of $file" >&2
|
|
216
|
+
return 1
|
|
217
|
+
fi
|
|
218
|
+
|
|
219
|
+
if ! printf '%s\n' "$frontmatter" | grep -q "^description:"; then
|
|
220
|
+
echo "ERROR: Missing 'description:' field in frontmatter of $file" >&2
|
|
221
|
+
return 1
|
|
222
|
+
fi
|
|
223
|
+
|
|
224
|
+
awk '
|
|
225
|
+
BEGIN { in_frontmatter = 0; found_end = 0 }
|
|
226
|
+
/^---$/ {
|
|
227
|
+
if (NR == 1 && in_frontmatter == 0) {
|
|
228
|
+
in_frontmatter = 1
|
|
229
|
+
next
|
|
230
|
+
} else if (found_end == 0) {
|
|
231
|
+
found_end = 1
|
|
232
|
+
next
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
found_end == 1 { print }
|
|
236
|
+
' "$file"
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
# Validate body format: line 1 blank, line 2 starts with #, line 3 blank.
|
|
240
|
+
validate_skill_body_format() {
|
|
241
|
+
local skill="$1"
|
|
242
|
+
local skill_file="$2"
|
|
243
|
+
|
|
244
|
+
local body_head line1 line2 line3
|
|
245
|
+
body_head=$(extract_body "$skill_file" | sed -n '1,3p' || true)
|
|
246
|
+
line1=$(echo "$body_head" | sed -n '1p')
|
|
247
|
+
line2=$(echo "$body_head" | sed -n '2p')
|
|
248
|
+
line3=$(echo "$body_head" | sed -n '3p')
|
|
249
|
+
if [[ -n "$line1" ]] || [[ ! "$line2" =~ ^#\ ]] || [[ -n "$line3" ]]; then
|
|
250
|
+
echo "ERROR: Skill '$skill' body format invalid (expected: blank, '# Title', blank). Got:" >&2
|
|
251
|
+
echo " Line 1: '${line1}'" >&2
|
|
252
|
+
echo " Line 2: '${line2}'" >&2
|
|
253
|
+
echo " Line 3: '${line3}'" >&2
|
|
254
|
+
return 1
|
|
255
|
+
fi
|
|
256
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Shared helpers for scripts/tools/*.sh.
|
|
3
|
+
#
|
|
4
|
+
# Sourced, not executed. No side effects at source time.
|
|
5
|
+
|
|
6
|
+
# shellcheck shell=bash
|
|
7
|
+
|
|
8
|
+
json_escape() {
|
|
9
|
+
local s="$1"
|
|
10
|
+
s="${s//\\/\\\\}"
|
|
11
|
+
s="${s//\"/\\\"}"
|
|
12
|
+
s="${s//$'\n'/\\n}"
|
|
13
|
+
s="${s//$'\t'/\\t}"
|
|
14
|
+
s="${s//$'\r'/}"
|
|
15
|
+
printf '%s' "$s"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
# Extract a top-level YAML frontmatter field value from a Markdown file.
|
|
19
|
+
# Discover track directories under a repo root (default: caller's Draft repo).
|
|
20
|
+
discover_track_dirs() {
|
|
21
|
+
local repo_root="${1:-}"
|
|
22
|
+
[[ -n "$repo_root" ]] || return 0
|
|
23
|
+
find "$repo_root" -type d -path '*/tracks/*' -maxdepth 4 -mindepth 2 \
|
|
24
|
+
-not -path '*/.*' 2>/dev/null | sort
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
# Extract a string value from minified or pretty-printed JSON.
|
|
28
|
+
read_json_str() {
|
|
29
|
+
local file="$1" key="$2"
|
|
30
|
+
[[ -f "$file" ]] || return 0
|
|
31
|
+
awk -v key="$key" '
|
|
32
|
+
{
|
|
33
|
+
pat = "\""key"\"[[:space:]]*:[[:space:]]*\"[^\"]*\""
|
|
34
|
+
if (match($0, pat)) {
|
|
35
|
+
s = substr($0, RSTART, RLENGTH)
|
|
36
|
+
sub("^\""key"\"[[:space:]]*:[[:space:]]*\"", "", s)
|
|
37
|
+
sub("\"$", "", s)
|
|
38
|
+
print s
|
|
39
|
+
exit
|
|
40
|
+
}
|
|
41
|
+
}' "$file"
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# Parse scope_includes / scope_excludes from metadata.json or spec.md frontmatter.
|
|
45
|
+
read_scope_array() {
|
|
46
|
+
local file="$1" key="$2"
|
|
47
|
+
[[ -f "$file" ]] || return 0
|
|
48
|
+
case "$file" in
|
|
49
|
+
*.json)
|
|
50
|
+
awk -v key="$key" '
|
|
51
|
+
{
|
|
52
|
+
pat = "\""key"\"[[:space:]]*:[[:space:]]*\\[[^]]*\\]"
|
|
53
|
+
if (match($0, pat)) {
|
|
54
|
+
s = substr($0, RSTART, RLENGTH)
|
|
55
|
+
sub("^\""key"\"[[:space:]]*:[[:space:]]*", "", s)
|
|
56
|
+
gsub(/[\[\]",]/, " ", s)
|
|
57
|
+
print s
|
|
58
|
+
exit
|
|
59
|
+
}
|
|
60
|
+
}' "$file"
|
|
61
|
+
;;
|
|
62
|
+
*.md)
|
|
63
|
+
awk -v key="$key" '
|
|
64
|
+
NR==1 && /^---$/ { in_fm=1; next }
|
|
65
|
+
in_fm && /^---$/ { exit }
|
|
66
|
+
in_fm && $0 ~ "^"key":" {
|
|
67
|
+
sub("^"key":[[:space:]]*", "", $0)
|
|
68
|
+
gsub(/[\[\]",]/, " ", $0)
|
|
69
|
+
print $0
|
|
70
|
+
exit
|
|
71
|
+
}' "$file"
|
|
72
|
+
;;
|
|
73
|
+
esac
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
# Return the per-skill line cap from a caps config file (or GLOBAL_CAP).
|
|
77
|
+
skill_line_cap() {
|
|
78
|
+
local skill_name="$1" caps_conf="$2" global_cap="$3"
|
|
79
|
+
local name cap
|
|
80
|
+
[[ -f "$caps_conf" ]] || { printf '%s' "$global_cap"; return; }
|
|
81
|
+
while read -r name cap; do
|
|
82
|
+
[[ -z "$name" || "$name" == \#* ]] && continue
|
|
83
|
+
if [[ "$name" == "*" ]]; then
|
|
84
|
+
global_cap="$cap"
|
|
85
|
+
elif [[ "$name" == "$skill_name" ]]; then
|
|
86
|
+
printf '%s' "$cap"
|
|
87
|
+
return
|
|
88
|
+
fi
|
|
89
|
+
done < "$caps_conf"
|
|
90
|
+
printf '%s' "$global_cap"
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
get_yaml_field() {
|
|
94
|
+
local file="$1"
|
|
95
|
+
local key="$2"
|
|
96
|
+
awk -v key="$key" '
|
|
97
|
+
NR == 1 && /^---$/ { in_fm = 1; next }
|
|
98
|
+
in_fm && /^---$/ { exit }
|
|
99
|
+
in_fm {
|
|
100
|
+
if ($0 ~ "^"key":[[:space:]]*") {
|
|
101
|
+
val = $0
|
|
102
|
+
sub("^"key":[[:space:]]*", "", val)
|
|
103
|
+
if (val ~ /^".*"$/) { val = substr(val, 2, length(val)-2) }
|
|
104
|
+
sub(/[[:space:]]+$/, "", val)
|
|
105
|
+
print val
|
|
106
|
+
exit
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
' "$file"
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
# Locate the `codebase-memory-mcp` binary (Draft knowledge-graph engine).
|
|
113
|
+
# Sets MEMORY_BIN globally; returns 0 if found, 1 otherwise.
|
|
114
|
+
# Preference: PATH > Draft-managed install (~/.cache/draft/bin) > vendored bin/<arch> under known roots.
|
|
115
|
+
# No legacy fallbacks: the Aether `graph`/`graph-clang` binaries are retired.
|
|
116
|
+
find_memory_bin() {
|
|
117
|
+
local repo_abs="$1"
|
|
118
|
+
local self_repo="$2"
|
|
119
|
+
MEMORY_BIN=""
|
|
120
|
+
local bin_name="codebase-memory-mcp"
|
|
121
|
+
|
|
122
|
+
# 0. Hard opt-out: force the graph engine off (tests, air-gapped, opt-out users).
|
|
123
|
+
if [[ -n "${DRAFT_MEMORY_DISABLE:-}" ]]; then
|
|
124
|
+
return 1
|
|
125
|
+
fi
|
|
126
|
+
|
|
127
|
+
# 1. Explicit override (testing / pinned install).
|
|
128
|
+
if [[ -n "${DRAFT_MEMORY_BIN:-}" && -x "${DRAFT_MEMORY_BIN}" ]]; then
|
|
129
|
+
MEMORY_BIN="$DRAFT_MEMORY_BIN"
|
|
130
|
+
return 0
|
|
131
|
+
fi
|
|
132
|
+
|
|
133
|
+
# 2. PATH (highest for dev / global installs).
|
|
134
|
+
if command -v "$bin_name" >/dev/null 2>&1; then
|
|
135
|
+
MEMORY_BIN="$bin_name"
|
|
136
|
+
return 0
|
|
137
|
+
fi
|
|
138
|
+
|
|
139
|
+
# 3. Draft-managed install location (install.sh fetches the binary here).
|
|
140
|
+
local managed="$HOME/.cache/draft/bin/$bin_name"
|
|
141
|
+
if [[ -x "$managed" ]]; then
|
|
142
|
+
MEMORY_BIN="$managed"
|
|
143
|
+
return 0
|
|
144
|
+
fi
|
|
145
|
+
|
|
146
|
+
# 4. Optional vendored arch-specific binary under known roots.
|
|
147
|
+
local os arch norm
|
|
148
|
+
os=$(uname -s | tr '[:upper:]' '[:lower:]')
|
|
149
|
+
arch=$(uname -m)
|
|
150
|
+
case "$arch" in
|
|
151
|
+
x86_64|amd64) norm="amd64" ;;
|
|
152
|
+
aarch64|arm64) norm="arm64" ;;
|
|
153
|
+
*) norm="$arch" ;;
|
|
154
|
+
esac
|
|
155
|
+
local ARCH="${os}-${norm}"
|
|
156
|
+
|
|
157
|
+
local roots=()
|
|
158
|
+
[[ -n "$repo_abs" && -d "$repo_abs" ]] && roots+=("$repo_abs")
|
|
159
|
+
[[ -n "$self_repo" && -d "$self_repo" ]] && roots+=("$self_repo")
|
|
160
|
+
for bc in \
|
|
161
|
+
"$HOME/.cursor/plugins/local/draft/.draft-install-path" \
|
|
162
|
+
"$HOME/.claude/plugins/draft/.draft-install-path"; do
|
|
163
|
+
if [[ -f "$bc" ]]; then
|
|
164
|
+
local pr; pr="$(cat "$bc" 2>/dev/null || true)"
|
|
165
|
+
[[ -n "$pr" && -d "$pr" ]] && roots+=("$pr")
|
|
166
|
+
fi
|
|
167
|
+
done
|
|
168
|
+
|
|
169
|
+
for pr in "${roots[@]}"; do
|
|
170
|
+
local cand="$pr/bin/$ARCH/$bin_name"
|
|
171
|
+
if [[ -x "$cand" ]]; then
|
|
172
|
+
MEMORY_BIN="$cand"
|
|
173
|
+
return 0
|
|
174
|
+
fi
|
|
175
|
+
done
|
|
176
|
+
|
|
177
|
+
return 1
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
# Run a codebase-memory-mcp CLI tool. Echoes the JSON result (stdout); the engine's
|
|
181
|
+
# `level=...` log lines go to stderr and are discarded unless DRAFT_MEMORY_DEBUG is set.
|
|
182
|
+
# Usage: memory_cli <tool> [json-args]
|
|
183
|
+
memory_cli() {
|
|
184
|
+
local tool="$1"
|
|
185
|
+
local args="${2:-{\}}"
|
|
186
|
+
if [[ -z "${MEMORY_BIN:-}" ]]; then
|
|
187
|
+
return 1
|
|
188
|
+
fi
|
|
189
|
+
if [[ -n "${DRAFT_MEMORY_DEBUG:-}" ]]; then
|
|
190
|
+
"$MEMORY_BIN" cli "$tool" "$args"
|
|
191
|
+
else
|
|
192
|
+
"$MEMORY_BIN" cli "$tool" "$args" 2>/dev/null
|
|
193
|
+
fi
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
# Resolve the engine's project name for a repository absolute path via list_projects.
|
|
197
|
+
# Echoes the project name, or nothing if the repo has not been indexed yet.
|
|
198
|
+
memory_project_for_repo() {
|
|
199
|
+
local repo_abs="$1"
|
|
200
|
+
command -v jq >/dev/null 2>&1 || return 1
|
|
201
|
+
memory_cli list_projects '{}' 2>/dev/null \
|
|
202
|
+
| jq -r --arg p "$repo_abs" '.projects[]? | select(.root_path == $p) | .name' 2>/dev/null \
|
|
203
|
+
| head -1
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
# Ensure a repository is indexed in the engine; echo its project name.
|
|
207
|
+
# Indexes on demand when absent. Returns 1 if the engine is unavailable.
|
|
208
|
+
memory_ensure_index() {
|
|
209
|
+
local repo_abs="$1"
|
|
210
|
+
[[ -n "${MEMORY_BIN:-}" ]] || return 1
|
|
211
|
+
command -v jq >/dev/null 2>&1 || return 1
|
|
212
|
+
local proj
|
|
213
|
+
proj="$(memory_project_for_repo "$repo_abs" 2>/dev/null || true)"
|
|
214
|
+
if [[ -z "$proj" ]]; then
|
|
215
|
+
proj="$(memory_cli index_repository "{\"repo_path\":\"$repo_abs\"}" 2>/dev/null \
|
|
216
|
+
| jq -r '.project // empty' 2>/dev/null || true)"
|
|
217
|
+
fi
|
|
218
|
+
[[ -n "$proj" ]] || return 1
|
|
219
|
+
printf '%s' "$proj"
|
|
220
|
+
}
|