@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.
Files changed (153) hide show
  1. package/.claude-plugin/marketplace.json +22 -0
  2. package/.claude-plugin/plugin.json +17 -0
  3. package/.mcp.json +17 -0
  4. package/AGENTS.md +59 -0
  5. package/CLAUDE.md.template +62 -0
  6. package/LICENSE +202 -0
  7. package/README.md +258 -0
  8. package/commands/autocompact.md +37 -0
  9. package/commands/checkpoint.md +85 -0
  10. package/commands/cleanup.md +99 -0
  11. package/commands/debug.md +145 -0
  12. package/commands/delegate.md +56 -0
  13. package/commands/ideate.md +82 -0
  14. package/commands/plan.md +150 -0
  15. package/commands/refactor.md +139 -0
  16. package/commands/reload.md +37 -0
  17. package/commands/resume.md +130 -0
  18. package/commands/review.md +51 -0
  19. package/commands/sync-schemas.md +74 -0
  20. package/commands/synthesize.md +122 -0
  21. package/commands/tdd.md +58 -0
  22. package/dist/exarchos-cli.js +8828 -0
  23. package/dist/exarchos-mcp.js +50 -0
  24. package/hooks/hooks.json +53 -0
  25. package/package.json +59 -0
  26. package/rules/coding-standards.md +46 -0
  27. package/rules/mcp-tool-guidance.md +26 -0
  28. package/rules/pr-descriptions.md +12 -0
  29. package/rules/rm-safety.md +9 -0
  30. package/rules/skill-path-resolution.md +10 -0
  31. package/rules/tdd.md +41 -0
  32. package/rules/telemetry-awareness.md +9 -0
  33. package/scripts/assess-refactor-scope.sh +239 -0
  34. package/scripts/check-benchmark-regression.sh +229 -0
  35. package/scripts/check-coderabbit.sh +288 -0
  36. package/scripts/check-coverage-thresholds.sh +194 -0
  37. package/scripts/check-polish-scope.sh +245 -0
  38. package/scripts/check-property-tests.sh +167 -0
  39. package/scripts/check-tdd-compliance.sh +265 -0
  40. package/scripts/coderabbit-review-gate.sh +518 -0
  41. package/scripts/debug-review-gate.sh +201 -0
  42. package/scripts/extract-fix-tasks.sh +179 -0
  43. package/scripts/extract-task.sh +67 -0
  44. package/scripts/generate-traceability.sh +209 -0
  45. package/scripts/investigation-timer.sh +171 -0
  46. package/scripts/needs-schema-sync.sh +174 -0
  47. package/scripts/new-project.sh +103 -0
  48. package/scripts/post-delegation-check.sh +317 -0
  49. package/scripts/pre-synthesis-check.sh +440 -0
  50. package/scripts/reconcile-state.sh +346 -0
  51. package/scripts/reconstruct-stack.sh +432 -0
  52. package/scripts/review-diff.sh +63 -0
  53. package/scripts/review-verdict.sh +169 -0
  54. package/scripts/security-scan.sh +248 -0
  55. package/scripts/select-debug-track.sh +186 -0
  56. package/scripts/setup-worktree.sh +323 -0
  57. package/scripts/spec-coverage-check.sh +230 -0
  58. package/scripts/static-analysis-gate.sh +236 -0
  59. package/scripts/sync-labels.sh +122 -0
  60. package/scripts/validate-companion.sh +161 -0
  61. package/scripts/validate-dotnet-standards.sh +267 -0
  62. package/scripts/validate-installation.sh +101 -0
  63. package/scripts/validate-plugin.sh +223 -0
  64. package/scripts/validate-refactor.sh +234 -0
  65. package/scripts/validate-rm.sh +93 -0
  66. package/scripts/verify-delegation-saga.sh +240 -0
  67. package/scripts/verify-doc-links.sh +211 -0
  68. package/scripts/verify-ideate-artifacts.sh +296 -0
  69. package/scripts/verify-plan-coverage.sh +228 -0
  70. package/scripts/verify-review-triage.sh +219 -0
  71. package/scripts/verify-worktree-baseline.sh +159 -0
  72. package/scripts/verify-worktree.sh +84 -0
  73. package/settings.json +47 -0
  74. package/skills/brainstorming/SKILL.md +127 -0
  75. package/skills/brainstorming/references/design-template.md +65 -0
  76. package/skills/cleanup/SKILL.md +147 -0
  77. package/skills/cleanup/references/merge-verification.md +40 -0
  78. package/skills/debug/SKILL.md +204 -0
  79. package/skills/debug/references/hotfix-track.md +134 -0
  80. package/skills/debug/references/investigation-checklist.md +217 -0
  81. package/skills/debug/references/rca-template.md +150 -0
  82. package/skills/debug/references/state-schema.md +294 -0
  83. package/skills/debug/references/thorough-track.md +194 -0
  84. package/skills/debug/references/triage-questions.md +155 -0
  85. package/skills/debug/references/troubleshooting.md +47 -0
  86. package/skills/delegation/SKILL.md +150 -0
  87. package/skills/delegation/references/adaptive-orchestration.md +31 -0
  88. package/skills/delegation/references/agent-teams-saga.md +248 -0
  89. package/skills/delegation/references/fix-mode.md +74 -0
  90. package/skills/delegation/references/fixer-prompt.md +162 -0
  91. package/skills/delegation/references/implementer-prompt.md +322 -0
  92. package/skills/delegation/references/parallel-strategy.md +124 -0
  93. package/skills/delegation/references/pbt-patterns.md +172 -0
  94. package/skills/delegation/references/pr-fixes-mode.md +154 -0
  95. package/skills/delegation/references/state-management.md +51 -0
  96. package/skills/delegation/references/testing-patterns.md +129 -0
  97. package/skills/delegation/references/troubleshooting.md +33 -0
  98. package/skills/delegation/references/workflow-steps.md +127 -0
  99. package/skills/delegation/references/worktree-enforcement.md +64 -0
  100. package/skills/dotnet-standards/SKILL.md +269 -0
  101. package/skills/dotnet-standards/references/csharp-standards.md +120 -0
  102. package/skills/dotnet-standards/templates/.editorconfig +366 -0
  103. package/skills/dotnet-standards/templates/Directory.Build.props +56 -0
  104. package/skills/dotnet-standards/templates/Directory.Packages.props +69 -0
  105. package/skills/dotnet-standards/templates/global.json +6 -0
  106. package/skills/dotnet-standards/templates/nuget.config +9 -0
  107. package/skills/dotnet-standards/templates/stylecop.json +37 -0
  108. package/skills/git-worktrees/SKILL.md +255 -0
  109. package/skills/implementation-planning/SKILL.md +233 -0
  110. package/skills/implementation-planning/references/plan-document-template.md +42 -0
  111. package/skills/implementation-planning/references/spec-tracing-guide.md +51 -0
  112. package/skills/implementation-planning/references/task-template.md +43 -0
  113. package/skills/implementation-planning/references/testing-strategy-guide.md +88 -0
  114. package/skills/quality-review/SKILL.md +278 -0
  115. package/skills/quality-review/references/code-quality-checklist.md +159 -0
  116. package/skills/quality-review/references/review-report-template.md +65 -0
  117. package/skills/quality-review/references/security-checklist.md +79 -0
  118. package/skills/quality-review/references/typescript-standards.md +24 -0
  119. package/skills/refactor/COMMAND.md +67 -0
  120. package/skills/refactor/SKILL.md +198 -0
  121. package/skills/refactor/phases/auto-chain.md +262 -0
  122. package/skills/refactor/phases/brief.md +176 -0
  123. package/skills/refactor/phases/explore.md +132 -0
  124. package/skills/refactor/phases/overhaul-delegate.md +136 -0
  125. package/skills/refactor/phases/overhaul-plan.md +312 -0
  126. package/skills/refactor/phases/overhaul-review.md +304 -0
  127. package/skills/refactor/phases/polish-implement.md +349 -0
  128. package/skills/refactor/phases/polish-validate.md +218 -0
  129. package/skills/refactor/phases/update-docs.md +234 -0
  130. package/skills/refactor/references/brief-template.md +81 -0
  131. package/skills/refactor/references/doc-update-checklist.md +110 -0
  132. package/skills/refactor/references/explore-checklist.md +73 -0
  133. package/skills/refactor/references/overhaul-track.md +215 -0
  134. package/skills/refactor/references/polish-track.md +170 -0
  135. package/skills/shared/prompts/context-reading.md +58 -0
  136. package/skills/shared/prompts/report-format.md +54 -0
  137. package/skills/shared/prompts/tdd-requirements.md +39 -0
  138. package/skills/shepherd/SKILL.md +264 -0
  139. package/skills/shepherd/references/assess-checklist.md +124 -0
  140. package/skills/shepherd/references/fix-strategies.md +191 -0
  141. package/skills/spec-review/SKILL.md +229 -0
  142. package/skills/spec-review/references/review-checklist.md +60 -0
  143. package/skills/sync-schemas/SKILL.md +114 -0
  144. package/skills/sync-schemas/references/configuration.md +73 -0
  145. package/skills/synthesis/SKILL.md +129 -0
  146. package/skills/synthesis/references/pr-descriptions.md +87 -0
  147. package/skills/synthesis/references/synthesis-steps.md +109 -0
  148. package/skills/synthesis/references/troubleshooting.md +115 -0
  149. package/skills/validate-all-skills.sh +57 -0
  150. package/skills/validate-frontmatter.sh +237 -0
  151. package/skills/workflow-state/SKILL.md +210 -0
  152. package/skills/workflow-state/references/mcp-tool-reference.md +111 -0
  153. package/skills/workflow-state/references/phase-transitions.md +141 -0
