@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,203 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# git-metadata.sh — emit deterministic git metadata for Draft reports.
|
|
3
|
+
#
|
|
4
|
+
# Output is YAML frontmatter by default; --json emits the same fields as JSON.
|
|
5
|
+
# Use --project-metadata to write/update draft/metadata.json (project-level
|
|
6
|
+
# single source of truth for git state, used by all project-level artifacts).
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# scripts/tools/git-metadata.sh [--yaml|--json]
|
|
10
|
+
# [--project NAME] [--module NAME]
|
|
11
|
+
# [--track-id ID] [--generated-by CMD]
|
|
12
|
+
# [--base BRANCH]
|
|
13
|
+
# scripts/tools/git-metadata.sh --project-metadata [--project NAME]
|
|
14
|
+
# [--generated-by CMD] [--base BRANCH]
|
|
15
|
+
# [--output-dir DIR]
|
|
16
|
+
#
|
|
17
|
+
# Exit codes: 0 OK, 1 not a git repo or invocation error.
|
|
18
|
+
set -euo pipefail
|
|
19
|
+
|
|
20
|
+
# shellcheck source=_lib.sh
|
|
21
|
+
source "$(dirname "${BASH_SOURCE[0]}")/_lib.sh"
|
|
22
|
+
|
|
23
|
+
FORMAT="yaml"
|
|
24
|
+
PROJECT=""
|
|
25
|
+
MODULE="root"
|
|
26
|
+
TRACK_ID="null"
|
|
27
|
+
GENERATED_BY=""
|
|
28
|
+
BASE_BRANCH="main"
|
|
29
|
+
WRITE_PROJECT_METADATA=0
|
|
30
|
+
OUTPUT_DIR="."
|
|
31
|
+
|
|
32
|
+
usage() {
|
|
33
|
+
cat <<'EOF'
|
|
34
|
+
git-metadata.sh — emit deterministic git metadata for Draft reports.
|
|
35
|
+
|
|
36
|
+
Usage:
|
|
37
|
+
scripts/tools/git-metadata.sh [--yaml|--json]
|
|
38
|
+
[--project NAME] [--module NAME]
|
|
39
|
+
[--track-id ID] [--generated-by CMD]
|
|
40
|
+
[--base BRANCH]
|
|
41
|
+
scripts/tools/git-metadata.sh --project-metadata [--project NAME]
|
|
42
|
+
[--generated-by CMD] [--base BRANCH]
|
|
43
|
+
[--output-dir DIR]
|
|
44
|
+
|
|
45
|
+
Flags:
|
|
46
|
+
--yaml Emit YAML frontmatter (default).
|
|
47
|
+
--json Emit JSON object.
|
|
48
|
+
--project-metadata Write git state to draft/metadata.json (project-level
|
|
49
|
+
single source of truth). Creates the file if absent,
|
|
50
|
+
merges git.* and synced_to_commit if present.
|
|
51
|
+
--project NAME Project name (default: basename of repo).
|
|
52
|
+
--module NAME Module name (default: "root").
|
|
53
|
+
--track-id ID Track id (default: null).
|
|
54
|
+
--generated-by CMD Command or skill name that produced the report.
|
|
55
|
+
--base BRANCH Upstream branch to compare against (default: main).
|
|
56
|
+
--output-dir DIR Directory containing draft/ (default: cwd). Used with
|
|
57
|
+
--project-metadata.
|
|
58
|
+
--help Show this help.
|
|
59
|
+
|
|
60
|
+
Exit codes: 0 OK, 1 not a git repo or invocation error.
|
|
61
|
+
EOF
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
while [[ $# -gt 0 ]]; do
|
|
65
|
+
case "$1" in
|
|
66
|
+
--yaml) FORMAT="yaml"; shift;;
|
|
67
|
+
--json) FORMAT="json"; shift;;
|
|
68
|
+
--project-metadata) WRITE_PROJECT_METADATA=1; shift;;
|
|
69
|
+
--project) PROJECT="$2"; shift 2;;
|
|
70
|
+
--module) MODULE="$2"; shift 2;;
|
|
71
|
+
--track-id) TRACK_ID="$2"; shift 2;;
|
|
72
|
+
--generated-by) GENERATED_BY="$2"; shift 2;;
|
|
73
|
+
--base) BASE_BRANCH="$2"; shift 2;;
|
|
74
|
+
--output-dir) OUTPUT_DIR="$2"; shift 2;;
|
|
75
|
+
--help|-h) usage; exit 0;;
|
|
76
|
+
*) echo "Unknown flag: $1" >&2; usage >&2; exit 1;;
|
|
77
|
+
esac
|
|
78
|
+
done
|
|
79
|
+
|
|
80
|
+
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
81
|
+
echo "ERROR: not inside a git repository" >&2
|
|
82
|
+
exit 1
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
|
86
|
+
if [[ -z "$PROJECT" ]]; then
|
|
87
|
+
PROJECT="$(basename "$REPO_ROOT")"
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
LOCAL_BRANCH="$(git branch --show-current 2>/dev/null || echo "")"
|
|
91
|
+
REMOTE_BRANCH="$(git rev-parse --abbrev-ref '@{upstream}' 2>/dev/null || echo "none")"
|
|
92
|
+
FULL_SHA="$(git rev-parse HEAD)"
|
|
93
|
+
SHORT_SHA="$(git rev-parse --short HEAD)"
|
|
94
|
+
COMMIT_DATE="$(git log -1 --format=%cI HEAD)"
|
|
95
|
+
COMMIT_MESSAGE="$(git log -1 --format=%s HEAD)"
|
|
96
|
+
if [[ -n "$(git status --porcelain)" ]]; then
|
|
97
|
+
DIRTY="true"
|
|
98
|
+
else
|
|
99
|
+
DIRTY="false"
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
# Ahead/behind vs base (graceful fallback if base missing)
|
|
103
|
+
AHEAD=0
|
|
104
|
+
BEHIND=0
|
|
105
|
+
if git rev-parse --verify "$BASE_BRANCH" >/dev/null 2>&1; then
|
|
106
|
+
read -r BEHIND AHEAD < <(git rev-list --left-right --count "$BASE_BRANCH"...HEAD 2>/dev/null || echo "0 0")
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
GENERATED_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
110
|
+
|
|
111
|
+
# Escape double quotes in commit message for JSON/YAML safety
|
|
112
|
+
escape_for_yaml() {
|
|
113
|
+
# YAML double-quoted strings use \" and \\ as escapes
|
|
114
|
+
local s="$1"
|
|
115
|
+
s="${s//\\/\\\\}"
|
|
116
|
+
s="${s//\"/\\\"}"
|
|
117
|
+
printf '%s' "$s"
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
# --project-metadata: write draft/metadata.json and exit
|
|
121
|
+
if (( WRITE_PROJECT_METADATA )); then
|
|
122
|
+
DRAFT_DIR="$OUTPUT_DIR/draft"
|
|
123
|
+
META_FILE="$DRAFT_DIR/metadata.json"
|
|
124
|
+
if [[ ! -d "$DRAFT_DIR" ]]; then
|
|
125
|
+
echo "ERROR: $DRAFT_DIR not found — run draft:init first" >&2
|
|
126
|
+
exit 1
|
|
127
|
+
fi
|
|
128
|
+
CMD="${GENERATED_BY:-draft:init}"
|
|
129
|
+
_tmp="$(mktemp "${META_FILE}.XXXXXX")"
|
|
130
|
+
cat > "$_tmp" <<EOF
|
|
131
|
+
{
|
|
132
|
+
"\$schema": "Draft Project Metadata Schema",
|
|
133
|
+
"\$description": "Single source of truth for project-level git state. Read by all project-level skills. Written by $CMD.",
|
|
134
|
+
"project": "$(json_escape "$PROJECT")",
|
|
135
|
+
"schema_version": "1.0.0",
|
|
136
|
+
"generated_by": "$(json_escape "$CMD")",
|
|
137
|
+
"generated_at": "$GENERATED_AT",
|
|
138
|
+
"git": {
|
|
139
|
+
"branch": "$(json_escape "$LOCAL_BRANCH")",
|
|
140
|
+
"remote": "$(json_escape "$REMOTE_BRANCH")",
|
|
141
|
+
"commit": "$FULL_SHA",
|
|
142
|
+
"commit_short": "$SHORT_SHA",
|
|
143
|
+
"commit_date": "$COMMIT_DATE",
|
|
144
|
+
"commit_message": "$(json_escape "$COMMIT_MESSAGE")",
|
|
145
|
+
"dirty": $DIRTY,
|
|
146
|
+
"base_branch": "$(json_escape "$BASE_BRANCH")",
|
|
147
|
+
"commits_ahead_base": $AHEAD,
|
|
148
|
+
"commits_behind_base": $BEHIND
|
|
149
|
+
},
|
|
150
|
+
"synced_to_commit": "$FULL_SHA"
|
|
151
|
+
}
|
|
152
|
+
EOF
|
|
153
|
+
mv -f "$_tmp" "$META_FILE"
|
|
154
|
+
echo "Written: $META_FILE (synced_to_commit=$FULL_SHA)"
|
|
155
|
+
exit 0
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
if [[ "$FORMAT" == "json" ]]; then
|
|
159
|
+
cat <<EOF
|
|
160
|
+
{
|
|
161
|
+
"project": "$(json_escape "$PROJECT")",
|
|
162
|
+
"module": "$(json_escape "$MODULE")",
|
|
163
|
+
"track_id": $([[ "$TRACK_ID" == "null" ]] && echo "null" || echo "\"$(json_escape "$TRACK_ID")\""),
|
|
164
|
+
"generated_by": $([[ -z "$GENERATED_BY" ]] && echo "null" || echo "\"$(json_escape "$GENERATED_BY")\""),
|
|
165
|
+
"generated_at": "$GENERATED_AT",
|
|
166
|
+
"git": {
|
|
167
|
+
"branch": "$(json_escape "$LOCAL_BRANCH")",
|
|
168
|
+
"remote": "$(json_escape "$REMOTE_BRANCH")",
|
|
169
|
+
"commit": "$FULL_SHA",
|
|
170
|
+
"commit_short": "$SHORT_SHA",
|
|
171
|
+
"commit_date": "$COMMIT_DATE",
|
|
172
|
+
"commit_message": "$(json_escape "$COMMIT_MESSAGE")",
|
|
173
|
+
"dirty": $DIRTY,
|
|
174
|
+
"base_branch": "$(json_escape "$BASE_BRANCH")",
|
|
175
|
+
"commits_ahead_base": $AHEAD,
|
|
176
|
+
"commits_behind_base": $BEHIND
|
|
177
|
+
},
|
|
178
|
+
"synced_to_commit": "$FULL_SHA"
|
|
179
|
+
}
|
|
180
|
+
EOF
|
|
181
|
+
else
|
|
182
|
+
cat <<EOF
|
|
183
|
+
---
|
|
184
|
+
project: "$(escape_for_yaml "$PROJECT")"
|
|
185
|
+
module: "$(escape_for_yaml "$MODULE")"
|
|
186
|
+
track_id: $([[ "$TRACK_ID" == "null" ]] && echo "null" || echo "\"$(escape_for_yaml "$TRACK_ID")\"")
|
|
187
|
+
generated_by: $([[ -z "$GENERATED_BY" ]] && echo "null" || echo "\"$(escape_for_yaml "$GENERATED_BY")\"")
|
|
188
|
+
generated_at: "$GENERATED_AT"
|
|
189
|
+
git:
|
|
190
|
+
branch: "$(escape_for_yaml "$LOCAL_BRANCH")"
|
|
191
|
+
remote: "$(escape_for_yaml "$REMOTE_BRANCH")"
|
|
192
|
+
commit: "$FULL_SHA"
|
|
193
|
+
commit_short: "$SHORT_SHA"
|
|
194
|
+
commit_date: "$COMMIT_DATE"
|
|
195
|
+
commit_message: "$(escape_for_yaml "$COMMIT_MESSAGE")"
|
|
196
|
+
dirty: $DIRTY
|
|
197
|
+
base_branch: "$(escape_for_yaml "$BASE_BRANCH")"
|
|
198
|
+
commits_ahead_base: $AHEAD
|
|
199
|
+
commits_behind_base: $BEHIND
|
|
200
|
+
synced_to_commit: "$FULL_SHA"
|
|
201
|
+
---
|
|
202
|
+
EOF
|
|
203
|
+
fi
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# graph-callers.sh — enumerate direct callers of a function, from the knowledge graph.
|
|
3
|
+
#
|
|
4
|
+
# Replaces `graph --query --symbol <name> --mode callers`. Backed by the
|
|
5
|
+
# codebase-memory-mcp engine via a single-hop CALLS openCypher pattern (the
|
|
6
|
+
# dialect handles fixed-length patterns reliably).
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# scripts/tools/graph-callers.sh --repo DIR --symbol NAME
|
|
10
|
+
#
|
|
11
|
+
# Output: JSON {symbol, callers:[{name,file}], source}.
|
|
12
|
+
# source = "memory-graph" | "unavailable"
|
|
13
|
+
#
|
|
14
|
+
# Exit codes: 0 OK, 1 invocation error, 2 graph engine unavailable.
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
# shellcheck source=_lib.sh
|
|
18
|
+
source "$(dirname "${BASH_SOURCE[0]}")/_lib.sh"
|
|
19
|
+
|
|
20
|
+
REPO="."
|
|
21
|
+
SYMBOL=""
|
|
22
|
+
|
|
23
|
+
usage() {
|
|
24
|
+
cat <<'EOF'
|
|
25
|
+
graph-callers.sh — direct callers of a function.
|
|
26
|
+
|
|
27
|
+
Usage:
|
|
28
|
+
scripts/tools/graph-callers.sh --repo DIR --symbol NAME
|
|
29
|
+
|
|
30
|
+
Flags:
|
|
31
|
+
--repo DIR Repository root (default: cwd).
|
|
32
|
+
--symbol NAME Function name to find callers of (required).
|
|
33
|
+
--help Show this help.
|
|
34
|
+
|
|
35
|
+
Output: JSON {symbol, callers, source}. Exit 2 when engine unavailable.
|
|
36
|
+
EOF
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
while [[ $# -gt 0 ]]; do
|
|
40
|
+
case "$1" in
|
|
41
|
+
--repo) REPO="$2"; shift 2;;
|
|
42
|
+
--symbol) SYMBOL="$2"; shift 2;;
|
|
43
|
+
--help|-h) usage; exit 0;;
|
|
44
|
+
*) echo "Unknown flag: $1" >&2; usage >&2; exit 1;;
|
|
45
|
+
esac
|
|
46
|
+
done
|
|
47
|
+
|
|
48
|
+
[[ -d "$REPO" ]] || { echo "ERROR: --repo '$REPO' is not a directory" >&2; exit 1; }
|
|
49
|
+
[[ -n "$SYMBOL" ]] || { echo "ERROR: --symbol is required" >&2; usage >&2; exit 1; }
|
|
50
|
+
|
|
51
|
+
REPO_ABS="$(cd "$REPO" && pwd)"
|
|
52
|
+
SELF_REPO="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
53
|
+
|
|
54
|
+
unavailable() {
|
|
55
|
+
jq -n --arg s "$SYMBOL" '{symbol:$s, callers:[], source:"unavailable"}' 2>/dev/null \
|
|
56
|
+
|| echo '{"callers":[],"source":"unavailable"}'
|
|
57
|
+
exit 2
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
find_memory_bin "$REPO_ABS" "$SELF_REPO" || unavailable
|
|
61
|
+
command -v jq >/dev/null 2>&1 || unavailable
|
|
62
|
+
|
|
63
|
+
PROJECT="$(memory_ensure_index "$REPO_ABS" || true)"
|
|
64
|
+
[[ -n "$PROJECT" ]] || unavailable
|
|
65
|
+
|
|
66
|
+
# Escape single quotes in the symbol for the Cypher string literal.
|
|
67
|
+
SYM_ESC="${SYMBOL//\'/\\\'}"
|
|
68
|
+
Q="MATCH (c)-[:CALLS]->(f:Function {name:'$SYM_ESC'}) RETURN c.name AS caller, c.file_path AS file LIMIT 200"
|
|
69
|
+
RES="$(memory_cli query_graph "{\"project\":\"$PROJECT\",\"query\":\"$Q\"}" || echo '{}')"
|
|
70
|
+
|
|
71
|
+
echo "${RES:-{\}}" | jq --arg s "$SYMBOL" '
|
|
72
|
+
{symbol:$s,
|
|
73
|
+
callers: [ (.rows // [])[] | {name:.[0], file:.[1]} ],
|
|
74
|
+
source:"memory-graph"}'
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# graph-impact.sh — blast radius for a file or symbol, from the knowledge graph.
|
|
3
|
+
#
|
|
4
|
+
# Replaces `graph --query --file <path> --mode impact`. Backed by the
|
|
5
|
+
# codebase-memory-mcp engine: combines detect_changes (git-diff → impacted
|
|
6
|
+
# symbols, when querying the working tree) with trace_path callers for a named
|
|
7
|
+
# function (transitive upstream dependents).
|
|
8
|
+
#
|
|
9
|
+
# Usage:
|
|
10
|
+
# scripts/tools/graph-impact.sh --repo DIR (--file PATH | --symbol NAME) [--depth N]
|
|
11
|
+
#
|
|
12
|
+
# Output: JSON {target, kind, impacted:[{name,file,hop}], source}.
|
|
13
|
+
# source = "memory-graph" | "unavailable"
|
|
14
|
+
#
|
|
15
|
+
# Exit codes: 0 OK, 1 invocation error, 2 graph engine unavailable.
|
|
16
|
+
set -euo pipefail
|
|
17
|
+
|
|
18
|
+
# shellcheck source=_lib.sh
|
|
19
|
+
source "$(dirname "${BASH_SOURCE[0]}")/_lib.sh"
|
|
20
|
+
|
|
21
|
+
REPO="."
|
|
22
|
+
FILE=""
|
|
23
|
+
SYMBOL=""
|
|
24
|
+
DEPTH=3
|
|
25
|
+
|
|
26
|
+
usage() {
|
|
27
|
+
cat <<'EOF'
|
|
28
|
+
graph-impact.sh — blast radius for a file or symbol.
|
|
29
|
+
|
|
30
|
+
Usage:
|
|
31
|
+
scripts/tools/graph-impact.sh --repo DIR (--file PATH | --symbol NAME) [--depth N]
|
|
32
|
+
|
|
33
|
+
Flags:
|
|
34
|
+
--repo DIR Repository root (default: cwd).
|
|
35
|
+
--file PATH Size impact of a changed file (uses git working-tree diff).
|
|
36
|
+
--symbol NAME Transitive callers of a function (default depth 3).
|
|
37
|
+
--depth N Caller traversal depth for --symbol (default: 3).
|
|
38
|
+
--help Show this help.
|
|
39
|
+
|
|
40
|
+
Output: JSON {target, kind, impacted, source}. Exit 2 when engine unavailable.
|
|
41
|
+
EOF
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
while [[ $# -gt 0 ]]; do
|
|
45
|
+
case "$1" in
|
|
46
|
+
--repo) REPO="$2"; shift 2;;
|
|
47
|
+
--file) FILE="$2"; shift 2;;
|
|
48
|
+
--symbol) SYMBOL="$2"; shift 2;;
|
|
49
|
+
--depth) DEPTH="$2"; shift 2;;
|
|
50
|
+
--help|-h) usage; exit 0;;
|
|
51
|
+
*) echo "Unknown flag: $1" >&2; usage >&2; exit 1;;
|
|
52
|
+
esac
|
|
53
|
+
done
|
|
54
|
+
|
|
55
|
+
[[ -d "$REPO" ]] || { echo "ERROR: --repo '$REPO' is not a directory" >&2; exit 1; }
|
|
56
|
+
[[ -n "$FILE" || -n "$SYMBOL" ]] || { echo "ERROR: provide --file or --symbol" >&2; usage >&2; exit 1; }
|
|
57
|
+
|
|
58
|
+
REPO_ABS="$(cd "$REPO" && pwd)"
|
|
59
|
+
SELF_REPO="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
60
|
+
|
|
61
|
+
unavailable() {
|
|
62
|
+
local t="$1" k="$2"
|
|
63
|
+
jq -n --arg t "$t" --arg k "$k" '{target:$t, kind:$k, impacted:[], source:"unavailable"}' 2>/dev/null \
|
|
64
|
+
|| echo '{"impacted":[],"source":"unavailable"}'
|
|
65
|
+
exit 2
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if [[ -n "$SYMBOL" ]]; then TARGET="$SYMBOL"; KIND="symbol"; else TARGET="$FILE"; KIND="file"; fi
|
|
69
|
+
|
|
70
|
+
find_memory_bin "$REPO_ABS" "$SELF_REPO" || unavailable "$TARGET" "$KIND"
|
|
71
|
+
command -v jq >/dev/null 2>&1 || unavailable "$TARGET" "$KIND"
|
|
72
|
+
|
|
73
|
+
PROJECT="$(memory_ensure_index "$REPO_ABS" || true)"
|
|
74
|
+
[[ -n "$PROJECT" ]] || unavailable "$TARGET" "$KIND"
|
|
75
|
+
|
|
76
|
+
if [[ -n "$SYMBOL" ]]; then
|
|
77
|
+
# direction:"both" is the reliable form (the "callers" value returns empty in this engine);
|
|
78
|
+
# we read the .callers array from it.
|
|
79
|
+
RES="$(memory_cli trace_path "{\"project\":\"$PROJECT\",\"function_name\":\"$SYMBOL\",\"depth\":$DEPTH,\"direction\":\"both\"}" || echo '{}')"
|
|
80
|
+
echo "${RES:-{\}}" | jq --arg t "$TARGET" '
|
|
81
|
+
{target:$t, kind:"symbol",
|
|
82
|
+
impacted: [ (.callers // [])[] | {name:.name, file:(.qualified_name // ""), hop:(.hop // 1)} ],
|
|
83
|
+
source:"memory-graph"}'
|
|
84
|
+
else
|
|
85
|
+
# File impact: detect_changes maps the working-tree diff to impacted symbols.
|
|
86
|
+
RES="$(memory_cli detect_changes "{\"project\":\"$PROJECT\"}" || echo '{}')"
|
|
87
|
+
echo "${RES:-{\}}" | jq --arg t "$TARGET" '
|
|
88
|
+
{target:$t, kind:"file",
|
|
89
|
+
impacted: [ (.impacted_symbols // [])[]
|
|
90
|
+
| select((.file // "") | endswith($t) or (. == $t))
|
|
91
|
+
| {name:.name, file:(.file // ""), hop:1} ],
|
|
92
|
+
source:"memory-graph"}'
|
|
93
|
+
fi
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# graph-snapshot.sh — materialize a lightweight, committed knowledge-graph snapshot.
|
|
3
|
+
#
|
|
4
|
+
# In the codebase-memory-mcp model, Claude Code skills query the engine live
|
|
5
|
+
# (on-demand indexing into ~/.cache). This snapshot exists for the two cases
|
|
6
|
+
# that cannot run the engine: PR-reviewable graph state, and the Copilot/Gemini
|
|
7
|
+
# integrations (which read committed files, not MCP). It is small and derived —
|
|
8
|
+
# git remains the source of truth.
|
|
9
|
+
#
|
|
10
|
+
# Writes under <repo>/draft/graph/:
|
|
11
|
+
# schema.yaml engine + project metadata + counts (gates skill graph use)
|
|
12
|
+
# architecture.json raw get_architecture(all) output
|
|
13
|
+
# hotspots.jsonl fan-in-ranked symbols, one JSON object per line
|
|
14
|
+
# module-deps.mermaid co-change coupling diagram
|
|
15
|
+
# proto-map.mermaid detected-route diagram
|
|
16
|
+
#
|
|
17
|
+
# Usage: scripts/tools/graph-snapshot.sh [--repo DIR] [--out DIR]
|
|
18
|
+
# Exit codes: 0 OK, 1 invocation error, 2 graph engine unavailable.
|
|
19
|
+
set -euo pipefail
|
|
20
|
+
|
|
21
|
+
TOOLS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
22
|
+
# shellcheck source=_lib.sh
|
|
23
|
+
source "$TOOLS_DIR/_lib.sh"
|
|
24
|
+
|
|
25
|
+
REPO="."
|
|
26
|
+
OUT_DIR=""
|
|
27
|
+
|
|
28
|
+
usage() {
|
|
29
|
+
cat <<'EOF'
|
|
30
|
+
graph-snapshot.sh — write a committed knowledge-graph snapshot to draft/graph/.
|
|
31
|
+
|
|
32
|
+
Usage:
|
|
33
|
+
scripts/tools/graph-snapshot.sh [--repo DIR] [--out DIR]
|
|
34
|
+
|
|
35
|
+
Flags:
|
|
36
|
+
--repo DIR Repository root (default: cwd).
|
|
37
|
+
--out DIR Snapshot dir (default: <repo>/draft/graph).
|
|
38
|
+
--help Show this help.
|
|
39
|
+
|
|
40
|
+
Exit 0 on success, 2 when the graph engine is unavailable (no snapshot written).
|
|
41
|
+
EOF
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
while [[ $# -gt 0 ]]; do
|
|
45
|
+
case "$1" in
|
|
46
|
+
--repo) REPO="$2"; shift 2;;
|
|
47
|
+
--out) OUT_DIR="$2"; shift 2;;
|
|
48
|
+
--help|-h) usage; exit 0;;
|
|
49
|
+
*) echo "Unknown flag: $1" >&2; usage >&2; exit 1;;
|
|
50
|
+
esac
|
|
51
|
+
done
|
|
52
|
+
|
|
53
|
+
[[ -d "$REPO" ]] || { echo "ERROR: --repo '$REPO' is not a directory" >&2; exit 1; }
|
|
54
|
+
|
|
55
|
+
REPO_ABS="$(cd "$REPO" && pwd)"
|
|
56
|
+
SELF_REPO="$(cd "$TOOLS_DIR/../.." && pwd)"
|
|
57
|
+
OUT="${OUT_DIR:-$REPO_ABS/draft/graph}"
|
|
58
|
+
|
|
59
|
+
find_memory_bin "$REPO_ABS" "$SELF_REPO" || { echo "graph engine unavailable — no snapshot written" >&2; exit 2; }
|
|
60
|
+
command -v jq >/dev/null 2>&1 || { echo "jq required for snapshot" >&2; exit 2; }
|
|
61
|
+
|
|
62
|
+
PROJECT="$(memory_ensure_index "$REPO_ABS" || true)"
|
|
63
|
+
[[ -n "$PROJECT" ]] || { echo "could not index repo — no snapshot written" >&2; exit 2; }
|
|
64
|
+
|
|
65
|
+
mkdir -p "$OUT"
|
|
66
|
+
|
|
67
|
+
# 1. architecture.json (full get_architecture)
|
|
68
|
+
ARCH="$(memory_cli get_architecture "{\"project\":\"$PROJECT\",\"aspects\":[\"all\"]}" || echo '{}')"
|
|
69
|
+
echo "$ARCH" | jq '.' > "$OUT/architecture.json"
|
|
70
|
+
|
|
71
|
+
# 2. hotspots.jsonl (one object per line)
|
|
72
|
+
"$TOOLS_DIR/hotspot-rank.sh" --repo "$REPO_ABS" 2>/dev/null \
|
|
73
|
+
| jq -c '.hotspots[]?' > "$OUT/hotspots.jsonl" || true
|
|
74
|
+
|
|
75
|
+
# 3. mermaid diagrams (best-effort; tools emit a stub + exit 2 if empty)
|
|
76
|
+
"$TOOLS_DIR/mermaid-from-graph.sh" --repo "$REPO_ABS" --diagram module-deps > "$OUT/module-deps.mermaid" 2>/dev/null || true
|
|
77
|
+
"$TOOLS_DIR/mermaid-from-graph.sh" --repo "$REPO_ABS" --diagram proto-map > "$OUT/proto-map.mermaid" 2>/dev/null || true
|
|
78
|
+
|
|
79
|
+
# 4. schema.yaml — metadata + gate for skill graph use
|
|
80
|
+
NODES="$(echo "$ARCH" | jq -r '.total_nodes // 0')"
|
|
81
|
+
EDGES="$(echo "$ARCH" | jq -r '.total_edges // 0')"
|
|
82
|
+
HOTN="$(wc -l < "$OUT/hotspots.jsonl" | tr -d ' ')"
|
|
83
|
+
VER="$("$MEMORY_BIN" --version 2>/dev/null | awk '{print $NF}' || echo unknown)"
|
|
84
|
+
cat > "$OUT/schema.yaml" <<EOF
|
|
85
|
+
# Draft knowledge-graph snapshot — generated by scripts/tools/graph-snapshot.sh
|
|
86
|
+
# Derived from the codebase-memory-mcp engine; git remains source of truth.
|
|
87
|
+
engine: codebase-memory-mcp
|
|
88
|
+
engine_version: "$VER"
|
|
89
|
+
project: "$PROJECT"
|
|
90
|
+
generated_at: "$(date -Iseconds 2>/dev/null || date)"
|
|
91
|
+
nodes: $NODES
|
|
92
|
+
edges: $EDGES
|
|
93
|
+
hotspots: $HOTN
|
|
94
|
+
artifacts:
|
|
95
|
+
- architecture.json
|
|
96
|
+
- hotspots.jsonl
|
|
97
|
+
- module-deps.mermaid
|
|
98
|
+
- proto-map.mermaid
|
|
99
|
+
EOF
|
|
100
|
+
|
|
101
|
+
echo "Snapshot written to $OUT (nodes=$NODES edges=$EDGES hotspots=$HOTN)"
|
|
102
|
+
exit 0
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# hotspot-rank.sh — emit complexity/fan-in-ranked symbols from the knowledge graph.
|
|
3
|
+
#
|
|
4
|
+
# Backed by the codebase-memory-mcp engine (get_architecture, server-computed
|
|
5
|
+
# hotspot ranking by fan-in). Indexes the repo on demand if needed.
|
|
6
|
+
#
|
|
7
|
+
# Usage:
|
|
8
|
+
# scripts/tools/hotspot-rank.sh [--repo DIR] [--top N]
|
|
9
|
+
#
|
|
10
|
+
# Output: JSON {hotspots:[{id, name, fanIn}], source}.
|
|
11
|
+
# source = "memory-graph" | "unavailable"
|
|
12
|
+
#
|
|
13
|
+
# Exit codes: 0 OK, 1 invocation error, 2 graph engine/data unavailable.
|
|
14
|
+
set -euo pipefail
|
|
15
|
+
|
|
16
|
+
# shellcheck source=_lib.sh
|
|
17
|
+
source "$(dirname "${BASH_SOURCE[0]}")/_lib.sh"
|
|
18
|
+
|
|
19
|
+
REPO="."
|
|
20
|
+
TOP=0
|
|
21
|
+
|
|
22
|
+
usage() {
|
|
23
|
+
cat <<'EOF'
|
|
24
|
+
hotspot-rank.sh — fan-in-ranked symbols from the knowledge graph.
|
|
25
|
+
|
|
26
|
+
Usage:
|
|
27
|
+
scripts/tools/hotspot-rank.sh [--repo DIR] [--top N]
|
|
28
|
+
|
|
29
|
+
Flags:
|
|
30
|
+
--repo DIR Repository root (default: cwd).
|
|
31
|
+
--top N Keep only top N hotspots (default: 0 = all).
|
|
32
|
+
--help Show this help.
|
|
33
|
+
|
|
34
|
+
Output: JSON {hotspots:[{id, name, fanIn}], source}.
|
|
35
|
+
source = "memory-graph" | "unavailable"
|
|
36
|
+
|
|
37
|
+
Exit 0 with results, exit 2 with {"hotspots":[],"source":"unavailable"} when the
|
|
38
|
+
graph engine is unavailable.
|
|
39
|
+
EOF
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
while [[ $# -gt 0 ]]; do
|
|
43
|
+
case "$1" in
|
|
44
|
+
--repo) REPO="$2"; shift 2;;
|
|
45
|
+
--top) TOP="$2"; shift 2;;
|
|
46
|
+
--help|-h) usage; exit 0;;
|
|
47
|
+
*) echo "Unknown flag: $1" >&2; usage >&2; exit 1;;
|
|
48
|
+
esac
|
|
49
|
+
done
|
|
50
|
+
|
|
51
|
+
if [[ ! -d "$REPO" ]]; then
|
|
52
|
+
echo "ERROR: --repo '$REPO' is not a directory" >&2
|
|
53
|
+
exit 1
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
REPO_ABS="$(cd "$REPO" && pwd)"
|
|
57
|
+
SELF_REPO="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
58
|
+
|
|
59
|
+
unavailable() { echo '{"hotspots":[],"source":"unavailable"}'; exit 2; }
|
|
60
|
+
|
|
61
|
+
find_memory_bin "$REPO_ABS" "$SELF_REPO" || unavailable
|
|
62
|
+
command -v jq >/dev/null 2>&1 || unavailable
|
|
63
|
+
|
|
64
|
+
PROJECT="$(memory_ensure_index "$REPO_ABS" || true)"
|
|
65
|
+
[[ -n "$PROJECT" ]] || unavailable
|
|
66
|
+
|
|
67
|
+
ARCH_JSON="$(memory_cli get_architecture "{\"project\":\"$PROJECT\",\"aspects\":[\"hotspots\"]}" || true)"
|
|
68
|
+
[[ -n "$ARCH_JSON" ]] || unavailable
|
|
69
|
+
|
|
70
|
+
echo "$ARCH_JSON" | jq --argjson top "$TOP" '
|
|
71
|
+
{
|
|
72
|
+
hotspots: ([ (.hotspots // [])[] | {id: .qualified_name, name: .name, fanIn: .fan_in} ]
|
|
73
|
+
| if $top > 0 then .[0:$top] else . end),
|
|
74
|
+
source: "memory-graph"
|
|
75
|
+
}'
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# manage-symlinks.sh — refresh the "<kind>-latest.md" symlink in a directory.
|
|
3
|
+
#
|
|
4
|
+
# Finds the newest file matching "<kind>-report-*.md" in DIR and points
|
|
5
|
+
# "<kind>-report-latest.md" at it. Selection is by filename sort order
|
|
6
|
+
# (timestamps embedded in filenames), not mtime, so result is reproducible.
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# scripts/tools/manage-symlinks.sh <DIR> <KIND>
|
|
10
|
+
#
|
|
11
|
+
# Exit codes: 0 created/refreshed, 1 invocation error, 2 no matching files.
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
DIR=""
|
|
15
|
+
KIND=""
|
|
16
|
+
|
|
17
|
+
usage() {
|
|
18
|
+
cat <<'EOF'
|
|
19
|
+
manage-symlinks.sh — point "<kind>-report-latest.md" at the newest timestamped report.
|
|
20
|
+
|
|
21
|
+
Usage:
|
|
22
|
+
scripts/tools/manage-symlinks.sh <DIR> <KIND>
|
|
23
|
+
|
|
24
|
+
Positional:
|
|
25
|
+
DIR Directory containing <kind>-report-<timestamp>.md files.
|
|
26
|
+
KIND Report kind (e.g. "bughunt", "review", "standup").
|
|
27
|
+
|
|
28
|
+
Flags:
|
|
29
|
+
--help Show this help.
|
|
30
|
+
|
|
31
|
+
Selects the highest-sorted filename, creates/refreshes <kind>-report-latest.md
|
|
32
|
+
(relative symlink). Emits the chosen target filename to stdout.
|
|
33
|
+
EOF
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
while [[ $# -gt 0 ]]; do
|
|
37
|
+
case "$1" in
|
|
38
|
+
--help|-h) usage; exit 0;;
|
|
39
|
+
-*) echo "Unknown flag: $1" >&2; usage >&2; exit 1;;
|
|
40
|
+
*)
|
|
41
|
+
if [[ -z "$DIR" ]]; then DIR="$1"
|
|
42
|
+
elif [[ -z "$KIND" ]]; then KIND="$1"
|
|
43
|
+
else echo "Unexpected arg: $1" >&2; exit 1
|
|
44
|
+
fi
|
|
45
|
+
shift
|
|
46
|
+
;;
|
|
47
|
+
esac
|
|
48
|
+
done
|
|
49
|
+
|
|
50
|
+
if [[ -z "$DIR" || -z "$KIND" ]]; then
|
|
51
|
+
usage >&2
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
if [[ ! -d "$DIR" ]]; then
|
|
56
|
+
echo "ERROR: '$DIR' is not a directory" >&2
|
|
57
|
+
exit 1
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# Validate KIND (kebab-case-ish; no slashes, dots, or spaces)
|
|
61
|
+
if [[ ! "$KIND" =~ ^[a-z][a-z0-9-]*$ ]]; then
|
|
62
|
+
echo "ERROR: KIND must be kebab-case (got: '$KIND')" >&2
|
|
63
|
+
exit 1
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
pattern="$KIND-report-*.md"
|
|
67
|
+
latest_name="$KIND-report-latest.md"
|
|
68
|
+
|
|
69
|
+
# Exclude the latest symlink itself from selection.
|
|
70
|
+
newest=""
|
|
71
|
+
while IFS= read -r -d '' f; do
|
|
72
|
+
base="$(basename "$f")"
|
|
73
|
+
[[ "$base" == "$latest_name" ]] && continue
|
|
74
|
+
# File-only (not symlink we already manage)
|
|
75
|
+
if [[ -L "$f" ]]; then continue; fi
|
|
76
|
+
newest="$base"
|
|
77
|
+
done < <(find "$DIR" -maxdepth 1 -name "$pattern" -print0 | sort -z)
|
|
78
|
+
|
|
79
|
+
if [[ -z "$newest" ]]; then
|
|
80
|
+
echo "No matching $pattern files in $DIR" >&2
|
|
81
|
+
exit 2
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
(cd "$DIR" && ln -sfn "$newest" "$latest_name")
|
|
85
|
+
echo "$newest"
|