@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,236 @@
1
+ #!/usr/bin/env bash
2
+ # Static Analysis Gate
3
+ # Runs static analysis tools with structured pass/fail output for the quality-review workflow.
4
+ #
5
+ # Usage: static-analysis-gate.sh --repo-root <path> [--skip-lint] [--skip-typecheck]
6
+ #
7
+ # Exit codes:
8
+ # 0 = all checks pass (warnings OK)
9
+ # 1 = errors found
10
+ # 2 = usage error
11
+
12
+ set -euo pipefail
13
+
14
+ # ============================================================
15
+ # ARGUMENT PARSING
16
+ # ============================================================
17
+
18
+ REPO_ROOT=""
19
+ SKIP_LINT=false
20
+ SKIP_TYPECHECK=false
21
+
22
+ usage() {
23
+ cat << 'USAGE'
24
+ Usage: static-analysis-gate.sh --repo-root <path> [--skip-lint] [--skip-typecheck]
25
+
26
+ Run static analysis tools with structured pass/fail output.
27
+
28
+ Required:
29
+ --repo-root <path> Repository root containing package.json
30
+
31
+ Optional:
32
+ --skip-lint Skip lint check
33
+ --skip-typecheck Skip typecheck
34
+ --help Show this help message
35
+
36
+ Exit codes:
37
+ 0 All checks pass (warnings OK)
38
+ 1 Errors found in one or more tools
39
+ 2 Usage error (missing required args)
40
+ USAGE
41
+ }
42
+
43
+ while [[ $# -gt 0 ]]; do
44
+ case "$1" in
45
+ --repo-root)
46
+ if [[ -z "${2:-}" ]]; then
47
+ echo "Error: --repo-root requires a path argument" >&2
48
+ exit 2
49
+ fi
50
+ REPO_ROOT="$2"
51
+ shift 2
52
+ ;;
53
+ --skip-lint)
54
+ SKIP_LINT=true
55
+ shift
56
+ ;;
57
+ --skip-typecheck)
58
+ SKIP_TYPECHECK=true
59
+ shift
60
+ ;;
61
+ --help)
62
+ usage
63
+ exit 0
64
+ ;;
65
+ *)
66
+ echo "Error: Unknown argument '$1'" >&2
67
+ usage >&2
68
+ exit 2
69
+ ;;
70
+ esac
71
+ done
72
+
73
+ if [[ -z "$REPO_ROOT" ]]; then
74
+ echo "Error: --repo-root is required" >&2
75
+ usage >&2
76
+ exit 2
77
+ fi
78
+
79
+ if [[ ! -f "$REPO_ROOT/package.json" ]]; then
80
+ echo "Error: No package.json found at $REPO_ROOT" >&2
81
+ exit 2
82
+ fi
83
+
84
+ # ============================================================
85
+ # CHECK FUNCTIONS
86
+ # ============================================================
87
+
88
+ CHECK_PASS=0
89
+ CHECK_FAIL=0
90
+ RESULTS=()
91
+
92
+ check_pass() {
93
+ local name="$1"
94
+ local detail="${2:-}"
95
+ if [[ -n "$detail" ]]; then
96
+ RESULTS+=("- **PASS**: $name — $detail")
97
+ else
98
+ RESULTS+=("- **PASS**: $name")
99
+ fi
100
+ CHECK_PASS=$((CHECK_PASS + 1))
101
+ }
102
+
103
+ check_fail() {
104
+ local name="$1"
105
+ local detail="${2:-}"
106
+ if [[ -n "$detail" ]]; then
107
+ RESULTS+=("- **FAIL**: $name — $detail")
108
+ else
109
+ RESULTS+=("- **FAIL**: $name")
110
+ fi
111
+ CHECK_FAIL=$((CHECK_FAIL + 1))
112
+ }
113
+
114
+ check_skip() {
115
+ local name="$1"
116
+ local detail="${2:-}"
117
+ if [[ -n "$detail" ]]; then
118
+ RESULTS+=("- **SKIP**: $name — $detail")
119
+ else
120
+ RESULTS+=("- **SKIP**: $name")
121
+ fi
122
+ }
123
+
124
+ # Check if an npm script exists in package.json
125
+ has_npm_script() {
126
+ local script_name="$1"
127
+ node -e '
128
+ const p = require(process.argv[1]);
129
+ const s = p.scripts || {};
130
+ process.exit(s[process.argv[2]] ? 0 : 1);
131
+ ' "$REPO_ROOT/package.json" "$script_name" 2>/dev/null
132
+ }
133
+
134
+ # ============================================================
135
+ # CHECK 1: Lint
136
+ # ============================================================
137
+
138
+ run_lint() {
139
+ if [[ "$SKIP_LINT" == true ]]; then
140
+ check_skip "Lint" "--skip-lint"
141
+ return 0
142
+ fi
143
+
144
+ if ! has_npm_script "lint"; then
145
+ check_skip "Lint" "no 'lint' script in package.json"
146
+ return 0
147
+ fi
148
+
149
+ local output
150
+ if output="$(cd "$REPO_ROOT" && npm run lint 2>&1)"; then
151
+ check_pass "Lint"
152
+ return 0
153
+ else
154
+ check_fail "Lint" "npm run lint failed"
155
+ return 1
156
+ fi
157
+ }
158
+
159
+ # ============================================================
160
+ # CHECK 2: Typecheck
161
+ # ============================================================
162
+
163
+ run_typecheck() {
164
+ if [[ "$SKIP_TYPECHECK" == true ]]; then
165
+ check_skip "Typecheck" "--skip-typecheck"
166
+ return 0
167
+ fi
168
+
169
+ if ! has_npm_script "typecheck"; then
170
+ check_skip "Typecheck" "no 'typecheck' script in package.json"
171
+ return 0
172
+ fi
173
+
174
+ local output
175
+ if output="$(cd "$REPO_ROOT" && npm run typecheck 2>&1)"; then
176
+ check_pass "Typecheck"
177
+ return 0
178
+ else
179
+ check_fail "Typecheck" "npm run typecheck failed"
180
+ return 1
181
+ fi
182
+ }
183
+
184
+ # ============================================================
185
+ # CHECK 3: Quality check
186
+ # ============================================================
187
+
188
+ run_quality_check() {
189
+ if ! has_npm_script "quality-check"; then
190
+ check_skip "Quality check" "no 'quality-check' script in package.json"
191
+ return 0
192
+ fi
193
+
194
+ local output
195
+ if output="$(cd "$REPO_ROOT" && npm run quality-check 2>&1)"; then
196
+ check_pass "Quality check"
197
+ return 0
198
+ else
199
+ check_fail "Quality check" "npm run quality-check failed"
200
+ return 1
201
+ fi
202
+ }
203
+
204
+ # ============================================================
205
+ # EXECUTE CHECKS
206
+ # ============================================================
207
+
208
+ run_lint || true
209
+ run_typecheck || true
210
+ run_quality_check || true
211
+
212
+ # ============================================================
213
+ # STRUCTURED OUTPUT
214
+ # ============================================================
215
+
216
+ echo "## Static Analysis Report"
217
+ echo ""
218
+ echo "**Repository:** \`$REPO_ROOT\`"
219
+ echo ""
220
+
221
+ for result in "${RESULTS[@]}"; do
222
+ echo "$result"
223
+ done
224
+
225
+ echo ""
226
+ TOTAL=$((CHECK_PASS + CHECK_FAIL))
227
+ echo "---"
228
+ echo ""
229
+
230
+ if [[ $CHECK_FAIL -eq 0 ]]; then
231
+ echo "**Result: PASS** ($CHECK_PASS/$TOTAL checks passed)"
232
+ exit 0
233
+ else
234
+ echo "**Result: FAIL** ($CHECK_FAIL/$TOTAL checks failed)"
235
+ exit 1
236
+ fi
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env bash
2
+ # sync-labels.sh - Sync labels from .github/labels.yml to GitHub
3
+ #
4
+ # Usage: ./scripts/sync-labels.sh [--dry-run]
5
+ #
6
+ # Requires: gh (GitHub CLI), python3 with pyyaml
7
+
8
+ set -euo pipefail
9
+
10
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
+ REPO_ROOT="$(dirname "$SCRIPT_DIR")"
12
+ LABELS_FILE="$REPO_ROOT/.github/labels.yml"
13
+
14
+ # Auto-detect repository from git remote, environment, or use default
15
+ if [[ -n "${GITHUB_REPOSITORY:-}" ]]; then
16
+ # Use GitHub Actions environment variable
17
+ REPO="$GITHUB_REPOSITORY"
18
+ elif command -v gh &> /dev/null && gh repo view --json nameWithOwner -q .nameWithOwner &> /dev/null; then
19
+ # Auto-detect from git remote via gh CLI
20
+ REPO="$(gh repo view --json nameWithOwner -q .nameWithOwner)"
21
+ else
22
+ # Fallback to default
23
+ REPO="lvlup-sw/exarchos"
24
+ fi
25
+
26
+ # Parse arguments
27
+ DRY_RUN=false
28
+ while [[ $# -gt 0 ]]; do
29
+ case $1 in
30
+ --dry-run) DRY_RUN=true; shift ;;
31
+ -h|--help)
32
+ echo "Usage: $0 [--dry-run]"
33
+ echo ""
34
+ echo "Options:"
35
+ echo " --dry-run Show what would be done without making changes"
36
+ echo " -h, --help Show this help message"
37
+ exit 0
38
+ ;;
39
+ *)
40
+ echo "Error: Unknown argument: $1" >&2
41
+ echo "Use --help for usage information" >&2
42
+ exit 1
43
+ ;;
44
+ esac
45
+ done
46
+
47
+ # Colors
48
+ RED='\033[0;31m'
49
+ GREEN='\033[0;32m'
50
+ YELLOW='\033[1;33m'
51
+ NC='\033[0m'
52
+
53
+ info() { echo -e "${GREEN}[INFO]${NC} $1"; }
54
+ warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
55
+ error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; }
56
+
57
+ # Check dependencies
58
+ check_deps() {
59
+ if ! command -v gh &> /dev/null; then
60
+ error "gh (GitHub CLI) is required but not installed"
61
+ fi
62
+ if ! python3 -c "import yaml" &> /dev/null; then
63
+ error "Python yaml module is required. Install with: pip install pyyaml"
64
+ fi
65
+ if [[ ! -f "$LABELS_FILE" ]]; then
66
+ error "Labels file not found: $LABELS_FILE"
67
+ fi
68
+ }
69
+
70
+ # Delete default GitHub labels we don't use
71
+ delete_default_labels() {
72
+ local defaults=("duplicate" "enhancement" "good first issue" "help wanted" "invalid" "wontfix" "bug" "documentation" "question")
73
+
74
+ info "Removing default labels..."
75
+ for label in "${defaults[@]}"; do
76
+ if [[ "$DRY_RUN" == "true" ]]; then
77
+ echo " [dry-run] Would delete: $label"
78
+ else
79
+ gh label delete "$label" -R "$REPO" --yes 2>/dev/null && \
80
+ echo " Deleted: $label" || \
81
+ echo " Skipped: $label (not found)"
82
+ fi
83
+ done
84
+ }
85
+
86
+ # Create/update labels from config
87
+ sync_labels() {
88
+ info "Syncing labels from $LABELS_FILE..."
89
+
90
+ # Parse YAML and create labels using Python
91
+ python3 -c "import yaml; [print(f\"{l['name']}|{l['color']}|{l['description']}\") for l in yaml.safe_load(open('$LABELS_FILE'))]" | \
92
+ while IFS='|' read -r name color desc; do
93
+ if [[ "$DRY_RUN" == "true" ]]; then
94
+ echo " [dry-run] Would create/update: $name ($color) - $desc"
95
+ else
96
+ gh label create "$name" -R "$REPO" --color "$color" --description "$desc" --force 2>/dev/null && \
97
+ echo " Created/Updated: $name" || \
98
+ echo " Failed: $name"
99
+ fi
100
+ done
101
+ }
102
+
103
+ # Main
104
+ main() {
105
+ echo "Label Sync"
106
+ echo "=========="
107
+ echo ""
108
+ echo "Repository: $REPO"
109
+ echo "Labels file: $LABELS_FILE"
110
+ [[ "$DRY_RUN" == "true" ]] && echo "Mode: DRY RUN"
111
+ echo ""
112
+
113
+ check_deps
114
+ delete_default_labels
115
+ echo ""
116
+ sync_labels
117
+
118
+ echo ""
119
+ info "Label sync complete!"
120
+ }
121
+
122
+ main
@@ -0,0 +1,161 @@
1
+ #!/usr/bin/env bash
2
+ # validate-companion.sh — Validate companion plugin directory structure
3
+ #
4
+ # Checks:
5
+ # 1. companion/.claude-plugin/plugin.json exists and valid JSON with required fields (name, version, mcpServers)
6
+ # 2. companion/.mcp.json exists and valid JSON
7
+ # 3. companion/settings.json exists and valid JSON with enabledPlugins
8
+ #
9
+ # Usage: validate-companion.sh --repo-root <path>
10
+ #
11
+ # Exit codes:
12
+ # 0 = all checks pass
13
+ # 1 = one or more checks fail
14
+ # 2 = usage error
15
+
16
+ set -euo pipefail
17
+
18
+ # ============================================================
19
+ # ARGUMENT PARSING
20
+ # ============================================================
21
+
22
+ REPO_ROOT="."
23
+
24
+ usage() {
25
+ cat << 'USAGE'
26
+ Usage: validate-companion.sh --repo-root <path>
27
+
28
+ Validates the Exarchos companion plugin directory structure.
29
+
30
+ Options:
31
+ --repo-root <path> Path to the repository root (default: .)
32
+ --help Show this help message
33
+
34
+ Exit codes:
35
+ 0 All checks pass
36
+ 1 One or more checks fail
37
+ 2 Usage error
38
+ USAGE
39
+ }
40
+
41
+ while [[ $# -gt 0 ]]; do
42
+ case "$1" in
43
+ --repo-root)
44
+ if [[ -z "${2:-}" ]]; then
45
+ echo "Error: --repo-root requires a path argument" >&2
46
+ exit 2
47
+ fi
48
+ REPO_ROOT="$2"
49
+ shift 2
50
+ ;;
51
+ --help)
52
+ usage
53
+ exit 0
54
+ ;;
55
+ *)
56
+ echo "Error: Unknown argument '$1'" >&2
57
+ usage >&2
58
+ exit 2
59
+ ;;
60
+ esac
61
+ done
62
+
63
+ if [[ ! -d "$REPO_ROOT" ]]; then
64
+ echo "Error: Repository root not found: $REPO_ROOT" >&2
65
+ exit 2
66
+ fi
67
+
68
+ # ============================================================
69
+ # DEPENDENCY CHECK
70
+ # ============================================================
71
+
72
+ if ! command -v jq &>/dev/null; then
73
+ echo "Error: jq is required but not installed" >&2
74
+ exit 2
75
+ fi
76
+
77
+ # ============================================================
78
+ # VALIDATION
79
+ # ============================================================
80
+
81
+ CHECK_PASS=0
82
+ CHECK_FAIL=0
83
+ TOTAL=0
84
+ RESULTS=()
85
+
86
+ check() {
87
+ local description="$1"
88
+ local passed="$2"
89
+ TOTAL=$((TOTAL + 1))
90
+ if [[ "$passed" == "true" ]]; then
91
+ RESULTS+=("- **PASS**: $description")
92
+ CHECK_PASS=$((CHECK_PASS + 1))
93
+ else
94
+ RESULTS+=("- **FAIL**: $description")
95
+ CHECK_FAIL=$((CHECK_FAIL + 1))
96
+ fi
97
+ }
98
+
99
+ # --- Check 1: companion/.claude-plugin/plugin.json exists and valid JSON with required fields ---
100
+ PLUGIN_JSON="$REPO_ROOT/companion/.claude-plugin/plugin.json"
101
+ if [[ -f "$PLUGIN_JSON" ]] && jq empty "$PLUGIN_JSON" 2>/dev/null; then
102
+ REQUIRED_FIELDS=("name" "version" "mcpServers")
103
+ ALL_FIELDS_PRESENT=true
104
+ MISSING_FIELDS=()
105
+ for field in "${REQUIRED_FIELDS[@]}"; do
106
+ if ! jq -e ".$field" "$PLUGIN_JSON" >/dev/null 2>&1; then
107
+ ALL_FIELDS_PRESENT=false
108
+ MISSING_FIELDS+=("$field")
109
+ fi
110
+ done
111
+ if [[ "$ALL_FIELDS_PRESENT" == "true" ]]; then
112
+ check "companion/.claude-plugin/plugin.json exists and valid" "true"
113
+ else
114
+ check "companion/.claude-plugin/plugin.json missing fields: ${MISSING_FIELDS[*]}" "false"
115
+ fi
116
+ else
117
+ check "companion/.claude-plugin/plugin.json exists and valid" "false"
118
+ fi
119
+
120
+ # --- Check 2: companion/.mcp.json exists and valid JSON ---
121
+ MCP_FILE="$REPO_ROOT/companion/.mcp.json"
122
+ if [[ -f "$MCP_FILE" ]] && jq empty "$MCP_FILE" 2>/dev/null; then
123
+ check "companion/.mcp.json exists and valid JSON" "true"
124
+ else
125
+ check "companion/.mcp.json exists and valid JSON" "false"
126
+ fi
127
+
128
+ # --- Check 3: companion/settings.json exists and valid JSON with enabledPlugins ---
129
+ SETTINGS_FILE="$REPO_ROOT/companion/settings.json"
130
+ if [[ -f "$SETTINGS_FILE" ]] && jq empty "$SETTINGS_FILE" 2>/dev/null; then
131
+ if jq -e '.enabledPlugins' "$SETTINGS_FILE" >/dev/null 2>&1; then
132
+ check "companion/settings.json exists and has enabledPlugins" "true"
133
+ else
134
+ check "companion/settings.json missing enabledPlugins field" "false"
135
+ fi
136
+ else
137
+ check "companion/settings.json exists and valid JSON" "false"
138
+ fi
139
+
140
+ # ============================================================
141
+ # STRUCTURED OUTPUT
142
+ # ============================================================
143
+
144
+ echo "## Companion Validation Report"
145
+ echo ""
146
+
147
+ for result in "${RESULTS[@]}"; do
148
+ echo "$result"
149
+ done
150
+
151
+ echo ""
152
+ echo "---"
153
+ echo ""
154
+
155
+ if [[ $CHECK_FAIL -eq 0 ]]; then
156
+ echo "**Result: PASS** ($CHECK_PASS/$TOTAL checks passed)"
157
+ exit 0
158
+ else
159
+ echo "**Result: FAIL** ($CHECK_PASS/$TOTAL checks passed)"
160
+ exit 1
161
+ fi