@@ -0,0 +1,109 @@
1
+ ---
2
+ name: synthesis-steps
3
+ ---
4
+
5
+ # Synthesis Process
6
+
7
+ ## Step 1: Verify Readiness
8
+
9
+ Run the pre-synthesis readiness check:
10
+ ```bash
11
+ scripts/pre-synthesis-check.sh \
12
+ --state-file ~/.claude/workflow-state/<featureId>.state.json \
13
+ --repo-root <repo-root>
14
+ ```
15
+
16
+ The script validates all readiness conditions:
17
+ - All delegated tasks complete (from state file)
18
+ - All reviews passed (from state file)
19
+ - No outstanding fix requests (from state file)
20
+ - Graphite stack branches exist (`gt log`)
21
+ - All tests pass (`npm run test:run && npm run typecheck`)
22
+
23
+ **On exit 0:** All checks passed -- proceed to Step 2.
24
+ **On exit 1:** Output identifies the failing check. Return to `/exarchos:review` or `/exarchos:delegate` as appropriate.
25
+
26
+ Use `--skip-tests` if tests were already verified in review phase. Use `--skip-stack` to defer stack check to Step 2.
27
+
28
+ ## Step 2: Verify and Reconstruct Graphite Stack
29
+
30
+ Run the stack reconstruction script to detect and fix any broken stack state:
31
+ ```bash
32
+ scripts/reconstruct-stack.sh \
33
+ --repo-root <repo-root> \
34
+ --state-file ~/.claude/workflow-state/<featureId>.state.json
35
+ ```
36
+
37
+ The script has three phases:
38
+ 1. **Detection** -- Parses `gt log` for diverged branches, restack markers, or missing task branches
39
+ 2. **Reconstruction** -- If issues detected: resets branch pointers, removes blocking worktrees, re-tracks with correct parent chain
40
+ 3. **Validation** -- Confirms `gt log` shows a clean stack with correct parent chain
41
+
42
+ **On exit 0:** Stack is healthy (or was successfully reconstructed) -- proceed to Step 3.
43
+ **On exit 1:** Reconstruction failed validation. Manual intervention required -- inspect `gt log` output and resolve conflicts.
44
+
45
+ Use `--dry-run` to preview reconstruction actions without making changes.
46
+
47
+ ## Step 3: Quick Test Verification
48
+
49
+ Run tests from the top of the Graphite stack to confirm everything works:
50
+ ```bash
51
+ npm run test:run
52
+ npm run typecheck
53
+ ```
54
+
55
+ If these fail, return to `/exarchos:review` or `/exarchos:delegate` to resolve.
56
+
57
+ ## Step 4: Check CodeRabbit Review State
58
+
59
+ Get PR numbers from the Graphite stack, then run the CodeRabbit review check:
60
+ ```bash
61
+ # Get PR numbers from gt log
62
+ PR_NUMBERS=$(gt log --short | grep -o '#[0-9]*' | sed 's/#//')
63
+
64
+ # Check CodeRabbit review state
65
+ scripts/check-coderabbit.sh \
66
+ --owner <owner> --repo <repo> \
67
+ $PR_NUMBERS
68
+ ```
69
+
70
+ The script queries GitHub's PR reviews API for each PR, filters for CodeRabbit reviews, and classifies the latest review state.
71
+
72
+ **On exit 0:** All PRs are APPROVED or have no CodeRabbit review -- proceed to Step 5.
73
+ **On exit 1:** At least one PR has CHANGES_REQUESTED or PENDING. The output identifies which PRs need attention. Route to fix cycle:
74
+ ```typescript
75
+ Skill({ skill: "exarchos:delegate", args: "--pr-fixes [PR_URL]" })
76
+ ```
77
+ After fixes are applied, return to Step 4 to re-check.
78
+
79
+ ## Step 5: Submit Stack to Merge Queue
80
+
81
+ Enqueue the stack for merging (PRs already exist from delegation):
82
+
83
+ ```
84
+ mcp__graphite__run_gt_cmd({
85
+ args: ["submit", "--no-interactive", "--publish", "--merge-when-ready"],
86
+ cwd: "<repo-root>",
87
+ why: "Enqueue stacked PRs in merge queue after review gates pass"
88
+ })
89
+ ```
90
+
91
+ After submission, use `mcp__graphite__run_gt_cmd` with `["log", "--short"]` to get the PR URLs for each stack entry.
92
+
93
+ ## Step 6: Cleanup After Merge
94
+
95
+ After PRs are merged, use Graphite to clean up:
96
+ ```
97
+ mcp__graphite__run_gt_cmd({
98
+ args: ["sync"],
99
+ cwd: "<repo-root>",
100
+ why: "Pull latest trunk, clean up merged branches"
101
+ })
102
+ ```
103
+
104
+ Then remove worktrees if they exist:
105
+ ```bash
106
+ # Remove worktrees used during delegation
107
+ git worktree list | grep ".worktrees/" | awk '{print $1}' | xargs -I{} git worktree remove {}
108
+ git worktree prune
109
+ ```
@@ -0,0 +1,115 @@
1
+ # Troubleshooting
2
+
3
+ ## Handling Failures
4
+
5
+ ### Test Failure (Unexpected)
6
+
7
+ If tests fail during synthesis (they passed in review):
8
+
9
+ 1. Return to review phase to investigate
10
+ 2. Re-run `/exarchos:review` to diagnose
11
+ 3. Dispatch fixes via `/exarchos:delegate --fixes`
12
+ 4. Return to synthesis after review passes
13
+
14
+ ### PR Checks Fail
15
+
16
+ 1. Wait for CI feedback
17
+ 2. Create fix task for failures
18
+ 3. Push fixes to the stack branches
19
+ 4. Re-run synthesis verification
20
+
21
+ ### Merge Queue Rejection
22
+
23
+ If the merge queue rejects a PR:
24
+ 1. Check CI status via `gh pr checks <number>` (or GitHub MCP `pull_request_read` with method `get_status` if available)
25
+ 2. Fix failing checks
26
+ 3. Push fixes and re-enqueue
27
+
28
+ ## Handling PR Feedback
29
+
30
+ If the user receives PR review comments:
31
+
32
+ 1. Offer to address feedback:
33
+ ```typescript
34
+ Skill({ skill: "exarchos:delegate", args: "--pr-fixes [PR_URL]" })
35
+ ```
36
+
37
+ 2. Delegate reads PR comments via gh CLI:
38
+ ```bash
39
+ gh pr view <number> --json reviews,comments
40
+ ```
41
+ > Or use GitHub MCP `pull_request_read` if available.
42
+
43
+ 3. Creates fix tasks from review comments
44
+ 4. After fixes, amend the stack with `mcp__graphite__run_gt_cmd` using `["modify", "-m", "fix: <description>"]` and resubmit with `["submit", "--no-interactive", "--publish", "--merge-when-ready"]`
45
+ 5. Return to merge confirmation
46
+
47
+ ## Final Report Template
48
+
49
+ ```markdown
50
+ ## Synthesis Complete
51
+
52
+ ### Pull Requests
53
+ [PR URLs from gt log --short]
54
+
55
+ ### Stack Branches
56
+ - task/001-types
57
+ - task/002-api
58
+ - task/003-tests
59
+
60
+ ### Test Results
61
+ - Unit tests: PASS
62
+ - Type check: PASS
63
+ - Lint: PASS
64
+ - Build: PASS
65
+
66
+ ### Next Steps
67
+ 1. Wait for CI/CD checks
68
+ 2. Request code review (if required)
69
+ 3. Merge when approved
70
+ 4. Worktrees will be cleaned up after merge
71
+
72
+ ### Documentation
73
+ - Design: docs/designs/YYYY-MM-DD-feature.md
74
+ - Plan: docs/plans/YYYY-MM-DD-feature.md
75
+ ```
76
+
77
+ ## MCP Tool Call Failed
78
+ If an Exarchos MCP tool returns an error:
79
+ 1. Check the error message -- it usually contains specific guidance
80
+ 2. Verify the workflow state exists: call `mcp__exarchos__exarchos_workflow` with `action: "get"` and the featureId
81
+ 3. If "version mismatch": another process updated state -- retry the operation
82
+ 4. If state is corrupted: call `mcp__exarchos__exarchos_workflow` with `action: "cancel"` and `dryRun: true`
83
+
84
+ ## State Desync
85
+ If workflow state doesn't match git reality:
86
+ 1. The SessionStart hook runs reconciliation automatically on resume
87
+ 2. If manual check needed: compare state file with `git log` and branch state
88
+ 3. Update state via `mcp__exarchos__exarchos_workflow` with `action: "set"` to match git truth
89
+
90
+ ## PR Creation Failed
91
+ If `gt submit` fails:
92
+ 1. Check the error output for specific guidance
93
+ 2. Run `gt log` to verify the stack state
94
+ 3. If rebase conflict: run `gt restack` to resolve
95
+ 4. If authentication issue: check GitHub token permissions
96
+
97
+ ## Stack Rebase Conflict
98
+ If `gt restack` encounters conflicts:
99
+ 1. Resolve conflicts manually in each affected file
100
+ 2. Run `git add <resolved-files>` then `gt continue`
101
+ 3. After resolution, re-run `gt submit --no-interactive --publish --merge-when-ready`
102
+
103
+ ## Exarchos Integration
104
+
105
+ When Exarchos MCP tools are available:
106
+
107
+ 1. **After stack submission:** Call `mcp__exarchos__exarchos_event` with `action: "append"` with event type `stack.enqueued` including PR numbers from `gt log --short`
108
+ 2. **Monitor merge status:** Use `mcp__graphite__run_gt_cmd` with `["log", "--short"]` to check stack/PR status
109
+ 3. **On successful merge:** Call `mcp__exarchos__exarchos_event` with `action: "append"` with event type `phase.transitioned` to mark workflow complete
110
+
111
+ ## Performance Notes
112
+
113
+ - Complete each step fully before advancing -- quality over speed
114
+ - Do not skip validation checks even when the change appears trivial
115
+ - Verify all tests pass before creating PR. Do not skip the pre-submit validation step.
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env bash
2
+ # validate-all-skills.sh — Run frontmatter validation on all SKILL.md files
3
+ #
4
+ # Usage: bash skills/validate-all-skills.sh
5
+ # Must be run from the repository root, or provide SKILLS_DIR env var.
6
+ #
7
+ # Iterates over skills/*/SKILL.md (excluding test-fixtures and shared),
8
+ # extracts folder name, and calls validate-frontmatter.sh for each.
9
+
10
+ set -euo pipefail
11
+
12
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13
+ VALIDATOR="${SCRIPT_DIR}/validate-frontmatter.sh"
14
+ SKILLS_DIR="${SCRIPT_DIR}"
15
+ shopt -s nullglob
16
+
17
+ # Colors
18
+ GREEN='\033[0;32m'
19
+ RED='\033[0;31m'
20
+ RESET='\033[0m'
21
+
22
+ PASS_COUNT=0
23
+ FAIL_COUNT=0
24
+ TOTAL=0
25
+
26
+ for skill_file in "${SKILLS_DIR}"/*/SKILL.md; do
27
+ folder_path=$(dirname "$skill_file")
28
+ folder_name=$(basename "$folder_path")
29
+
30
+ # Skip test fixtures and shared
31
+ if [[ "$folder_name" == "test-fixtures" || "$folder_name" == "shared" ]]; then
32
+ continue
33
+ fi
34
+
35
+ TOTAL=$((TOTAL + 1))
36
+
37
+ validation_output=""
38
+ validation_output=$("$VALIDATOR" "$skill_file" "$folder_name" 2>&1) && validation_exit=0 || validation_exit=$?
39
+
40
+ if [[ "$validation_exit" -eq 0 ]]; then
41
+ PASS_COUNT=$((PASS_COUNT + 1))
42
+ printf "%b" "Validating $(printf '%-30s' "${folder_name}...") ${GREEN}PASS${RESET}\n"
43
+ else
44
+ FAIL_COUNT=$((FAIL_COUNT + 1))
45
+ # Extract the first error for the summary line
46
+ first_error=$(echo "$validation_output" | head -n 1 | sed 's/^ERROR: //')
47
+ printf "%b" "Validating $(printf '%-30s' "${folder_name}...") ${RED}FAIL${RESET} (${first_error})\n"
48
+ fi
49
+ done
50
+
51
+ echo ""
52
+ echo "=== Results: ${PASS_COUNT}/${TOTAL} skills passed ==="
53
+
54
+ if [[ "$FAIL_COUNT" -gt 0 ]]; then
55
+ exit 1
56
+ fi
57
+ exit 0
@@ -0,0 +1,237 @@
1
+ #!/usr/bin/env bash
2
+ # validate-frontmatter.sh — Validate YAML frontmatter in SKILL.md files
3
+ #
4
+ # Usage: validate-frontmatter.sh <path-to-SKILL.md> <expected-folder-name>
5
+ #
6
+ # Runs all checks, collects errors, exits 0 if clean or 1 if any errors found.
7
+ # Designed for macOS compatibility (no GNU-specific tools).
8
+
9
+ set -euo pipefail
10
+
11
+ SKILL_FILE="${1:-}"
12
+ EXPECTED_FOLDER="${2:-}"
13
+
14
+ if [[ -z "$SKILL_FILE" || -z "$EXPECTED_FOLDER" ]]; then
15
+ echo "Usage: validate-frontmatter.sh <path-to-SKILL.md> <expected-folder-name>"
16
+ exit 2
17
+ fi
18
+
19
+ if [[ ! -f "$SKILL_FILE" ]]; then
20
+ echo "ERROR: File not found: $SKILL_FILE"
21
+ exit 2
22
+ fi
23
+
24
+ ERRORS=()
25
+ FRONTMATTER=""
26
+ BODY=""
27
+
28
+ # ---------------------------------------------------------------------------
29
+ # check_frontmatter_exists
30
+ # Verify file starts with --- and has a closing ---.
31
+ # Extract frontmatter between delimiters and body after closing delimiter.
32
+ # ---------------------------------------------------------------------------
33
+ check_frontmatter_exists() {
34
+ local first_line
35
+ first_line=$(head -n 1 "$SKILL_FILE")
36
+
37
+ if [[ "$first_line" != "---" ]]; then
38
+ ERRORS+=("check_frontmatter_exists: Missing opening --- delimiter")
39
+ return
40
+ fi
41
+
42
+ # Find the closing --- (second occurrence, so line number > 1)
43
+ local closing_line=0
44
+ local line_num=0
45
+ while IFS= read -r line; do
46
+ line_num=$((line_num + 1))
47
+ if [[ "$line_num" -gt 1 && "$line" == "---" ]]; then
48
+ closing_line=$line_num
49
+ break
50
+ fi
51
+ done < "$SKILL_FILE"
52
+
53
+ if [[ "$closing_line" -eq 0 ]]; then
54
+ ERRORS+=("check_frontmatter_exists: Missing closing --- delimiter")
55
+ return
56
+ fi
57
+
58
+ # Extract frontmatter (between line 2 and closing_line - 1)
59
+ local fm_start=2
60
+ local fm_end=$((closing_line - 1))
61
+ FRONTMATTER=$(sed -n "${fm_start},${fm_end}p" "$SKILL_FILE")
62
+
63
+ # Extract body (everything after closing delimiter)
64
+ local body_start=$((closing_line + 1))
65
+ local total_lines
66
+ total_lines=$(awk 'END {print NR}' "$SKILL_FILE")
67
+ if [[ "$body_start" -le "$total_lines" ]]; then
68
+ BODY=$(tail -n +"$body_start" "$SKILL_FILE")
69
+ else
70
+ BODY=""
71
+ fi
72
+ }
73
+
74
+ # ---------------------------------------------------------------------------
75
+ # check_required_fields
76
+ # Verify name: and description: are present in the frontmatter.
77
+ # ---------------------------------------------------------------------------
78
+ check_required_fields() {
79
+ if [[ -z "$FRONTMATTER" ]]; then
80
+ return
81
+ fi
82
+
83
+ if ! echo "$FRONTMATTER" | grep -q '^name:'; then
84
+ ERRORS+=("check_required_fields: Missing required field 'name'")
85
+ fi
86
+
87
+ if ! echo "$FRONTMATTER" | grep -q '^description:'; then
88
+ ERRORS+=("check_required_fields: Missing required field 'description'")
89
+ fi
90
+ }
91
+
92
+ # ---------------------------------------------------------------------------
93
+ # check_name_matches_folder
94
+ # Verify the name: value matches the expected folder name (kebab-case).
95
+ # ---------------------------------------------------------------------------
96
+ check_name_matches_folder() {
97
+ if [[ -z "$FRONTMATTER" ]]; then
98
+ return
99
+ fi
100
+
101
+ local name_value
102
+ name_value=$(echo "$FRONTMATTER" | grep '^name:' | sed 's/^name:[[:space:]]*//' | tr -d '"' | tr -d "'" || true)
103
+
104
+ if [[ -z "$name_value" ]]; then
105
+ return # Already caught by check_required_fields
106
+ fi
107
+
108
+ if [[ "$name_value" != "$EXPECTED_FOLDER" ]]; then
109
+ ERRORS+=("check_name_matches_folder: Name '${name_value}' does not match folder '${EXPECTED_FOLDER}'")
110
+ fi
111
+ }
112
+
113
+ # ---------------------------------------------------------------------------
114
+ # check_no_xml_tags
115
+ # Verify the frontmatter section contains no < or > characters.
116
+ # ---------------------------------------------------------------------------
117
+ check_no_xml_tags() {
118
+ if [[ -z "$FRONTMATTER" ]]; then
119
+ return
120
+ fi
121
+
122
+ if echo "$FRONTMATTER" | grep -q '[<>]'; then
123
+ ERRORS+=("check_no_xml_tags: Frontmatter contains '<' or '>' characters (breaks Claude Code parsing)")
124
+ fi
125
+ }
126
+
127
+ # ---------------------------------------------------------------------------
128
+ # check_word_count
129
+ # Count words in the body and verify <= 2000 words.
130
+ # ---------------------------------------------------------------------------
131
+ check_word_count() {
132
+ if [[ -z "$BODY" ]]; then
133
+ return
134
+ fi
135
+
136
+ local word_count
137
+ word_count=$(echo "$BODY" | wc -w | tr -d ' ')
138
+
139
+ if [[ "$word_count" -gt 2000 ]]; then
140
+ ERRORS+=("check_word_count: Body has ${word_count} words (limit: 2000)")
141
+ fi
142
+ }
143
+
144
+ # ---------------------------------------------------------------------------
145
+ # check_references_exist
146
+ # Find all references/*.md patterns in the body and verify each file exists
147
+ # relative to the SKILL.md's parent directory.
148
+ # ---------------------------------------------------------------------------
149
+ check_references_exist() {
150
+ if [[ -z "$BODY" ]]; then
151
+ return
152
+ fi
153
+
154
+ local skill_dir
155
+ skill_dir=$(dirname "$SKILL_FILE")
156
+
157
+ # Find all references/*.md patterns in the body
158
+ local refs
159
+ refs=$(echo "$BODY" | grep -oE 'references/[^)[:space:]"]+\.md' || true)
160
+
161
+ if [[ -z "$refs" ]]; then
162
+ return
163
+ fi
164
+
165
+ while IFS= read -r ref; do
166
+ if [[ ! -f "${skill_dir}/${ref}" ]]; then
167
+ ERRORS+=("check_references_exist: Referenced file '${ref}' not found relative to $(basename "$skill_dir")/")
168
+ fi
169
+ done <<< "$refs"
170
+ }
171
+
172
+ # ---------------------------------------------------------------------------
173
+ # check_negative_trigger
174
+ # Verify the description contains a negative trigger phrase
175
+ # (e.g., "Do NOT" or "Not for") to help Claude Code disambiguate skills.
176
+ # ---------------------------------------------------------------------------
177
+ check_negative_trigger() {
178
+ if [[ -z "$FRONTMATTER" ]]; then
179
+ return
180
+ fi
181
+
182
+ local desc_value
183
+ desc_value=$(echo "$FRONTMATTER" | grep '^description:' | sed 's/^description:[[:space:]]*//' | tr -d '"' | tr -d "'" || true)
184
+
185
+ if [[ -z "$desc_value" ]]; then
186
+ return # Already caught by check_required_fields
187
+ fi
188
+
189
+ if ! echo "$desc_value" | grep -qi 'Do NOT\|Not for'; then
190
+ ERRORS+=("check_negative_trigger: Description lacks a negative trigger phrase (e.g., 'Do NOT ...' or 'Not for ...')")
191
+ fi
192
+ }
193
+
194
+ # ---------------------------------------------------------------------------
195
+ # check_no_orphan_references
196
+ # Verify every .md file in references/ is actually referenced in the body.
197
+ # Only checks .md files (not .sh, .json, etc.).
198
+ # ---------------------------------------------------------------------------
199
+ check_no_orphan_references() {
200
+ local skill_dir
201
+ skill_dir=$(dirname "$SKILL_FILE")
202
+ local refs_dir="${skill_dir}/references"
203
+
204
+ if [[ ! -d "$refs_dir" ]]; then
205
+ return # No references directory — nothing to check
206
+ fi
207
+
208
+ for ref_file in "$refs_dir"/*.md; do
209
+ [[ -f "$ref_file" ]] || continue
210
+ local ref_name="references/$(basename "$ref_file")"
211
+ if ! echo "$BODY" | grep -qF "$ref_name"; then
212
+ ERRORS+=("check_no_orphan_references: File '${ref_name}' exists but is not referenced in SKILL.md")
213
+ fi
214
+ done
215
+ }
216
+
217
+ # ---------------------------------------------------------------------------
218
+ # Main — Run all checks, report errors, exit appropriately
219
+ # ---------------------------------------------------------------------------
220
+
221
+ check_frontmatter_exists
222
+ check_required_fields
223
+ check_name_matches_folder
224
+ check_no_xml_tags
225
+ check_word_count
226
+ check_references_exist
227
+ check_negative_trigger
228
+ check_no_orphan_references
229
+
230
+ if [[ ${#ERRORS[@]} -gt 0 ]]; then
231
+ for err in "${ERRORS[@]}"; do
232
+ echo "ERROR: $err"
233
+ done
234
+ exit 1
235
+ fi
236
+
237
+ exit 0