@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,267 @@
1
+ #!/usr/bin/env bash
2
+ # Validate .NET Standards
3
+ # Checks .NET project structure compliance: required files, CPM configuration,
4
+ # editorconfig, global.json, and no inline package versions.
5
+ #
6
+ # Usage: validate-dotnet-standards.sh --project-root <path>
7
+ #
8
+ # Exit codes:
9
+ # 0 = project is compliant
10
+ # 1 = violations found
11
+ # 2 = usage error (missing required args)
12
+
13
+ set -euo pipefail
14
+
15
+ # ============================================================
16
+ # ARGUMENT PARSING
17
+ # ============================================================
18
+
19
+ PROJECT_ROOT=""
20
+
21
+ usage() {
22
+ cat << 'USAGE'
23
+ Usage: validate-dotnet-standards.sh --project-root <path>
24
+
25
+ Required:
26
+ --project-root <path> Root directory of the .NET project
27
+
28
+ Optional:
29
+ --help Show this help message
30
+
31
+ Exit codes:
32
+ 0 Project is compliant
33
+ 1 Violations found
34
+ 2 Usage error (missing required args)
35
+ USAGE
36
+ }
37
+
38
+ while [[ $# -gt 0 ]]; do
39
+ case "$1" in
40
+ --project-root)
41
+ if [[ -z "${2:-}" ]]; then
42
+ echo "Error: --project-root requires a path argument" >&2
43
+ exit 2
44
+ fi
45
+ PROJECT_ROOT="$2"
46
+ shift 2
47
+ ;;
48
+ --help)
49
+ usage
50
+ exit 0
51
+ ;;
52
+ *)
53
+ echo "Error: Unknown argument '$1'" >&2
54
+ usage >&2
55
+ exit 2
56
+ ;;
57
+ esac
58
+ done
59
+
60
+ if [[ -z "$PROJECT_ROOT" ]]; then
61
+ echo "Error: --project-root is required" >&2
62
+ usage >&2
63
+ exit 2
64
+ fi
65
+
66
+ # ============================================================
67
+ # CHECK FUNCTIONS
68
+ # ============================================================
69
+
70
+ CHECK_PASS=0
71
+ CHECK_FAIL=0
72
+ RESULTS=()
73
+
74
+ check_pass() {
75
+ local name="$1"
76
+ RESULTS+=("- **PASS**: $name")
77
+ CHECK_PASS=$((CHECK_PASS + 1))
78
+ }
79
+
80
+ check_fail() {
81
+ local name="$1"
82
+ local detail="${2:-}"
83
+ if [[ -n "$detail" ]]; then
84
+ RESULTS+=("- **FAIL**: $name — $detail")
85
+ else
86
+ RESULTS+=("- **FAIL**: $name")
87
+ fi
88
+ CHECK_FAIL=$((CHECK_FAIL + 1))
89
+ }
90
+
91
+ # ============================================================
92
+ # CHECK 1: Directory.Build.props exists
93
+ # ============================================================
94
+
95
+ check_build_props() {
96
+ local build_props="$PROJECT_ROOT/src/Directory.Build.props"
97
+ if [[ -f "$build_props" ]]; then
98
+ check_pass "Directory.Build.props exists"
99
+ return 0
100
+ else
101
+ check_fail "Directory.Build.props exists" "Not found at $build_props"
102
+ return 1
103
+ fi
104
+ }
105
+
106
+ # ============================================================
107
+ # CHECK 2: Directory.Packages.props exists
108
+ # ============================================================
109
+
110
+ check_packages_props_exists() {
111
+ local packages_props="$PROJECT_ROOT/src/Directory.Packages.props"
112
+ if [[ -f "$packages_props" ]]; then
113
+ check_pass "Directory.Packages.props exists"
114
+ return 0
115
+ else
116
+ check_fail "Directory.Packages.props exists" "Not found at $packages_props"
117
+ return 1
118
+ fi
119
+ }
120
+
121
+ # ============================================================
122
+ # CHECK 3: CPM is enabled in Directory.Packages.props
123
+ # ============================================================
124
+
125
+ check_cpm_enabled() {
126
+ local packages_props="$PROJECT_ROOT/src/Directory.Packages.props"
127
+
128
+ if [[ ! -f "$packages_props" ]]; then
129
+ # Already reported by check_packages_props_exists
130
+ return 1
131
+ fi
132
+
133
+ if grep -qE '<ManagePackageVersionsCentrally>[[:space:]]*true[[:space:]]*</ManagePackageVersionsCentrally>' "$packages_props"; then
134
+ check_pass "Central Package Management (CPM) enabled"
135
+ return 0
136
+ else
137
+ check_fail "Central Package Management (CPM) enabled" "ManagePackageVersionsCentrally is not set to true in Directory.Packages.props"
138
+ return 1
139
+ fi
140
+ }
141
+
142
+ # ============================================================
143
+ # CHECK 4: .editorconfig exists
144
+ # ============================================================
145
+
146
+ check_editorconfig() {
147
+ local editorconfig="$PROJECT_ROOT/src/.editorconfig"
148
+ if [[ -f "$editorconfig" ]]; then
149
+ check_pass ".editorconfig exists"
150
+ return 0
151
+ else
152
+ check_fail ".editorconfig exists" "Not found at $editorconfig"
153
+ return 1
154
+ fi
155
+ }
156
+
157
+ # ============================================================
158
+ # CHECK 5: global.json exists with SDK version
159
+ # ============================================================
160
+
161
+ check_global_json() {
162
+ local global_json="$PROJECT_ROOT/src/global.json"
163
+
164
+ if [[ ! -f "$global_json" ]]; then
165
+ check_fail "global.json exists" "Not found at $global_json"
166
+ return 1
167
+ fi
168
+
169
+ # Check for sdk.version field
170
+ if command -v jq &>/dev/null; then
171
+ local sdk_version
172
+ if ! sdk_version="$(jq -r '.sdk.version // empty' "$global_json" 2>/dev/null)"; then
173
+ check_fail "global.json valid" "Invalid JSON in $global_json"
174
+ return 1
175
+ fi
176
+ if [[ -n "$sdk_version" ]]; then
177
+ check_pass "global.json exists (SDK $sdk_version)"
178
+ return 0
179
+ else
180
+ check_fail "global.json exists" "File exists but sdk.version is not specified"
181
+ return 1
182
+ fi
183
+ else
184
+ # Fallback: just check file contains "version"
185
+ if grep -q '"version"' "$global_json"; then
186
+ check_pass "global.json exists (with version)"
187
+ return 0
188
+ else
189
+ check_fail "global.json exists" "File exists but no version field found"
190
+ return 1
191
+ fi
192
+ fi
193
+ }
194
+
195
+ # ============================================================
196
+ # CHECK 6: No inline PackageReference with Version in .csproj
197
+ # ============================================================
198
+
199
+ check_no_inline_versions() {
200
+ # Find all .csproj files under src/
201
+ local src_dir="$PROJECT_ROOT/src"
202
+ if [[ ! -d "$src_dir" ]]; then
203
+ check_pass "No inline package versions (no src/ directory)"
204
+ return 0
205
+ fi
206
+
207
+ local violations=()
208
+ while IFS= read -r csproj_file; do
209
+ [[ -z "$csproj_file" ]] && continue
210
+ # Check for PackageReference with Version attribute (but not in Directory.Build.props)
211
+ local basename
212
+ basename="$(basename "$csproj_file")"
213
+ if [[ "$basename" == "Directory.Build.props" || "$basename" == "Directory.Packages.props" ]]; then
214
+ continue
215
+ fi
216
+ if grep -qE '<PackageReference\s+[^>]*Version\s*=' "$csproj_file"; then
217
+ violations+=("$csproj_file")
218
+ fi
219
+ done < <(find "$src_dir" -name '*.csproj' -type f 2>/dev/null)
220
+
221
+ if [[ ${#violations[@]} -eq 0 ]]; then
222
+ check_pass "No inline package versions in .csproj files"
223
+ return 0
224
+ else
225
+ local violation_list
226
+ violation_list="$(printf '%s\n' "${violations[@]}" | sed "s|$PROJECT_ROOT/||g" | tr '\n' ', ' | sed 's/, $//')"
227
+ check_fail "No inline package versions in .csproj files" "Inline Version found in: $violation_list"
228
+ return 1
229
+ fi
230
+ }
231
+
232
+ # ============================================================
233
+ # EXECUTE CHECKS
234
+ # ============================================================
235
+
236
+ check_build_props || true
237
+ check_packages_props_exists || true
238
+ check_cpm_enabled || true
239
+ check_editorconfig || true
240
+ check_global_json || true
241
+ check_no_inline_versions || true
242
+
243
+ # ============================================================
244
+ # STRUCTURED OUTPUT
245
+ # ============================================================
246
+
247
+ echo "## .NET Standards Compliance Report"
248
+ echo ""
249
+ echo "**Project root:** \`$PROJECT_ROOT\`"
250
+ echo ""
251
+
252
+ for result in "${RESULTS[@]}"; do
253
+ echo "$result"
254
+ done
255
+
256
+ echo ""
257
+ TOTAL=$((CHECK_PASS + CHECK_FAIL))
258
+ echo "---"
259
+ echo ""
260
+
261
+ if [[ $CHECK_FAIL -eq 0 ]]; then
262
+ echo "**Result: PASS** ($CHECK_PASS/$TOTAL checks passed)"
263
+ exit 0
264
+ else
265
+ echo "**Result: FAIL** ($CHECK_FAIL/$TOTAL checks failed)"
266
+ exit 1
267
+ fi
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env bash
2
+ # validate-installation.sh — Post-install verification for skills
3
+ #
4
+ # Usage: validate-installation.sh [target-skills-dir]
5
+ # Default target: ~/.claude/skills
6
+ #
7
+ # Verifies:
8
+ # 1. Each skill subdirectory has a SKILL.md file
9
+ # 2. Each SKILL.md passes frontmatter validation
10
+ # 3. references/ directories have matching file counts vs repo source
11
+ #
12
+ # Exit 0 if all pass, exit 1 with error list otherwise.
13
+
14
+ set -euo pipefail
15
+
16
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
17
+ REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
18
+ VALIDATOR="${REPO_ROOT}/skills/validate-frontmatter.sh"
19
+ TARGET_DIR="${1:-${HOME}/.claude/skills}"
20
+
21
+ if [[ ! -d "$TARGET_DIR" ]]; then
22
+ echo "ERROR: Target directory not found: $TARGET_DIR"
23
+ exit 2
24
+ fi
25
+
26
+ if [[ ! -x "$VALIDATOR" ]]; then
27
+ echo "ERROR: Validator script not found or not executable: $VALIDATOR"
28
+ exit 2
29
+ fi
30
+
31
+ ERRORS=()
32
+ PASS_COUNT=0
33
+ TOTAL=0
34
+
35
+ for skill_dir in "$TARGET_DIR"/*/; do
36
+ [[ -d "$skill_dir" ]] || continue
37
+
38
+ # Skip test-fixtures and trigger-tests directories
39
+ local_name=$(basename "$skill_dir")
40
+ if [[ "$local_name" == "test-fixtures" || "$local_name" == "trigger-tests" ]]; then
41
+ continue
42
+ fi
43
+
44
+ TOTAL=$((TOTAL + 1))
45
+ skill_file="${skill_dir}SKILL.md"
46
+
47
+ # Check 1: SKILL.md exists
48
+ if [[ ! -f "$skill_file" ]]; then
49
+ ERRORS+=("${local_name}: Missing SKILL.md")
50
+ continue
51
+ fi
52
+
53
+ # Check 2: Frontmatter validation
54
+ result=""
55
+ rc=0
56
+ result=$("$VALIDATOR" "$skill_file" "$local_name" 2>&1) || rc=$?
57
+
58
+ if [[ $rc -ne 0 ]]; then
59
+ ERRORS+=("${local_name}: Frontmatter validation failed — ${result}")
60
+ continue
61
+ fi
62
+
63
+ PASS_COUNT=$((PASS_COUNT + 1))
64
+
65
+ # Check 3: references/ directory file count matches repo source (if applicable)
66
+ repo_refs="${REPO_ROOT}/skills/${local_name}/references"
67
+ target_refs="${skill_dir}references"
68
+
69
+ if [[ -d "$repo_refs" ]]; then
70
+ if [[ ! -d "$target_refs" ]]; then
71
+ ERRORS+=("${local_name}: Missing references/ directory (repo has one)")
72
+ PASS_COUNT=$((PASS_COUNT - 1))
73
+ else
74
+ repo_count=$(find "$repo_refs" -type f | wc -l | tr -d ' ')
75
+ target_count=$(find "$target_refs" -type f | wc -l | tr -d ' ')
76
+
77
+ if [[ "$repo_count" != "$target_count" ]]; then
78
+ ERRORS+=("${local_name}: references/ file count mismatch (repo: ${repo_count}, installed: ${target_count})")
79
+ PASS_COUNT=$((PASS_COUNT - 1))
80
+ fi
81
+ fi
82
+ fi
83
+ done
84
+
85
+ if [[ $TOTAL -eq 0 ]]; then
86
+ echo "ERROR: No skills found in $TARGET_DIR"
87
+ exit 1
88
+ fi
89
+
90
+ echo "=== Installation Validation: ${PASS_COUNT}/${TOTAL} skills passed ==="
91
+
92
+ if [[ ${#ERRORS[@]} -gt 0 ]]; then
93
+ echo ""
94
+ echo "Errors:"
95
+ for err in "${ERRORS[@]}"; do
96
+ echo " - $err"
97
+ done
98
+ exit 1
99
+ fi
100
+
101
+ exit 0
@@ -0,0 +1,223 @@
1
+ #!/usr/bin/env bash
2
+ # validate-plugin.sh — Validate core plugin directory structure
3
+ #
4
+ # Checks:
5
+ # 1. .claude-plugin/plugin.json exists and valid JSON with required fields
6
+ # 2. Referenced directories exist: commands/, skills/
7
+ # 3. Referenced files exist: hooks/hooks.json, .mcp.json
8
+ # 4. .mcp.json is valid JSON containing exarchos and graphite server entries
9
+ # 5. hooks/hooks.json contains all 6 hook types
10
+ # 6. No {{CLI_PATH}} references in hooks (should use ${CLAUDE_PLUGIN_ROOT})
11
+ #
12
+ # Usage: validate-plugin.sh --repo-root <path>
13
+ #
14
+ # Exit codes:
15
+ # 0 = all checks pass
16
+ # 1 = one or more checks fail
17
+ # 2 = usage error
18
+
19
+ set -euo pipefail
20
+
21
+ # ============================================================
22
+ # ARGUMENT PARSING
23
+ # ============================================================
24
+
25
+ REPO_ROOT="."
26
+
27
+ usage() {
28
+ cat << 'USAGE'
29
+ Usage: validate-plugin.sh --repo-root <path>
30
+
31
+ Validates the core Exarchos plugin directory structure.
32
+
33
+ Options:
34
+ --repo-root <path> Path to the plugin repository root (default: .)
35
+ --help Show this help message
36
+
37
+ Exit codes:
38
+ 0 All checks pass
39
+ 1 One or more checks fail
40
+ 2 Usage error
41
+ USAGE
42
+ }
43
+
44
+ while [[ $# -gt 0 ]]; do
45
+ case "$1" in
46
+ --repo-root)
47
+ if [[ -z "${2:-}" ]]; then
48
+ echo "Error: --repo-root requires a path argument" >&2
49
+ exit 2
50
+ fi
51
+ REPO_ROOT="$2"
52
+ shift 2
53
+ ;;
54
+ --help)
55
+ usage
56
+ exit 0
57
+ ;;
58
+ *)
59
+ echo "Error: Unknown argument '$1'" >&2
60
+ usage >&2
61
+ exit 2
62
+ ;;
63
+ esac
64
+ done
65
+
66
+ if [[ ! -d "$REPO_ROOT" ]]; then
67
+ echo "Error: Repository root not found: $REPO_ROOT" >&2
68
+ exit 2
69
+ fi
70
+
71
+ # ============================================================
72
+ # DEPENDENCY CHECK
73
+ # ============================================================
74
+
75
+ if ! command -v jq &>/dev/null; then
76
+ echo "Error: jq is required but not installed" >&2
77
+ exit 2
78
+ fi
79
+
80
+ # ============================================================
81
+ # VALIDATION
82
+ # ============================================================
83
+
84
+ CHECK_PASS=0
85
+ CHECK_FAIL=0
86
+ TOTAL=0
87
+ RESULTS=()
88
+
89
+ check() {
90
+ local description="$1"
91
+ local passed="$2"
92
+ TOTAL=$((TOTAL + 1))
93
+ if [[ "$passed" == "true" ]]; then
94
+ RESULTS+=("- **PASS**: $description")
95
+ CHECK_PASS=$((CHECK_PASS + 1))
96
+ else
97
+ RESULTS+=("- **FAIL**: $description")
98
+ CHECK_FAIL=$((CHECK_FAIL + 1))
99
+ fi
100
+ }
101
+
102
+ # --- Check 1: .claude-plugin/plugin.json exists and valid JSON with required fields ---
103
+ PLUGIN_JSON="$REPO_ROOT/.claude-plugin/plugin.json"
104
+ if [[ -f "$PLUGIN_JSON" ]] && jq empty "$PLUGIN_JSON" 2>/dev/null; then
105
+ # Verify required fields
106
+ REQUIRED_FIELDS=("name" "version" "commands" "skills" "hooks" "mcpServers")
107
+ ALL_FIELDS_PRESENT=true
108
+ MISSING_FIELDS=()
109
+ for field in "${REQUIRED_FIELDS[@]}"; do
110
+ if ! jq -e ".$field" "$PLUGIN_JSON" >/dev/null 2>&1; then
111
+ ALL_FIELDS_PRESENT=false
112
+ MISSING_FIELDS+=("$field")
113
+ fi
114
+ done
115
+ if [[ "$ALL_FIELDS_PRESENT" == "true" ]]; then
116
+ check ".claude-plugin/plugin.json exists and valid" "true"
117
+ else
118
+ check ".claude-plugin/plugin.json missing fields: ${MISSING_FIELDS[*]}" "false"
119
+ fi
120
+ else
121
+ check ".claude-plugin/plugin.json exists and valid" "false"
122
+ fi
123
+
124
+ # --- Check 2: Referenced directories exist ---
125
+ COMMANDS_DIR="$REPO_ROOT/commands"
126
+ SKILLS_DIR="$REPO_ROOT/skills"
127
+ if [[ -d "$COMMANDS_DIR" ]]; then
128
+ check "commands/ directory exists" "true"
129
+ else
130
+ check "commands/ directory exists" "false"
131
+ fi
132
+
133
+ if [[ -d "$SKILLS_DIR" ]]; then
134
+ check "skills/ directory exists" "true"
135
+ else
136
+ check "skills/ directory exists" "false"
137
+ fi
138
+
139
+ # --- Check 3: Referenced files exist ---
140
+ HOOKS_FILE="$REPO_ROOT/hooks/hooks.json"
141
+ MCP_FILE="$REPO_ROOT/.mcp.json"
142
+
143
+ if [[ -f "$HOOKS_FILE" ]]; then
144
+ check "hooks/hooks.json exists" "true"
145
+ else
146
+ check "hooks/hooks.json exists" "false"
147
+ fi
148
+
149
+ if [[ -f "$MCP_FILE" ]]; then
150
+ check ".mcp.json exists" "true"
151
+ else
152
+ check ".mcp.json exists" "false"
153
+ fi
154
+
155
+ # --- Check 4: .mcp.json is valid JSON with exarchos and graphite entries ---
156
+ if [[ -f "$MCP_FILE" ]] && jq empty "$MCP_FILE" 2>/dev/null; then
157
+ HAS_EXARCHOS=$(jq -e '.mcpServers.exarchos' "$MCP_FILE" >/dev/null 2>&1 && echo "true" || echo "false")
158
+ HAS_GRAPHITE=$(jq -e '.mcpServers.graphite' "$MCP_FILE" >/dev/null 2>&1 && echo "true" || echo "false")
159
+ if [[ "$HAS_EXARCHOS" == "true" && "$HAS_GRAPHITE" == "true" ]]; then
160
+ check ".mcp.json contains exarchos and graphite entries" "true"
161
+ else
162
+ MISSING_SERVERS=()
163
+ [[ "$HAS_EXARCHOS" == "false" ]] && MISSING_SERVERS+=("exarchos")
164
+ [[ "$HAS_GRAPHITE" == "false" ]] && MISSING_SERVERS+=("graphite")
165
+ check ".mcp.json missing server entries: ${MISSING_SERVERS[*]}" "false"
166
+ fi
167
+ else
168
+ check ".mcp.json valid JSON with required entries" "false"
169
+ fi
170
+
171
+ # --- Check 5: hooks/hooks.json contains all 6 hook types ---
172
+ REQUIRED_HOOKS=("PreCompact" "SessionStart" "PreToolUse" "TaskCompleted" "TeammateIdle" "SubagentStart")
173
+ if [[ -f "$HOOKS_FILE" ]] && jq empty "$HOOKS_FILE" 2>/dev/null; then
174
+ ALL_HOOKS_PRESENT=true
175
+ MISSING_HOOKS=()
176
+ for hook in "${REQUIRED_HOOKS[@]}"; do
177
+ if ! jq -e ".hooks.$hook" "$HOOKS_FILE" >/dev/null 2>&1; then
178
+ ALL_HOOKS_PRESENT=false
179
+ MISSING_HOOKS+=("$hook")
180
+ fi
181
+ done
182
+ if [[ "$ALL_HOOKS_PRESENT" == "true" ]]; then
183
+ check "hooks/hooks.json contains all 6 hook types" "true"
184
+ else
185
+ check "hooks/hooks.json missing hook types: ${MISSING_HOOKS[*]}" "false"
186
+ fi
187
+ else
188
+ check "hooks/hooks.json valid JSON with all hook types" "false"
189
+ fi
190
+
191
+ # --- Check 6: No {{CLI_PATH}} references in hooks ---
192
+ if [[ -f "$HOOKS_FILE" ]]; then
193
+ if grep -q '{{CLI_PATH}}' "$HOOKS_FILE" 2>/dev/null; then
194
+ check "No {{CLI_PATH}} references in hooks (should use \${CLAUDE_PLUGIN_ROOT})" "false"
195
+ else
196
+ check "No {{CLI_PATH}} references in hooks" "true"
197
+ fi
198
+ else
199
+ check "No {{CLI_PATH}} references in hooks (hooks file missing)" "false"
200
+ fi
201
+
202
+ # ============================================================
203
+ # STRUCTURED OUTPUT
204
+ # ============================================================
205
+
206
+ echo "## Plugin Validation Report"
207
+ echo ""
208
+
209
+ for result in "${RESULTS[@]}"; do
210
+ echo "$result"
211
+ done
212
+
213
+ echo ""
214
+ echo "---"
215
+ echo ""
216
+
217
+ if [[ $CHECK_FAIL -eq 0 ]]; then
218
+ echo "**Result: PASS** ($CHECK_PASS/$TOTAL checks passed)"
219
+ exit 0
220
+ else
221
+ echo "**Result: FAIL** ($CHECK_PASS/$TOTAL checks passed)"
222
+ exit 1
223
+ fi