@lvlup-sw/exarchos 2.0.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 +22 -0
- package/.claude-plugin/plugin.json +17 -0
- package/.mcp.json +17 -0
- package/AGENTS.md +59 -0
- package/CLAUDE.md.template +62 -0
- package/LICENSE +202 -0
- package/README.md +258 -0
- package/commands/autocompact.md +37 -0
- package/commands/checkpoint.md +85 -0
- package/commands/cleanup.md +99 -0
- package/commands/debug.md +145 -0
- package/commands/delegate.md +56 -0
- package/commands/ideate.md +82 -0
- package/commands/plan.md +150 -0
- package/commands/refactor.md +139 -0
- package/commands/reload.md +37 -0
- package/commands/resume.md +130 -0
- package/commands/review.md +51 -0
- package/commands/sync-schemas.md +74 -0
- package/commands/synthesize.md +122 -0
- package/commands/tdd.md +58 -0
- package/dist/exarchos-cli.js +8828 -0
- package/dist/exarchos-mcp.js +50 -0
- package/hooks/hooks.json +53 -0
- package/package.json +59 -0
- package/rules/coding-standards.md +46 -0
- package/rules/mcp-tool-guidance.md +26 -0
- package/rules/pr-descriptions.md +12 -0
- package/rules/rm-safety.md +9 -0
- package/rules/skill-path-resolution.md +10 -0
- package/rules/tdd.md +41 -0
- package/rules/telemetry-awareness.md +9 -0
- package/scripts/assess-refactor-scope.sh +239 -0
- package/scripts/check-benchmark-regression.sh +229 -0
- package/scripts/check-coderabbit.sh +288 -0
- package/scripts/check-coverage-thresholds.sh +194 -0
- package/scripts/check-polish-scope.sh +245 -0
- package/scripts/check-property-tests.sh +167 -0
- package/scripts/check-tdd-compliance.sh +265 -0
- package/scripts/coderabbit-review-gate.sh +518 -0
- package/scripts/debug-review-gate.sh +201 -0
- package/scripts/extract-fix-tasks.sh +179 -0
- package/scripts/extract-task.sh +67 -0
- package/scripts/generate-traceability.sh +209 -0
- package/scripts/investigation-timer.sh +171 -0
- package/scripts/needs-schema-sync.sh +174 -0
- package/scripts/new-project.sh +103 -0
- package/scripts/post-delegation-check.sh +317 -0
- package/scripts/pre-synthesis-check.sh +440 -0
- package/scripts/reconcile-state.sh +346 -0
- package/scripts/reconstruct-stack.sh +432 -0
- package/scripts/review-diff.sh +63 -0
- package/scripts/review-verdict.sh +169 -0
- package/scripts/security-scan.sh +248 -0
- package/scripts/select-debug-track.sh +186 -0
- package/scripts/setup-worktree.sh +323 -0
- package/scripts/spec-coverage-check.sh +230 -0
- package/scripts/static-analysis-gate.sh +236 -0
- package/scripts/sync-labels.sh +122 -0
- package/scripts/validate-companion.sh +161 -0
- package/scripts/validate-dotnet-standards.sh +267 -0
- package/scripts/validate-installation.sh +101 -0
- package/scripts/validate-plugin.sh +223 -0
- package/scripts/validate-refactor.sh +234 -0
- package/scripts/validate-rm.sh +93 -0
- package/scripts/verify-delegation-saga.sh +240 -0
- package/scripts/verify-doc-links.sh +211 -0
- package/scripts/verify-ideate-artifacts.sh +296 -0
- package/scripts/verify-plan-coverage.sh +228 -0
- package/scripts/verify-review-triage.sh +219 -0
- package/scripts/verify-worktree-baseline.sh +159 -0
- package/scripts/verify-worktree.sh +84 -0
- package/settings.json +47 -0
- package/skills/brainstorming/SKILL.md +127 -0
- package/skills/brainstorming/references/design-template.md +65 -0
- package/skills/cleanup/SKILL.md +147 -0
- package/skills/cleanup/references/merge-verification.md +40 -0
- package/skills/debug/SKILL.md +204 -0
- package/skills/debug/references/hotfix-track.md +134 -0
- package/skills/debug/references/investigation-checklist.md +217 -0
- package/skills/debug/references/rca-template.md +150 -0
- package/skills/debug/references/state-schema.md +294 -0
- package/skills/debug/references/thorough-track.md +194 -0
- package/skills/debug/references/triage-questions.md +155 -0
- package/skills/debug/references/troubleshooting.md +47 -0
- package/skills/delegation/SKILL.md +150 -0
- package/skills/delegation/references/adaptive-orchestration.md +31 -0
- package/skills/delegation/references/agent-teams-saga.md +248 -0
- package/skills/delegation/references/fix-mode.md +74 -0
- package/skills/delegation/references/fixer-prompt.md +162 -0
- package/skills/delegation/references/implementer-prompt.md +322 -0
- package/skills/delegation/references/parallel-strategy.md +124 -0
- package/skills/delegation/references/pbt-patterns.md +172 -0
- package/skills/delegation/references/pr-fixes-mode.md +154 -0
- package/skills/delegation/references/state-management.md +51 -0
- package/skills/delegation/references/testing-patterns.md +129 -0
- package/skills/delegation/references/troubleshooting.md +33 -0
- package/skills/delegation/references/workflow-steps.md +127 -0
- package/skills/delegation/references/worktree-enforcement.md +64 -0
- package/skills/dotnet-standards/SKILL.md +269 -0
- package/skills/dotnet-standards/references/csharp-standards.md +120 -0
- package/skills/dotnet-standards/templates/.editorconfig +366 -0
- package/skills/dotnet-standards/templates/Directory.Build.props +56 -0
- package/skills/dotnet-standards/templates/Directory.Packages.props +69 -0
- package/skills/dotnet-standards/templates/global.json +6 -0
- package/skills/dotnet-standards/templates/nuget.config +9 -0
- package/skills/dotnet-standards/templates/stylecop.json +37 -0
- package/skills/git-worktrees/SKILL.md +255 -0
- package/skills/implementation-planning/SKILL.md +233 -0
- package/skills/implementation-planning/references/plan-document-template.md +42 -0
- package/skills/implementation-planning/references/spec-tracing-guide.md +51 -0
- package/skills/implementation-planning/references/task-template.md +43 -0
- package/skills/implementation-planning/references/testing-strategy-guide.md +88 -0
- package/skills/quality-review/SKILL.md +278 -0
- package/skills/quality-review/references/code-quality-checklist.md +159 -0
- package/skills/quality-review/references/review-report-template.md +65 -0
- package/skills/quality-review/references/security-checklist.md +79 -0
- package/skills/quality-review/references/typescript-standards.md +24 -0
- package/skills/refactor/COMMAND.md +67 -0
- package/skills/refactor/SKILL.md +198 -0
- package/skills/refactor/phases/auto-chain.md +262 -0
- package/skills/refactor/phases/brief.md +176 -0
- package/skills/refactor/phases/explore.md +132 -0
- package/skills/refactor/phases/overhaul-delegate.md +136 -0
- package/skills/refactor/phases/overhaul-plan.md +312 -0
- package/skills/refactor/phases/overhaul-review.md +304 -0
- package/skills/refactor/phases/polish-implement.md +349 -0
- package/skills/refactor/phases/polish-validate.md +218 -0
- package/skills/refactor/phases/update-docs.md +234 -0
- package/skills/refactor/references/brief-template.md +81 -0
- package/skills/refactor/references/doc-update-checklist.md +110 -0
- package/skills/refactor/references/explore-checklist.md +73 -0
- package/skills/refactor/references/overhaul-track.md +215 -0
- package/skills/refactor/references/polish-track.md +170 -0
- package/skills/shared/prompts/context-reading.md +58 -0
- package/skills/shared/prompts/report-format.md +54 -0
- package/skills/shared/prompts/tdd-requirements.md +39 -0
- package/skills/shepherd/SKILL.md +264 -0
- package/skills/shepherd/references/assess-checklist.md +124 -0
- package/skills/shepherd/references/fix-strategies.md +191 -0
- package/skills/spec-review/SKILL.md +229 -0
- package/skills/spec-review/references/review-checklist.md +60 -0
- package/skills/sync-schemas/SKILL.md +114 -0
- package/skills/sync-schemas/references/configuration.md +73 -0
- package/skills/synthesis/SKILL.md +129 -0
- package/skills/synthesis/references/pr-descriptions.md +87 -0
- package/skills/synthesis/references/synthesis-steps.md +109 -0
- package/skills/synthesis/references/troubleshooting.md +115 -0
- package/skills/validate-all-skills.sh +57 -0
- package/skills/validate-frontmatter.sh +237 -0
- package/skills/workflow-state/SKILL.md +210 -0
- package/skills/workflow-state/references/mcp-tool-reference.md +111 -0
- package/skills/workflow-state/references/phase-transitions.md +141 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Debug Review Gate
|
|
3
|
+
# Verifies that a debug fix has proper test coverage for the bug scenario.
|
|
4
|
+
# Replaces "Thorough Track Review" prose with deterministic validation.
|
|
5
|
+
#
|
|
6
|
+
# Usage: debug-review-gate.sh --repo-root <path> --base-branch <branch> [--skip-run]
|
|
7
|
+
#
|
|
8
|
+
# Exit codes:
|
|
9
|
+
# 0 = review passed (tests added, tests pass, no regressions)
|
|
10
|
+
# 1 = gaps found (missing tests or regressions)
|
|
11
|
+
# 2 = usage error (missing required args)
|
|
12
|
+
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
|
|
15
|
+
# ============================================================
|
|
16
|
+
# ARGUMENT PARSING
|
|
17
|
+
# ============================================================
|
|
18
|
+
|
|
19
|
+
REPO_ROOT=""
|
|
20
|
+
BASE_BRANCH=""
|
|
21
|
+
SKIP_RUN=false
|
|
22
|
+
|
|
23
|
+
usage() {
|
|
24
|
+
cat << 'USAGE'
|
|
25
|
+
Usage: debug-review-gate.sh --repo-root <path> --base-branch <branch> [--skip-run]
|
|
26
|
+
|
|
27
|
+
Required:
|
|
28
|
+
--repo-root <path> Repository root directory
|
|
29
|
+
--base-branch <branch> Base branch to diff against (e.g., main)
|
|
30
|
+
|
|
31
|
+
Optional:
|
|
32
|
+
--skip-run Skip test execution (only check for new test files)
|
|
33
|
+
--help Show this help message
|
|
34
|
+
|
|
35
|
+
Exit codes:
|
|
36
|
+
0 Review passed — tests added, tests pass, no regressions
|
|
37
|
+
1 Gaps found — missing tests or test failures
|
|
38
|
+
2 Usage error (missing required args)
|
|
39
|
+
USAGE
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
while [[ $# -gt 0 ]]; do
|
|
43
|
+
case "$1" in
|
|
44
|
+
--repo-root)
|
|
45
|
+
if [[ -z "${2:-}" ]]; then
|
|
46
|
+
echo "Error: --repo-root requires a path argument" >&2
|
|
47
|
+
exit 2
|
|
48
|
+
fi
|
|
49
|
+
REPO_ROOT="$2"
|
|
50
|
+
shift 2
|
|
51
|
+
;;
|
|
52
|
+
--base-branch)
|
|
53
|
+
if [[ -z "${2:-}" ]]; then
|
|
54
|
+
echo "Error: --base-branch requires a branch name argument" >&2
|
|
55
|
+
exit 2
|
|
56
|
+
fi
|
|
57
|
+
BASE_BRANCH="$2"
|
|
58
|
+
shift 2
|
|
59
|
+
;;
|
|
60
|
+
--skip-run)
|
|
61
|
+
SKIP_RUN=true
|
|
62
|
+
shift
|
|
63
|
+
;;
|
|
64
|
+
--help)
|
|
65
|
+
usage
|
|
66
|
+
exit 0
|
|
67
|
+
;;
|
|
68
|
+
*)
|
|
69
|
+
echo "Error: Unknown argument '$1'" >&2
|
|
70
|
+
usage >&2
|
|
71
|
+
exit 2
|
|
72
|
+
;;
|
|
73
|
+
esac
|
|
74
|
+
done
|
|
75
|
+
|
|
76
|
+
if [[ -z "$REPO_ROOT" || -z "$BASE_BRANCH" ]]; then
|
|
77
|
+
echo "Error: --repo-root and --base-branch are required" >&2
|
|
78
|
+
usage >&2
|
|
79
|
+
exit 2
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
if [[ ! -d "$REPO_ROOT" ]]; then
|
|
83
|
+
echo "Error: Repository root not found: $REPO_ROOT" >&2
|
|
84
|
+
exit 2
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# ============================================================
|
|
88
|
+
# CHECK FUNCTIONS
|
|
89
|
+
# ============================================================
|
|
90
|
+
|
|
91
|
+
CHECK_PASS=0
|
|
92
|
+
CHECK_FAIL=0
|
|
93
|
+
RESULTS=()
|
|
94
|
+
|
|
95
|
+
check_pass() {
|
|
96
|
+
local name="$1"
|
|
97
|
+
RESULTS+=("- **PASS**: $name")
|
|
98
|
+
CHECK_PASS=$((CHECK_PASS + 1))
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
check_fail() {
|
|
102
|
+
local name="$1"
|
|
103
|
+
local detail="${2:-}"
|
|
104
|
+
if [[ -n "$detail" ]]; then
|
|
105
|
+
RESULTS+=("- **FAIL**: $name — $detail")
|
|
106
|
+
else
|
|
107
|
+
RESULTS+=("- **FAIL**: $name")
|
|
108
|
+
fi
|
|
109
|
+
CHECK_FAIL=$((CHECK_FAIL + 1))
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
check_skip() {
|
|
113
|
+
local name="$1"
|
|
114
|
+
RESULTS+=("- **SKIP**: $name")
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
# ============================================================
|
|
118
|
+
# CHECK 1: New test files added in the fix branch
|
|
119
|
+
# ============================================================
|
|
120
|
+
|
|
121
|
+
check_new_tests() {
|
|
122
|
+
local changed_files
|
|
123
|
+
changed_files="$(cd "$REPO_ROOT" && git diff --name-only "$BASE_BRANCH"...HEAD 2>/dev/null || \
|
|
124
|
+
cd "$REPO_ROOT" && git diff --name-only "$BASE_BRANCH" HEAD 2>/dev/null || true)"
|
|
125
|
+
|
|
126
|
+
if [[ -z "$changed_files" ]]; then
|
|
127
|
+
check_fail "New test files added" "No changed files found between $BASE_BRANCH and HEAD"
|
|
128
|
+
return 1
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
# Look for test files: .test.ts, .test.sh, .spec.ts, .test.js, .spec.js
|
|
132
|
+
local test_files
|
|
133
|
+
test_files="$(echo "$changed_files" | grep -E '\.(test|spec)\.(ts|js|sh)$' || true)"
|
|
134
|
+
|
|
135
|
+
if [[ -z "$test_files" ]]; then
|
|
136
|
+
check_fail "New test files added" "No test files found in changed files"
|
|
137
|
+
return 1
|
|
138
|
+
fi
|
|
139
|
+
|
|
140
|
+
local test_count
|
|
141
|
+
test_count="$(echo "$test_files" | wc -l | tr -d ' ')"
|
|
142
|
+
check_pass "New test files added ($test_count test file(s): $(echo "$test_files" | tr '\n' ', ' | sed 's/,$//'))"
|
|
143
|
+
return 0
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
# ============================================================
|
|
147
|
+
# CHECK 2: Tests pass (npm run test:run)
|
|
148
|
+
# ============================================================
|
|
149
|
+
|
|
150
|
+
check_tests_pass() {
|
|
151
|
+
if [[ "$SKIP_RUN" == true ]]; then
|
|
152
|
+
check_skip "Tests pass (--skip-run)"
|
|
153
|
+
return 0
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
local test_output
|
|
157
|
+
if ! test_output="$(cd "$REPO_ROOT" && npm run test:run 2>&1)"; then
|
|
158
|
+
check_fail "Tests pass" "npm run test:run failed"
|
|
159
|
+
return 1
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
check_pass "Tests pass"
|
|
163
|
+
return 0
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
# ============================================================
|
|
167
|
+
# EXECUTE CHECKS
|
|
168
|
+
# ============================================================
|
|
169
|
+
|
|
170
|
+
# Check 1: New test files
|
|
171
|
+
check_new_tests || true
|
|
172
|
+
|
|
173
|
+
# Check 2: Tests pass
|
|
174
|
+
check_tests_pass || true
|
|
175
|
+
|
|
176
|
+
# ============================================================
|
|
177
|
+
# STRUCTURED OUTPUT
|
|
178
|
+
# ============================================================
|
|
179
|
+
|
|
180
|
+
echo "## Debug Review Gate"
|
|
181
|
+
echo ""
|
|
182
|
+
echo "**Repository:** \`$REPO_ROOT\`"
|
|
183
|
+
echo "**Base branch:** \`$BASE_BRANCH\`"
|
|
184
|
+
echo ""
|
|
185
|
+
|
|
186
|
+
for result in "${RESULTS[@]}"; do
|
|
187
|
+
echo "$result"
|
|
188
|
+
done
|
|
189
|
+
|
|
190
|
+
echo ""
|
|
191
|
+
TOTAL=$((CHECK_PASS + CHECK_FAIL))
|
|
192
|
+
echo "---"
|
|
193
|
+
echo ""
|
|
194
|
+
|
|
195
|
+
if [[ $CHECK_FAIL -eq 0 ]]; then
|
|
196
|
+
echo "**Result: PASS** ($CHECK_PASS/$TOTAL checks passed)"
|
|
197
|
+
exit 0
|
|
198
|
+
else
|
|
199
|
+
echo "**Result: FAIL** ($CHECK_FAIL/$TOTAL checks failed)"
|
|
200
|
+
exit 1
|
|
201
|
+
fi
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# extract-fix-tasks.sh — Parse review findings into fix tasks
|
|
3
|
+
# Replaces "Fix Mode Task Extraction" prose in delegation SKILL.md.
|
|
4
|
+
#
|
|
5
|
+
# Usage: extract-fix-tasks.sh --state-file <path> [--review-report <path>] [--repo-root <path>]
|
|
6
|
+
#
|
|
7
|
+
# Exit codes:
|
|
8
|
+
# 0 = tasks extracted (outputs JSON array to stdout)
|
|
9
|
+
# 1 = parse error
|
|
10
|
+
# 2 = usage error (missing required args)
|
|
11
|
+
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
15
|
+
|
|
16
|
+
# ============================================================
|
|
17
|
+
# ARGUMENT PARSING
|
|
18
|
+
# ============================================================
|
|
19
|
+
|
|
20
|
+
STATE_FILE=""
|
|
21
|
+
REVIEW_REPORT=""
|
|
22
|
+
REPO_ROOT=""
|
|
23
|
+
|
|
24
|
+
usage() {
|
|
25
|
+
cat << 'USAGE'
|
|
26
|
+
Usage: extract-fix-tasks.sh --state-file <path> [--review-report <path>] [--repo-root <path>]
|
|
27
|
+
|
|
28
|
+
Required:
|
|
29
|
+
--state-file <path> Path to the workflow state JSON file
|
|
30
|
+
|
|
31
|
+
Optional:
|
|
32
|
+
--review-report <path> External review report JSON file (overrides state findings)
|
|
33
|
+
--repo-root <path> Repository root for worktree resolution
|
|
34
|
+
--help Show this help message
|
|
35
|
+
|
|
36
|
+
Output:
|
|
37
|
+
JSON array of fix tasks to stdout. Each task has: id, file, line, worktree, description, severity
|
|
38
|
+
|
|
39
|
+
Exit codes:
|
|
40
|
+
0 Tasks extracted (JSON array output, may be empty if no findings)
|
|
41
|
+
1 Parse error (invalid JSON, missing file)
|
|
42
|
+
2 Usage error (missing required args)
|
|
43
|
+
USAGE
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
while [[ $# -gt 0 ]]; do
|
|
47
|
+
case "$1" in
|
|
48
|
+
--state-file)
|
|
49
|
+
if [[ -z "${2:-}" ]]; then
|
|
50
|
+
echo "Error: --state-file requires a path argument" >&2
|
|
51
|
+
exit 2
|
|
52
|
+
fi
|
|
53
|
+
STATE_FILE="$2"
|
|
54
|
+
shift 2
|
|
55
|
+
;;
|
|
56
|
+
--review-report)
|
|
57
|
+
if [[ -z "${2:-}" ]]; then
|
|
58
|
+
echo "Error: --review-report requires a path argument" >&2
|
|
59
|
+
exit 2
|
|
60
|
+
fi
|
|
61
|
+
REVIEW_REPORT="$2"
|
|
62
|
+
shift 2
|
|
63
|
+
;;
|
|
64
|
+
--repo-root)
|
|
65
|
+
if [[ -z "${2:-}" ]]; then
|
|
66
|
+
echo "Error: --repo-root requires a path argument" >&2
|
|
67
|
+
exit 2
|
|
68
|
+
fi
|
|
69
|
+
REPO_ROOT="$2"
|
|
70
|
+
shift 2
|
|
71
|
+
;;
|
|
72
|
+
--help)
|
|
73
|
+
usage
|
|
74
|
+
exit 0
|
|
75
|
+
;;
|
|
76
|
+
*)
|
|
77
|
+
echo "Error: Unknown argument '$1'" >&2
|
|
78
|
+
usage >&2
|
|
79
|
+
exit 2
|
|
80
|
+
;;
|
|
81
|
+
esac
|
|
82
|
+
done
|
|
83
|
+
|
|
84
|
+
if [[ -z "$STATE_FILE" ]]; then
|
|
85
|
+
echo "Error: --state-file is required" >&2
|
|
86
|
+
usage >&2
|
|
87
|
+
exit 2
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
# ============================================================
|
|
91
|
+
# DEPENDENCY CHECK
|
|
92
|
+
# ============================================================
|
|
93
|
+
|
|
94
|
+
if ! command -v jq &>/dev/null; then
|
|
95
|
+
echo "Error: jq is required but not installed" >&2
|
|
96
|
+
exit 2
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
# ============================================================
|
|
100
|
+
# VALIDATE INPUTS
|
|
101
|
+
# ============================================================
|
|
102
|
+
|
|
103
|
+
if [[ ! -f "$STATE_FILE" ]]; then
|
|
104
|
+
echo "Error: State file not found: $STATE_FILE" >&2
|
|
105
|
+
exit 1
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
if ! jq empty "$STATE_FILE" 2>/dev/null; then
|
|
109
|
+
echo "Error: Invalid JSON in state file: $STATE_FILE" >&2
|
|
110
|
+
exit 1
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
if [[ -n "$REVIEW_REPORT" ]]; then
|
|
114
|
+
if [[ ! -f "$REVIEW_REPORT" ]]; then
|
|
115
|
+
echo "Error: Review report not found: $REVIEW_REPORT" >&2
|
|
116
|
+
exit 1
|
|
117
|
+
fi
|
|
118
|
+
if ! jq empty "$REVIEW_REPORT" 2>/dev/null; then
|
|
119
|
+
echo "Error: Invalid JSON in review report: $REVIEW_REPORT" >&2
|
|
120
|
+
exit 1
|
|
121
|
+
fi
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
# ============================================================
|
|
125
|
+
# EXTRACT FINDINGS
|
|
126
|
+
# ============================================================
|
|
127
|
+
|
|
128
|
+
# Collect all findings from either the review report or the state file
|
|
129
|
+
if [[ -n "$REVIEW_REPORT" ]]; then
|
|
130
|
+
# Use external review report
|
|
131
|
+
ALL_FINDINGS="$(jq -c '.findings // []' "$REVIEW_REPORT" 2>/dev/null || echo '[]')"
|
|
132
|
+
else
|
|
133
|
+
# Extract findings from state file reviews
|
|
134
|
+
ALL_FINDINGS="$(jq -c '
|
|
135
|
+
[
|
|
136
|
+
(.reviews // {} | to_entries[] | .value.findings // [] | .[])
|
|
137
|
+
]
|
|
138
|
+
' "$STATE_FILE" 2>/dev/null || echo '[]')"
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
# ============================================================
|
|
142
|
+
# BUILD FIX TASKS
|
|
143
|
+
# ============================================================
|
|
144
|
+
|
|
145
|
+
# Get all worktrees from tasks for file-to-worktree mapping
|
|
146
|
+
WORKTREES_JSON="$(jq -c '[.tasks[] | select(.worktree != null) | {worktree: .worktree, branch: (.branch // "unknown")}] | unique_by(.worktree)' "$STATE_FILE" 2>/dev/null || echo '[]')"
|
|
147
|
+
|
|
148
|
+
# Fail fast when multiple worktrees exist — deterministic mapping not yet implemented
|
|
149
|
+
WORKTREE_COUNT="$(echo "$WORKTREES_JSON" | jq 'length')"
|
|
150
|
+
FINDING_COUNT="$(echo "$ALL_FINDINGS" | jq 'length')"
|
|
151
|
+
if [[ "$WORKTREE_COUNT" -gt 1 && "$FINDING_COUNT" -gt 0 ]]; then
|
|
152
|
+
echo "Error: $WORKTREE_COUNT worktrees detected but cannot deterministically map $FINDING_COUNT findings to worktrees." >&2
|
|
153
|
+
echo " Assign worktrees manually in the fix task file." >&2
|
|
154
|
+
exit 1
|
|
155
|
+
fi
|
|
156
|
+
|
|
157
|
+
# Transform findings into fix tasks with IDs and worktree mapping
|
|
158
|
+
FIX_TASKS="$(echo "$ALL_FINDINGS" | jq -c --argjson worktrees "$WORKTREES_JSON" '
|
|
159
|
+
[to_entries[] | {
|
|
160
|
+
id: ("fix-\(.key + 1 | tostring | if length < 3 then ("00" + .)[-3:] else . end)"),
|
|
161
|
+
file: .value.file,
|
|
162
|
+
line: (.value.line // null),
|
|
163
|
+
worktree: (
|
|
164
|
+
($worktrees | length) as $n |
|
|
165
|
+
if $n == 1 then $worktrees[0].worktree else null end
|
|
166
|
+
),
|
|
167
|
+
description: .value.description,
|
|
168
|
+
severity: (.value.severity // "MEDIUM")
|
|
169
|
+
}]
|
|
170
|
+
' 2>/dev/null)"
|
|
171
|
+
|
|
172
|
+
if [[ -z "$FIX_TASKS" || "$FIX_TASKS" == "null" ]]; then
|
|
173
|
+
echo "[]"
|
|
174
|
+
exit 0
|
|
175
|
+
fi
|
|
176
|
+
|
|
177
|
+
# Output the fix tasks JSON array
|
|
178
|
+
echo "$FIX_TASKS"
|
|
179
|
+
exit 0
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# extract-task.sh - Extract single task from implementation plan
|
|
4
|
+
#
|
|
5
|
+
# Usage: extract-task.sh <plan-path> <task-id>
|
|
6
|
+
#
|
|
7
|
+
# Output: Just the task section from the plan, not the full document.
|
|
8
|
+
# This reduces context by ~90% when delegating tasks.
|
|
9
|
+
#
|
|
10
|
+
# Examples:
|
|
11
|
+
# extract-task.sh docs/plans/2026-01-05-auth.md 001
|
|
12
|
+
# extract-task.sh docs/plans/2026-01-05-auth.md A1
|
|
13
|
+
#
|
|
14
|
+
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
PLAN="${1:-}"
|
|
18
|
+
TASK_ID="${2:-}"
|
|
19
|
+
|
|
20
|
+
if [ -z "$PLAN" ] || [ -z "$TASK_ID" ]; then
|
|
21
|
+
echo "Usage: extract-task.sh <plan-path> <task-id>" >&2
|
|
22
|
+
exit 1
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
if [ ! -f "$PLAN" ]; then
|
|
26
|
+
echo "ERROR: Plan file not found: $PLAN" >&2
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# Extract task section using awk
|
|
31
|
+
# Matches: ### Task 001, ### Task A1, ### Task 1:, etc.
|
|
32
|
+
# Stops at next task header or major section header
|
|
33
|
+
|
|
34
|
+
awk -v task_id="$TASK_ID" '
|
|
35
|
+
BEGIN {
|
|
36
|
+
found = 0
|
|
37
|
+
# Build pattern to match task header
|
|
38
|
+
# Handles: "### Task 001:", "### Task A1:", "## Task 1", etc.
|
|
39
|
+
pattern = "^##+ *Task *" task_id "([: ]|$)"
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
# Start capturing when we find the task
|
|
43
|
+
$0 ~ pattern {
|
|
44
|
+
found = 1
|
|
45
|
+
print
|
|
46
|
+
next
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# Stop at next task or major section
|
|
50
|
+
found && /^##+ *(Task [0-9A-Za-z]+|[A-Z])/ {
|
|
51
|
+
exit
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# Print while capturing
|
|
55
|
+
found {
|
|
56
|
+
print
|
|
57
|
+
}
|
|
58
|
+
' "$PLAN"
|
|
59
|
+
|
|
60
|
+
# Check if we found anything
|
|
61
|
+
if ! grep -qE "^##+ *Task *$TASK_ID([: ]|$)" "$PLAN"; then
|
|
62
|
+
echo "WARNING: Task $TASK_ID not found in $PLAN" >&2
|
|
63
|
+
echo "" >&2
|
|
64
|
+
echo "Available tasks:" >&2
|
|
65
|
+
grep -E "^##+ *Task " "$PLAN" | head -20 >&2
|
|
66
|
+
exit 1
|
|
67
|
+
fi
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Generate Traceability Matrix
|
|
3
|
+
# Pre-populate traceability matrix from design and plan headers.
|
|
4
|
+
#
|
|
5
|
+
# Usage: generate-traceability.sh --design-file <path> --plan-file <path> [--output <path>]
|
|
6
|
+
#
|
|
7
|
+
# Exit codes:
|
|
8
|
+
# 0 = generated successfully
|
|
9
|
+
# 1 = parse error (no sections found)
|
|
10
|
+
# 2 = usage error (missing required args, missing files)
|
|
11
|
+
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
15
|
+
|
|
16
|
+
# Colors
|
|
17
|
+
RED='\033[0;31m'
|
|
18
|
+
GREEN='\033[0;32m'
|
|
19
|
+
YELLOW='\033[1;33m'
|
|
20
|
+
NC='\033[0m'
|
|
21
|
+
|
|
22
|
+
# ============================================================
|
|
23
|
+
# ARGUMENT PARSING
|
|
24
|
+
# ============================================================
|
|
25
|
+
|
|
26
|
+
DESIGN_FILE=""
|
|
27
|
+
PLAN_FILE=""
|
|
28
|
+
OUTPUT_FILE=""
|
|
29
|
+
|
|
30
|
+
usage() {
|
|
31
|
+
cat << 'USAGE'
|
|
32
|
+
Usage: generate-traceability.sh --design-file <path> --plan-file <path> [--output <path>]
|
|
33
|
+
|
|
34
|
+
Required:
|
|
35
|
+
--design-file <path> Path to the design document markdown file
|
|
36
|
+
--plan-file <path> Path to the implementation plan markdown file
|
|
37
|
+
|
|
38
|
+
Optional:
|
|
39
|
+
--output <path> Write output to file instead of stdout
|
|
40
|
+
--help Show this help message
|
|
41
|
+
|
|
42
|
+
Exit codes:
|
|
43
|
+
0 Generated successfully
|
|
44
|
+
1 Parse error (no sections found in design)
|
|
45
|
+
2 Usage error (missing required args, missing files)
|
|
46
|
+
USAGE
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
while [[ $# -gt 0 ]]; do
|
|
50
|
+
case "$1" in
|
|
51
|
+
--design-file)
|
|
52
|
+
if [[ -z "${2:-}" ]]; then
|
|
53
|
+
echo "Error: --design-file requires a path argument" >&2
|
|
54
|
+
exit 2
|
|
55
|
+
fi
|
|
56
|
+
DESIGN_FILE="$2"
|
|
57
|
+
shift 2
|
|
58
|
+
;;
|
|
59
|
+
--plan-file)
|
|
60
|
+
if [[ -z "${2:-}" ]]; then
|
|
61
|
+
echo "Error: --plan-file requires a path argument" >&2
|
|
62
|
+
exit 2
|
|
63
|
+
fi
|
|
64
|
+
PLAN_FILE="$2"
|
|
65
|
+
shift 2
|
|
66
|
+
;;
|
|
67
|
+
--output)
|
|
68
|
+
if [[ -z "${2:-}" ]]; then
|
|
69
|
+
echo "Error: --output requires a path argument" >&2
|
|
70
|
+
exit 2
|
|
71
|
+
fi
|
|
72
|
+
OUTPUT_FILE="$2"
|
|
73
|
+
shift 2
|
|
74
|
+
;;
|
|
75
|
+
--help)
|
|
76
|
+
usage
|
|
77
|
+
exit 0
|
|
78
|
+
;;
|
|
79
|
+
*)
|
|
80
|
+
echo "Error: Unknown argument '$1'" >&2
|
|
81
|
+
usage >&2
|
|
82
|
+
exit 2
|
|
83
|
+
;;
|
|
84
|
+
esac
|
|
85
|
+
done
|
|
86
|
+
|
|
87
|
+
if [[ -z "$DESIGN_FILE" || -z "$PLAN_FILE" ]]; then
|
|
88
|
+
echo "Error: --design-file and --plan-file are required" >&2
|
|
89
|
+
usage >&2
|
|
90
|
+
exit 2
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
if [[ ! -f "$DESIGN_FILE" ]]; then
|
|
94
|
+
echo "Error: Design file not found: $DESIGN_FILE" >&2
|
|
95
|
+
exit 2
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
if [[ ! -f "$PLAN_FILE" ]]; then
|
|
99
|
+
echo "Error: Plan file not found: $PLAN_FILE" >&2
|
|
100
|
+
exit 2
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
# ============================================================
|
|
104
|
+
# EXTRACT DESIGN SECTIONS (## and ### headers)
|
|
105
|
+
# ============================================================
|
|
106
|
+
|
|
107
|
+
DESIGN_SECTIONS=()
|
|
108
|
+
DESIGN_LEVELS=()
|
|
109
|
+
|
|
110
|
+
while IFS= read -r line; do
|
|
111
|
+
if [[ "$line" =~ ^(#{2,3})[[:space:]]+(.+) ]]; then
|
|
112
|
+
level="${BASH_REMATCH[1]}"
|
|
113
|
+
section_name="${BASH_REMATCH[2]}"
|
|
114
|
+
section_name="$(echo "$section_name" | sed 's/[[:space:]]*$//')"
|
|
115
|
+
DESIGN_SECTIONS+=("$section_name")
|
|
116
|
+
DESIGN_LEVELS+=("$level")
|
|
117
|
+
fi
|
|
118
|
+
done < "$DESIGN_FILE"
|
|
119
|
+
|
|
120
|
+
if [[ ${#DESIGN_SECTIONS[@]} -eq 0 ]]; then
|
|
121
|
+
echo "Error: No ## or ### headers found in design document" >&2
|
|
122
|
+
exit 1
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
# ============================================================
|
|
126
|
+
# EXTRACT PLAN TASKS (### Task headers)
|
|
127
|
+
# ============================================================
|
|
128
|
+
|
|
129
|
+
PLAN_TASKS=()
|
|
130
|
+
PLAN_TASK_IDS=()
|
|
131
|
+
|
|
132
|
+
while IFS= read -r line; do
|
|
133
|
+
if [[ "$line" =~ ^###[[:space:]]+Task[[:space:]]+([0-9]+) ]]; then
|
|
134
|
+
task_id="${BASH_REMATCH[1]}"
|
|
135
|
+
# Extract the full task title
|
|
136
|
+
task_title="${line#*: }"
|
|
137
|
+
if [[ -n "$task_title" && "$task_title" != "$line" ]]; then
|
|
138
|
+
PLAN_TASKS+=("$task_title")
|
|
139
|
+
else
|
|
140
|
+
PLAN_TASKS+=("$line")
|
|
141
|
+
fi
|
|
142
|
+
PLAN_TASK_IDS+=("$task_id")
|
|
143
|
+
fi
|
|
144
|
+
done < "$PLAN_FILE"
|
|
145
|
+
|
|
146
|
+
# Read full plan content for matching
|
|
147
|
+
PLAN_CONTENT="$(cat "$PLAN_FILE")"
|
|
148
|
+
|
|
149
|
+
# ============================================================
|
|
150
|
+
# GENERATE TRACEABILITY TABLE
|
|
151
|
+
# ============================================================
|
|
152
|
+
|
|
153
|
+
generate_table() {
|
|
154
|
+
echo "## Spec Traceability"
|
|
155
|
+
echo ""
|
|
156
|
+
echo "### Traceability Matrix"
|
|
157
|
+
echo ""
|
|
158
|
+
echo "| Design Section | Key Requirements | Task ID(s) | Status |"
|
|
159
|
+
echo "|----------------|-----------------|------------|--------|"
|
|
160
|
+
|
|
161
|
+
for i in "${!DESIGN_SECTIONS[@]}"; do
|
|
162
|
+
section="${DESIGN_SECTIONS[$i]}"
|
|
163
|
+
level="${DESIGN_LEVELS[$i]}"
|
|
164
|
+
|
|
165
|
+
# Find matching tasks
|
|
166
|
+
matched_ids=()
|
|
167
|
+
for j in "${!PLAN_TASKS[@]}"; do
|
|
168
|
+
task="${PLAN_TASKS[$j]}"
|
|
169
|
+
tid="${PLAN_TASK_IDS[$j]}"
|
|
170
|
+
if echo "$task" | grep -qiF "$section"; then
|
|
171
|
+
matched_ids+=("$tid")
|
|
172
|
+
fi
|
|
173
|
+
done
|
|
174
|
+
|
|
175
|
+
# Also check plan body
|
|
176
|
+
if [[ ${#matched_ids[@]} -eq 0 ]]; then
|
|
177
|
+
if echo "$PLAN_CONTENT" | grep -qiF "$section"; then
|
|
178
|
+
matched_ids+=("?")
|
|
179
|
+
fi
|
|
180
|
+
fi
|
|
181
|
+
|
|
182
|
+
# Format output
|
|
183
|
+
if [[ ${#matched_ids[@]} -gt 0 ]]; then
|
|
184
|
+
ids="$(printf '%s, ' "${matched_ids[@]}")"
|
|
185
|
+
ids="${ids%, }"
|
|
186
|
+
echo "| $section | (to be filled) | $ids | Covered |"
|
|
187
|
+
else
|
|
188
|
+
echo "| $section | (to be filled) | — | Uncovered |"
|
|
189
|
+
fi
|
|
190
|
+
done
|
|
191
|
+
echo ""
|
|
192
|
+
echo "### Scope Declaration"
|
|
193
|
+
echo ""
|
|
194
|
+
echo "**Target:** (to be filled)"
|
|
195
|
+
echo "**Excluded:** (to be filled)"
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
# ============================================================
|
|
199
|
+
# OUTPUT
|
|
200
|
+
# ============================================================
|
|
201
|
+
|
|
202
|
+
if [[ -n "$OUTPUT_FILE" ]]; then
|
|
203
|
+
generate_table > "$OUTPUT_FILE"
|
|
204
|
+
echo "Traceability matrix written to: $OUTPUT_FILE"
|
|
205
|
+
else
|
|
206
|
+
generate_table
|
|
207
|
+
fi
|
|
208
|
+
|
|
209
|
+
exit 0
|