autonomous-coding-toolkit 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (324) hide show
  1. package/.claude-plugin/marketplace.json +22 -0
  2. package/.claude-plugin/plugin.json +13 -0
  3. package/LICENSE +21 -0
  4. package/Makefile +21 -0
  5. package/README.md +140 -0
  6. package/SECURITY.md +28 -0
  7. package/agents/bash-expert.md +113 -0
  8. package/agents/dependency-auditor.md +138 -0
  9. package/agents/integration-tester.md +120 -0
  10. package/agents/lesson-scanner.md +149 -0
  11. package/agents/python-expert.md +179 -0
  12. package/agents/service-monitor.md +141 -0
  13. package/agents/shell-expert.md +147 -0
  14. package/benchmarks/runner.sh +147 -0
  15. package/benchmarks/tasks/01-rest-endpoint/rubric.sh +29 -0
  16. package/benchmarks/tasks/01-rest-endpoint/task.md +17 -0
  17. package/benchmarks/tasks/02-refactor-module/task.md +8 -0
  18. package/benchmarks/tasks/03-fix-integration-bug/task.md +8 -0
  19. package/benchmarks/tasks/04-add-test-coverage/task.md +8 -0
  20. package/benchmarks/tasks/05-multi-file-feature/task.md +8 -0
  21. package/bin/act.js +238 -0
  22. package/commands/autocode.md +6 -0
  23. package/commands/cancel-ralph.md +18 -0
  24. package/commands/code-factory.md +53 -0
  25. package/commands/create-prd.md +55 -0
  26. package/commands/ralph-loop.md +18 -0
  27. package/commands/run-plan.md +117 -0
  28. package/commands/submit-lesson.md +122 -0
  29. package/docs/ARCHITECTURE.md +630 -0
  30. package/docs/CONTRIBUTING.md +125 -0
  31. package/docs/lessons/0001-bare-exception-swallowing.md +34 -0
  32. package/docs/lessons/0002-async-def-without-await.md +28 -0
  33. package/docs/lessons/0003-create-task-without-callback.md +28 -0
  34. package/docs/lessons/0004-hardcoded-test-counts.md +28 -0
  35. package/docs/lessons/0005-sqlite-without-closing.md +33 -0
  36. package/docs/lessons/0006-venv-pip-path.md +27 -0
  37. package/docs/lessons/0007-runner-state-self-rejection.md +35 -0
  38. package/docs/lessons/0008-quality-gate-blind-spot.md +33 -0
  39. package/docs/lessons/0009-parser-overcount-empty-batches.md +36 -0
  40. package/docs/lessons/0010-local-outside-function-bash.md +33 -0
  41. package/docs/lessons/0011-batch-tests-for-unimplemented-code.md +36 -0
  42. package/docs/lessons/0012-api-markdown-unescaped-chars.md +33 -0
  43. package/docs/lessons/0013-export-prefix-env-parsing.md +33 -0
  44. package/docs/lessons/0014-decorator-registry-import-side-effect.md +43 -0
  45. package/docs/lessons/0015-frontend-backend-schema-drift.md +43 -0
  46. package/docs/lessons/0016-event-driven-cold-start-seeding.md +44 -0
  47. package/docs/lessons/0017-copy-paste-logic-diverges.md +43 -0
  48. package/docs/lessons/0018-layer-passes-pipeline-broken.md +45 -0
  49. package/docs/lessons/0019-systemd-envfile-ignores-export.md +41 -0
  50. package/docs/lessons/0020-persist-state-incrementally.md +44 -0
  51. package/docs/lessons/0021-dual-axis-testing.md +48 -0
  52. package/docs/lessons/0022-jsx-factory-shadowing.md +43 -0
  53. package/docs/lessons/0023-static-analysis-spiral.md +51 -0
  54. package/docs/lessons/0024-shared-pipeline-implementation.md +55 -0
  55. package/docs/lessons/0025-defense-in-depth-all-entry-points.md +65 -0
  56. package/docs/lessons/0026-linter-no-rules-false-enforcement.md +54 -0
  57. package/docs/lessons/0027-jsx-silent-prop-drop.md +64 -0
  58. package/docs/lessons/0028-no-infrastructure-in-client-code.md +49 -0
  59. package/docs/lessons/0029-never-write-secrets-to-files.md +61 -0
  60. package/docs/lessons/0030-cache-merge-not-replace.md +62 -0
  61. package/docs/lessons/0031-verify-units-at-boundaries.md +66 -0
  62. package/docs/lessons/0032-module-lifecycle-subscribe-unsubscribe.md +89 -0
  63. package/docs/lessons/0033-async-iteration-mutable-snapshot.md +72 -0
  64. package/docs/lessons/0034-caller-missing-await-silent-discard.md +65 -0
  65. package/docs/lessons/0035-duplicate-registration-silent-overwrite.md +85 -0
  66. package/docs/lessons/0036-websocket-dirty-disconnect.md +33 -0
  67. package/docs/lessons/0037-parallel-agents-worktree-corruption.md +31 -0
  68. package/docs/lessons/0038-subscribe-no-stored-ref.md +36 -0
  69. package/docs/lessons/0039-fallback-or-default-hides-bugs.md +34 -0
  70. package/docs/lessons/0040-event-firehose-filter-first.md +36 -0
  71. package/docs/lessons/0041-ambiguous-base-dir-path-nesting.md +32 -0
  72. package/docs/lessons/0042-spec-compliance-insufficient.md +36 -0
  73. package/docs/lessons/0043-exact-count-extensible-collections.md +32 -0
  74. package/docs/lessons/0044-relative-file-deps-worktree.md +39 -0
  75. package/docs/lessons/0045-iterative-design-improvement.md +33 -0
  76. package/docs/lessons/0046-plan-assertion-math-bugs.md +38 -0
  77. package/docs/lessons/0047-pytest-single-threaded-default.md +37 -0
  78. package/docs/lessons/0048-integration-wiring-batch.md +40 -0
  79. package/docs/lessons/0049-ab-verification.md +41 -0
  80. package/docs/lessons/0050-editing-sourced-files-during-execution.md +33 -0
  81. package/docs/lessons/0051-infrastructure-fixes-cant-self-heal.md +30 -0
  82. package/docs/lessons/0052-uncommitted-changes-poison-quality-gates.md +31 -0
  83. package/docs/lessons/0053-jq-compact-flag-inconsistency.md +31 -0
  84. package/docs/lessons/0054-parser-matches-inside-code-blocks.md +30 -0
  85. package/docs/lessons/0055-agents-compensate-for-garbled-prompts.md +31 -0
  86. package/docs/lessons/0056-grep-count-exit-code-on-zero.md +42 -0
  87. package/docs/lessons/0057-new-artifacts-break-git-clean-gates.md +42 -0
  88. package/docs/lessons/0058-dead-config-keys-never-consumed.md +49 -0
  89. package/docs/lessons/0059-contract-test-shared-structures.md +53 -0
  90. package/docs/lessons/0060-set-e-silent-death-in-runners.md +53 -0
  91. package/docs/lessons/0061-context-injection-dirty-state.md +50 -0
  92. package/docs/lessons/0062-sibling-bug-neighborhood-scan.md +29 -0
  93. package/docs/lessons/0063-one-flag-two-lifetimes.md +31 -0
  94. package/docs/lessons/0064-test-passes-wrong-reason.md +31 -0
  95. package/docs/lessons/0065-pipefail-grep-count-double-output.md +39 -0
  96. package/docs/lessons/0066-local-keyword-outside-function.md +37 -0
  97. package/docs/lessons/0067-stdin-hang-non-interactive-shell.md +36 -0
  98. package/docs/lessons/0068-agent-builds-wrong-thing-correctly.md +31 -0
  99. package/docs/lessons/0069-plan-quality-dominates-execution.md +30 -0
  100. package/docs/lessons/0070-spec-echo-back-prevents-drift.md +31 -0
  101. package/docs/lessons/0071-positive-instructions-outperform-negative.md +30 -0
  102. package/docs/lessons/0072-lost-in-the-middle-context-placement.md +30 -0
  103. package/docs/lessons/0073-unscoped-lessons-cause-false-positives.md +30 -0
  104. package/docs/lessons/0074-stale-context-injection-wrong-batch.md +32 -0
  105. package/docs/lessons/0075-research-artifacts-must-persist.md +32 -0
  106. package/docs/lessons/0076-wrong-decomposition-contaminates-downstream.md +30 -0
  107. package/docs/lessons/0077-cherry-pick-merges-need-manual-resolution.md +30 -0
  108. package/docs/lessons/0078-static-review-without-live-test.md +30 -0
  109. package/docs/lessons/0079-integration-wiring-batch-required.md +32 -0
  110. package/docs/lessons/FRAMEWORK.md +161 -0
  111. package/docs/lessons/SUMMARY.md +201 -0
  112. package/docs/lessons/TEMPLATE.md +85 -0
  113. package/docs/plans/2026-02-21-code-factory-v2-design.md +204 -0
  114. package/docs/plans/2026-02-21-code-factory-v2-implementation-plan.md +2189 -0
  115. package/docs/plans/2026-02-21-code-factory-v2-phase4-design.md +537 -0
  116. package/docs/plans/2026-02-21-code-factory-v2-phase4-implementation-plan.md +2012 -0
  117. package/docs/plans/2026-02-21-hardening-pass-design.md +108 -0
  118. package/docs/plans/2026-02-21-hardening-pass-plan.md +1378 -0
  119. package/docs/plans/2026-02-21-mab-research-report.md +406 -0
  120. package/docs/plans/2026-02-21-marketplace-restructure-design.md +240 -0
  121. package/docs/plans/2026-02-21-marketplace-restructure-plan.md +832 -0
  122. package/docs/plans/2026-02-21-phase4-completion-plan.md +697 -0
  123. package/docs/plans/2026-02-21-validator-suite-design.md +148 -0
  124. package/docs/plans/2026-02-21-validator-suite-plan.md +540 -0
  125. package/docs/plans/2026-02-22-mab-research-round2.md +556 -0
  126. package/docs/plans/2026-02-22-mab-run-design.md +462 -0
  127. package/docs/plans/2026-02-22-mab-run-plan.md +2046 -0
  128. package/docs/plans/2026-02-22-operations-design-methodology-research.md +681 -0
  129. package/docs/plans/2026-02-22-research-agent-failure-taxonomy.md +532 -0
  130. package/docs/plans/2026-02-22-research-code-guideline-policies.md +886 -0
  131. package/docs/plans/2026-02-22-research-codebase-audit-refactoring.md +908 -0
  132. package/docs/plans/2026-02-22-research-coding-standards-documentation.md +541 -0
  133. package/docs/plans/2026-02-22-research-competitive-landscape.md +687 -0
  134. package/docs/plans/2026-02-22-research-comprehensive-testing.md +1076 -0
  135. package/docs/plans/2026-02-22-research-context-utilization.md +459 -0
  136. package/docs/plans/2026-02-22-research-cost-quality-tradeoff.md +548 -0
  137. package/docs/plans/2026-02-22-research-lesson-transferability.md +508 -0
  138. package/docs/plans/2026-02-22-research-multi-agent-coordination.md +312 -0
  139. package/docs/plans/2026-02-22-research-phase-integration.md +602 -0
  140. package/docs/plans/2026-02-22-research-plan-quality.md +428 -0
  141. package/docs/plans/2026-02-22-research-prompt-engineering.md +558 -0
  142. package/docs/plans/2026-02-22-research-unconventional-perspectives.md +528 -0
  143. package/docs/plans/2026-02-22-research-user-adoption.md +638 -0
  144. package/docs/plans/2026-02-22-research-verification-effectiveness.md +433 -0
  145. package/docs/plans/2026-02-23-agent-suite-design.md +299 -0
  146. package/docs/plans/2026-02-23-agent-suite-plan.md +578 -0
  147. package/docs/plans/2026-02-23-phase3-cost-infrastructure-design.md +148 -0
  148. package/docs/plans/2026-02-23-phase3-cost-infrastructure-plan.md +1062 -0
  149. package/docs/plans/2026-02-23-research-bash-expert-agent.md +543 -0
  150. package/docs/plans/2026-02-23-research-dependency-auditor-agent.md +564 -0
  151. package/docs/plans/2026-02-23-research-improving-existing-agents.md +503 -0
  152. package/docs/plans/2026-02-23-research-integration-tester-agent.md +454 -0
  153. package/docs/plans/2026-02-23-research-python-expert-agent.md +429 -0
  154. package/docs/plans/2026-02-23-research-service-monitor-agent.md +425 -0
  155. package/docs/plans/2026-02-23-research-shell-expert-agent.md +533 -0
  156. package/docs/plans/2026-02-23-roadmap-to-completion.md +530 -0
  157. package/docs/plans/2026-02-24-headless-module-split-design.md +98 -0
  158. package/docs/plans/2026-02-24-headless-module-split.md +443 -0
  159. package/docs/plans/2026-02-24-lesson-scope-metadata-design.md +228 -0
  160. package/docs/plans/2026-02-24-lesson-scope-metadata-plan.md +968 -0
  161. package/docs/plans/2026-02-24-npm-packaging-design.md +841 -0
  162. package/docs/plans/2026-02-24-npm-packaging-plan.md +1965 -0
  163. package/docs/plans/audit-findings.md +186 -0
  164. package/docs/telegram-notification-format.md +98 -0
  165. package/examples/example-plan.md +51 -0
  166. package/examples/example-prd.json +72 -0
  167. package/examples/example-roadmap.md +33 -0
  168. package/examples/quickstart-plan.md +63 -0
  169. package/hooks/hooks.json +26 -0
  170. package/hooks/setup-symlinks.sh +48 -0
  171. package/hooks/stop-hook.sh +135 -0
  172. package/package.json +47 -0
  173. package/policies/bash.md +71 -0
  174. package/policies/python.md +71 -0
  175. package/policies/testing.md +61 -0
  176. package/policies/universal.md +60 -0
  177. package/scripts/analyze-report.sh +97 -0
  178. package/scripts/architecture-map.sh +145 -0
  179. package/scripts/auto-compound.sh +273 -0
  180. package/scripts/batch-audit.sh +42 -0
  181. package/scripts/batch-test.sh +101 -0
  182. package/scripts/entropy-audit.sh +221 -0
  183. package/scripts/failure-digest.sh +51 -0
  184. package/scripts/generate-ast-rules.sh +96 -0
  185. package/scripts/init.sh +112 -0
  186. package/scripts/lesson-check.sh +428 -0
  187. package/scripts/lib/common.sh +61 -0
  188. package/scripts/lib/cost-tracking.sh +153 -0
  189. package/scripts/lib/ollama.sh +60 -0
  190. package/scripts/lib/progress-writer.sh +128 -0
  191. package/scripts/lib/run-plan-context.sh +215 -0
  192. package/scripts/lib/run-plan-echo-back.sh +231 -0
  193. package/scripts/lib/run-plan-headless.sh +396 -0
  194. package/scripts/lib/run-plan-notify.sh +57 -0
  195. package/scripts/lib/run-plan-parser.sh +81 -0
  196. package/scripts/lib/run-plan-prompt.sh +215 -0
  197. package/scripts/lib/run-plan-quality-gate.sh +132 -0
  198. package/scripts/lib/run-plan-routing.sh +315 -0
  199. package/scripts/lib/run-plan-sampling.sh +170 -0
  200. package/scripts/lib/run-plan-scoring.sh +146 -0
  201. package/scripts/lib/run-plan-state.sh +142 -0
  202. package/scripts/lib/run-plan-team.sh +199 -0
  203. package/scripts/lib/telegram.sh +54 -0
  204. package/scripts/lib/thompson-sampling.sh +176 -0
  205. package/scripts/license-check.sh +74 -0
  206. package/scripts/mab-run.sh +575 -0
  207. package/scripts/module-size-check.sh +146 -0
  208. package/scripts/patterns/async-no-await.yml +5 -0
  209. package/scripts/patterns/bare-except.yml +6 -0
  210. package/scripts/patterns/empty-catch.yml +6 -0
  211. package/scripts/patterns/hardcoded-localhost.yml +9 -0
  212. package/scripts/patterns/retry-loop-no-backoff.yml +12 -0
  213. package/scripts/pipeline-status.sh +197 -0
  214. package/scripts/policy-check.sh +226 -0
  215. package/scripts/prior-art-search.sh +133 -0
  216. package/scripts/promote-mab-lessons.sh +126 -0
  217. package/scripts/prompts/agent-a-superpowers.md +29 -0
  218. package/scripts/prompts/agent-b-ralph.md +29 -0
  219. package/scripts/prompts/judge-agent.md +61 -0
  220. package/scripts/prompts/planner-agent.md +44 -0
  221. package/scripts/pull-community-lessons.sh +90 -0
  222. package/scripts/quality-gate.sh +266 -0
  223. package/scripts/research-gate.sh +90 -0
  224. package/scripts/run-plan.sh +329 -0
  225. package/scripts/scope-infer.sh +159 -0
  226. package/scripts/setup-ralph-loop.sh +155 -0
  227. package/scripts/telemetry.sh +230 -0
  228. package/scripts/tests/run-all-tests.sh +52 -0
  229. package/scripts/tests/test-act-cli.sh +46 -0
  230. package/scripts/tests/test-agents-md.sh +87 -0
  231. package/scripts/tests/test-analyze-report.sh +114 -0
  232. package/scripts/tests/test-architecture-map.sh +89 -0
  233. package/scripts/tests/test-auto-compound.sh +169 -0
  234. package/scripts/tests/test-batch-test.sh +65 -0
  235. package/scripts/tests/test-benchmark-runner.sh +25 -0
  236. package/scripts/tests/test-common.sh +168 -0
  237. package/scripts/tests/test-cost-tracking.sh +158 -0
  238. package/scripts/tests/test-echo-back.sh +180 -0
  239. package/scripts/tests/test-entropy-audit.sh +146 -0
  240. package/scripts/tests/test-failure-digest.sh +66 -0
  241. package/scripts/tests/test-generate-ast-rules.sh +145 -0
  242. package/scripts/tests/test-helpers.sh +82 -0
  243. package/scripts/tests/test-init.sh +47 -0
  244. package/scripts/tests/test-lesson-check.sh +278 -0
  245. package/scripts/tests/test-lesson-local.sh +55 -0
  246. package/scripts/tests/test-license-check.sh +109 -0
  247. package/scripts/tests/test-mab-run.sh +182 -0
  248. package/scripts/tests/test-ollama-lib.sh +49 -0
  249. package/scripts/tests/test-ollama.sh +60 -0
  250. package/scripts/tests/test-pipeline-status.sh +198 -0
  251. package/scripts/tests/test-policy-check.sh +124 -0
  252. package/scripts/tests/test-prior-art-search.sh +96 -0
  253. package/scripts/tests/test-progress-writer.sh +140 -0
  254. package/scripts/tests/test-promote-mab-lessons.sh +110 -0
  255. package/scripts/tests/test-pull-community-lessons.sh +149 -0
  256. package/scripts/tests/test-quality-gate.sh +241 -0
  257. package/scripts/tests/test-research-gate.sh +132 -0
  258. package/scripts/tests/test-run-plan-cli.sh +86 -0
  259. package/scripts/tests/test-run-plan-context.sh +305 -0
  260. package/scripts/tests/test-run-plan-e2e.sh +153 -0
  261. package/scripts/tests/test-run-plan-headless.sh +424 -0
  262. package/scripts/tests/test-run-plan-notify.sh +124 -0
  263. package/scripts/tests/test-run-plan-parser.sh +217 -0
  264. package/scripts/tests/test-run-plan-prompt.sh +254 -0
  265. package/scripts/tests/test-run-plan-quality-gate.sh +222 -0
  266. package/scripts/tests/test-run-plan-routing.sh +178 -0
  267. package/scripts/tests/test-run-plan-scoring.sh +148 -0
  268. package/scripts/tests/test-run-plan-state.sh +261 -0
  269. package/scripts/tests/test-run-plan-team.sh +157 -0
  270. package/scripts/tests/test-scope-infer.sh +150 -0
  271. package/scripts/tests/test-setup-ralph-loop.sh +63 -0
  272. package/scripts/tests/test-telegram-env.sh +38 -0
  273. package/scripts/tests/test-telegram.sh +121 -0
  274. package/scripts/tests/test-telemetry.sh +46 -0
  275. package/scripts/tests/test-thompson-sampling.sh +139 -0
  276. package/scripts/tests/test-validate-all.sh +60 -0
  277. package/scripts/tests/test-validate-commands.sh +89 -0
  278. package/scripts/tests/test-validate-hooks.sh +98 -0
  279. package/scripts/tests/test-validate-lessons.sh +150 -0
  280. package/scripts/tests/test-validate-plan-quality.sh +235 -0
  281. package/scripts/tests/test-validate-plans.sh +187 -0
  282. package/scripts/tests/test-validate-plugin.sh +106 -0
  283. package/scripts/tests/test-validate-prd.sh +184 -0
  284. package/scripts/tests/test-validate-skills.sh +134 -0
  285. package/scripts/validate-all.sh +57 -0
  286. package/scripts/validate-commands.sh +67 -0
  287. package/scripts/validate-hooks.sh +89 -0
  288. package/scripts/validate-lessons.sh +98 -0
  289. package/scripts/validate-plan-quality.sh +369 -0
  290. package/scripts/validate-plans.sh +120 -0
  291. package/scripts/validate-plugin.sh +86 -0
  292. package/scripts/validate-policies.sh +42 -0
  293. package/scripts/validate-prd.sh +118 -0
  294. package/scripts/validate-skills.sh +96 -0
  295. package/skills/autocode/SKILL.md +285 -0
  296. package/skills/autocode/ab-verification.md +51 -0
  297. package/skills/autocode/code-quality-standards.md +37 -0
  298. package/skills/autocode/competitive-mode.md +364 -0
  299. package/skills/brainstorming/SKILL.md +97 -0
  300. package/skills/capture-lesson/SKILL.md +187 -0
  301. package/skills/check-lessons/SKILL.md +116 -0
  302. package/skills/dispatching-parallel-agents/SKILL.md +110 -0
  303. package/skills/executing-plans/SKILL.md +85 -0
  304. package/skills/finishing-a-development-branch/SKILL.md +201 -0
  305. package/skills/receiving-code-review/SKILL.md +72 -0
  306. package/skills/requesting-code-review/SKILL.md +59 -0
  307. package/skills/requesting-code-review/code-reviewer.md +82 -0
  308. package/skills/research/SKILL.md +145 -0
  309. package/skills/roadmap/SKILL.md +115 -0
  310. package/skills/subagent-driven-development/SKILL.md +98 -0
  311. package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +18 -0
  312. package/skills/subagent-driven-development/implementer-prompt.md +73 -0
  313. package/skills/subagent-driven-development/spec-reviewer-prompt.md +57 -0
  314. package/skills/systematic-debugging/SKILL.md +134 -0
  315. package/skills/systematic-debugging/condition-based-waiting.md +64 -0
  316. package/skills/systematic-debugging/defense-in-depth.md +32 -0
  317. package/skills/systematic-debugging/root-cause-tracing.md +55 -0
  318. package/skills/test-driven-development/SKILL.md +167 -0
  319. package/skills/using-git-worktrees/SKILL.md +219 -0
  320. package/skills/using-superpowers/SKILL.md +54 -0
  321. package/skills/verification-before-completion/SKILL.md +140 -0
  322. package/skills/verify/SKILL.md +82 -0
  323. package/skills/writing-plans/SKILL.md +128 -0
  324. package/skills/writing-skills/SKILL.md +93 -0
@@ -0,0 +1,369 @@
1
+ #!/usr/bin/env bash
2
+ # validate-plan-quality.sh — Score implementation plan quality on 8 dimensions
3
+ #
4
+ # Usage:
5
+ # validate-plan-quality.sh <plan-file> [--min-score N] [--json]
6
+ #
7
+ # Returns score 0-100. Exit 0 if >= min-score (default: 60), exit 1 otherwise.
8
+ # Research basis: Plan quality has 3x the impact of execution quality (SWE-bench Pro, N=1865).
9
+ #
10
+ # Dimensions (weights):
11
+ # 1. Task granularity — each task < 100 lines estimated (15%)
12
+ # 2. Spec completeness — each task has verification command (20%)
13
+ # 3. Single outcome — no mixed task types per batch (10%)
14
+ # 4. Dependency ordering — no forward references (10%)
15
+ # 5. File path specificity — all tasks name exact files (15%)
16
+ # 6. Acceptance criteria — each batch has at least one assert (15%)
17
+ # 7. Batch size — 1-5 tasks per batch (10%)
18
+ # 8. TDD structure — test-before-implement pattern (5%)
19
+ set -euo pipefail
20
+
21
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
22
+
23
+ # Source parser for plan parsing functions
24
+ source "$SCRIPT_DIR/lib/run-plan-parser.sh"
25
+
26
+ # --- Defaults ---
27
+ PLAN_FILE=""
28
+ MIN_SCORE=60
29
+ JSON_OUTPUT=false
30
+
31
+ # --- Usage ---
32
+ usage() {
33
+ cat <<'USAGE'
34
+ validate-plan-quality — Score implementation plan quality (0-100)
35
+
36
+ Usage:
37
+ validate-plan-quality.sh <plan-file> [--min-score N] [--json]
38
+
39
+ Options:
40
+ --min-score N Minimum passing score (default: 60)
41
+ --json Output JSON report instead of text
42
+ -h, --help Show this help message
43
+
44
+ Dimensions scored:
45
+ 1. Task granularity (15%) — tasks should be small (<100 lines each)
46
+ 2. Spec completeness (20%) — tasks have verification commands
47
+ 3. Single outcome (10%) — batches don't mix create/refactor/test
48
+ 4. Dependency ordering (10%) — no forward references to later batches
49
+ 5. File path specificity (15%) — tasks name exact file paths
50
+ 6. Acceptance criteria (15%) — batches have testable assertions
51
+ 7. Batch size (10%) — 1-5 tasks per batch
52
+ 8. TDD structure (5%) — test-before-implement ordering
53
+ USAGE
54
+ }
55
+
56
+ # --- Argument parsing ---
57
+ while [[ $# -gt 0 ]]; do
58
+ case "$1" in
59
+ -h|--help) usage; exit 0 ;;
60
+ --min-score) MIN_SCORE="$2"; shift 2 ;;
61
+ --json) JSON_OUTPUT=true; shift ;;
62
+ -*) echo "ERROR: Unknown option: $1" >&2; exit 1 ;;
63
+ *) PLAN_FILE="$1"; shift ;;
64
+ esac
65
+ done
66
+
67
+ if [[ -z "$PLAN_FILE" ]]; then
68
+ echo "ERROR: Plan file required" >&2
69
+ usage >&2
70
+ exit 1
71
+ fi
72
+
73
+ if ! [[ "$MIN_SCORE" =~ ^[0-9]+$ ]]; then
74
+ echo "ERROR: --min-score must be a number, got: $MIN_SCORE" >&2
75
+ exit 1
76
+ fi
77
+
78
+ if [[ ! -f "$PLAN_FILE" ]]; then
79
+ echo "ERROR: Plan file not found: $PLAN_FILE" >&2
80
+ exit 1
81
+ fi
82
+
83
+ # --- Helpers ---
84
+ # Safe grep -c that works with pipefail (avoids the 0\n0 double-output bug).
85
+ # Reads from stdin. Distinguishes "no matches" (exit 1) from "grep error" (exit 2+).
86
+ _count_matches() {
87
+ local pattern="$1"
88
+ local result exit_code=0
89
+ result=$(grep -ciE "$pattern" 2>&1) || exit_code=$?
90
+ if [[ $exit_code -le 1 ]]; then
91
+ # 0 = matches found, 1 = no matches (both normal)
92
+ echo "${result:-0}"
93
+ else
94
+ echo "WARNING: grep failed (exit $exit_code) for pattern: $pattern" >&2
95
+ echo "0"
96
+ fi
97
+ }
98
+
99
+ # --- Scoring functions ---
100
+ # Each returns a score 0-100 for its dimension
101
+
102
+ score_task_granularity() {
103
+ local plan_file="$1"
104
+ local total_batches task_count total_tasks=0 batches_with_big_tasks=0
105
+ total_batches=$(count_batches "$plan_file")
106
+ [[ "$total_batches" -eq 0 ]] && { echo 0; return; }
107
+
108
+ for ((b = 1; b <= total_batches; b++)); do
109
+ local text
110
+ text=$(get_batch_text "$plan_file" "$b")
111
+ task_count=$(echo "$text" | _count_matches '^### Task [0-9]+')
112
+ total_tasks=$((total_tasks + task_count))
113
+
114
+ # Estimate: if batch text > 200 lines and has tasks, tasks are probably too big
115
+ local line_count
116
+ line_count=$(echo "$text" | wc -l)
117
+ if [[ "$task_count" -gt 0 ]]; then
118
+ local avg_lines=$(( line_count / task_count ))
119
+ if [[ "$avg_lines" -gt 100 ]]; then
120
+ batches_with_big_tasks=$((batches_with_big_tasks + 1))
121
+ fi
122
+ fi
123
+ done
124
+
125
+ if [[ "$total_batches" -eq 0 ]]; then
126
+ echo 0
127
+ elif [[ "$batches_with_big_tasks" -eq 0 ]]; then
128
+ echo 100
129
+ else
130
+ local pct=$(( 100 - (batches_with_big_tasks * 100 / total_batches) ))
131
+ echo "$pct"
132
+ fi
133
+ }
134
+
135
+ score_spec_completeness() {
136
+ local plan_file="$1"
137
+ local total_batches tasks_with_verify=0 total_tasks=0
138
+ total_batches=$(count_batches "$plan_file")
139
+ [[ "$total_batches" -eq 0 ]] && { echo 0; return; }
140
+
141
+ for ((b = 1; b <= total_batches; b++)); do
142
+ local text
143
+ text=$(get_batch_text "$plan_file" "$b")
144
+ local task_count
145
+ task_count=$(echo "$text" | _count_matches '^### Task [0-9]+')
146
+ total_tasks=$((total_tasks + task_count))
147
+
148
+ # Count tasks that mention verification patterns
149
+ local verify_count
150
+ verify_count=$(echo "$text" | _count_matches '(verify|assert|test|check|confirm|expect|should)')
151
+ # Approximate: if verify mentions >= task count, all tasks are specified
152
+ if [[ "$task_count" -gt 0 && "$verify_count" -ge "$task_count" ]]; then
153
+ tasks_with_verify=$((tasks_with_verify + task_count))
154
+ elif [[ "$task_count" -gt 0 ]]; then
155
+ # Partial credit
156
+ tasks_with_verify=$((tasks_with_verify + verify_count))
157
+ fi
158
+ done
159
+
160
+ if [[ "$total_tasks" -eq 0 ]]; then
161
+ echo 0
162
+ else
163
+ local pct=$(( tasks_with_verify * 100 / total_tasks ))
164
+ [[ "$pct" -gt 100 ]] && pct=100
165
+ echo "$pct"
166
+ fi
167
+ }
168
+
169
+ score_single_outcome() {
170
+ local plan_file="$1"
171
+ local total_batches mixed_batches=0
172
+ total_batches=$(count_batches "$plan_file")
173
+ [[ "$total_batches" -eq 0 ]] && { echo 0; return; }
174
+
175
+ for ((b = 1; b <= total_batches; b++)); do
176
+ local text
177
+ text=$(get_batch_text "$plan_file" "$b")
178
+ # Detect mixed types: creation + refactoring in same batch
179
+ local has_create has_refactor
180
+ has_create=$(echo "$text" | _count_matches '(create|add|new|implement)')
181
+ has_refactor=$(echo "$text" | _count_matches '(refactor|rename|move|extract|reorganize)')
182
+
183
+ # Mixed = has significant refactoring alongside significant creation
184
+ if [[ "$has_create" -ge 2 && "$has_refactor" -ge 2 ]]; then
185
+ mixed_batches=$((mixed_batches + 1))
186
+ fi
187
+ done
188
+
189
+ if [[ "$mixed_batches" -eq 0 ]]; then
190
+ echo 100
191
+ else
192
+ local pct=$(( 100 - (mixed_batches * 100 / total_batches) ))
193
+ [[ "$pct" -lt 0 ]] && pct=0
194
+ echo "$pct"
195
+ fi
196
+ }
197
+
198
+ score_dependency_ordering() {
199
+ local plan_file="$1"
200
+ local total_batches forward_refs=0
201
+ total_batches=$(count_batches "$plan_file")
202
+ [[ "$total_batches" -eq 0 ]] && { echo 0; return; }
203
+
204
+ for ((b = 1; b <= total_batches; b++)); do
205
+ local text
206
+ text=$(get_batch_text "$plan_file" "$b")
207
+ # Check for references to later batches
208
+ for ((future = b + 1; future <= total_batches; future++)); do
209
+ if echo "$text" | grep -qE "(Batch ${future}|batch ${future})" 2>/dev/null; then
210
+ forward_refs=$((forward_refs + 1))
211
+ break
212
+ fi
213
+ done
214
+ done
215
+
216
+ if [[ "$forward_refs" -eq 0 ]]; then
217
+ echo 100
218
+ else
219
+ local pct=$(( 100 - (forward_refs * 100 / total_batches) ))
220
+ [[ "$pct" -lt 0 ]] && pct=0
221
+ echo "$pct"
222
+ fi
223
+ }
224
+
225
+ score_file_path_specificity() {
226
+ local plan_file="$1"
227
+ local total_batches batches_with_paths=0
228
+ total_batches=$(count_batches "$plan_file")
229
+ [[ "$total_batches" -eq 0 ]] && { echo 0; return; }
230
+
231
+ for ((b = 1; b <= total_batches; b++)); do
232
+ local text
233
+ text=$(get_batch_text "$plan_file" "$b")
234
+ # Check for file path patterns (backtick-wrapped paths or **Files:** sections)
235
+ local path_count
236
+ path_count=$(echo "$text" | _count_matches '(`[a-zA-Z0-9_./-]+\.[a-zA-Z]+`|\*\*Files:\*\*)')
237
+ if [[ "$path_count" -gt 0 ]]; then
238
+ batches_with_paths=$((batches_with_paths + 1))
239
+ fi
240
+ done
241
+
242
+ echo $(( batches_with_paths * 100 / total_batches ))
243
+ }
244
+
245
+ score_acceptance_criteria() {
246
+ local plan_file="$1"
247
+ local total_batches batches_with_criteria=0
248
+ total_batches=$(count_batches "$plan_file")
249
+ [[ "$total_batches" -eq 0 ]] && { echo 0; return; }
250
+
251
+ for ((b = 1; b <= total_batches; b++)); do
252
+ local text
253
+ text=$(get_batch_text "$plan_file" "$b")
254
+ # Look for acceptance criteria patterns
255
+ local criteria_count
256
+ criteria_count=$(echo "$text" | _count_matches '(assert|expect|should|must|test.*pass|verify that|confirm)')
257
+ if [[ "$criteria_count" -gt 0 ]]; then
258
+ batches_with_criteria=$((batches_with_criteria + 1))
259
+ fi
260
+ done
261
+
262
+ echo $(( batches_with_criteria * 100 / total_batches ))
263
+ }
264
+
265
+ score_batch_size() {
266
+ local plan_file="$1"
267
+ local total_batches good_batches=0
268
+ total_batches=$(count_batches "$plan_file")
269
+ [[ "$total_batches" -eq 0 ]] && { echo 0; return; }
270
+
271
+ for ((b = 1; b <= total_batches; b++)); do
272
+ local task_count
273
+ task_count=$(get_batch_task_count "$plan_file" "$b")
274
+ # Ideal: 1-5 tasks per batch
275
+ if [[ "$task_count" -ge 1 && "$task_count" -le 5 ]]; then
276
+ good_batches=$((good_batches + 1))
277
+ fi
278
+ done
279
+
280
+ echo $(( good_batches * 100 / total_batches ))
281
+ }
282
+
283
+ score_tdd_structure() {
284
+ local plan_file="$1"
285
+ local total_batches tdd_batches=0
286
+ total_batches=$(count_batches "$plan_file")
287
+ [[ "$total_batches" -eq 0 ]] && { echo 0; return; }
288
+
289
+ for ((b = 1; b <= total_batches; b++)); do
290
+ local text
291
+ text=$(get_batch_text "$plan_file" "$b")
292
+ # Look for TDD patterns: explicit TDD language or test file references before source
293
+ if echo "$text" | grep -qiE '(write.*test.*before|test.*first|failing test|red.green|TDD)' 2>/dev/null; then
294
+ tdd_batches=$((tdd_batches + 1))
295
+ elif echo "$text" | grep -qiE 'Test:.*test.*\.(py|js|ts|sh)' 2>/dev/null; then
296
+ tdd_batches=$((tdd_batches + 1))
297
+ fi
298
+ done
299
+
300
+ echo $(( tdd_batches * 100 / total_batches ))
301
+ }
302
+
303
+ # --- Main scoring ---
304
+ total_batches=$(count_batches "$PLAN_FILE")
305
+ if [[ "$total_batches" -eq 0 ]]; then
306
+ echo "ERROR: No batches found in plan (expected '## Batch N:' headers)" >&2
307
+ exit 1
308
+ fi
309
+
310
+ # Score each dimension
311
+ s_granularity=$(score_task_granularity "$PLAN_FILE")
312
+ s_spec=$(score_spec_completeness "$PLAN_FILE")
313
+ s_single=$(score_single_outcome "$PLAN_FILE")
314
+ s_deps=$(score_dependency_ordering "$PLAN_FILE")
315
+ s_paths=$(score_file_path_specificity "$PLAN_FILE")
316
+ s_criteria=$(score_acceptance_criteria "$PLAN_FILE")
317
+ s_batch_size=$(score_batch_size "$PLAN_FILE")
318
+ s_tdd=$(score_tdd_structure "$PLAN_FILE")
319
+
320
+ # Weighted total (weights sum to 100)
321
+ total=$(( (s_granularity * 15 + s_spec * 20 + s_single * 10 + s_deps * 10 + s_paths * 15 + s_criteria * 15 + s_batch_size * 10 + s_tdd * 5) / 100 ))
322
+
323
+ if [[ "$JSON_OUTPUT" == true ]]; then
324
+ escaped_plan=$(printf '%s' "$PLAN_FILE" | jq -Rs '.')
325
+ cat <<JSONEOF
326
+ {
327
+ "plan_file": $escaped_plan,
328
+ "total_batches": $total_batches,
329
+ "score": $total,
330
+ "min_score": $MIN_SCORE,
331
+ "passed": $([ "$total" -ge "$MIN_SCORE" ] && echo "true" || echo "false"),
332
+ "dimensions": {
333
+ "task_granularity": {"score": $s_granularity, "weight": 15},
334
+ "spec_completeness": {"score": $s_spec, "weight": 20},
335
+ "single_outcome": {"score": $s_single, "weight": 10},
336
+ "dependency_ordering": {"score": $s_deps, "weight": 10},
337
+ "file_path_specificity": {"score": $s_paths, "weight": 15},
338
+ "acceptance_criteria": {"score": $s_criteria, "weight": 15},
339
+ "batch_size": {"score": $s_batch_size, "weight": 10},
340
+ "tdd_structure": {"score": $s_tdd, "weight": 5}
341
+ }
342
+ }
343
+ JSONEOF
344
+ else
345
+ echo "Plan Quality Scorecard: $(basename "$PLAN_FILE")"
346
+ echo "═══════════════════════════════════════════"
347
+ printf " %-25s %3d/100 (15%%)\n" "Task granularity" "$s_granularity"
348
+ printf " %-25s %3d/100 (20%%)\n" "Spec completeness" "$s_spec"
349
+ printf " %-25s %3d/100 (10%%)\n" "Single outcome" "$s_single"
350
+ printf " %-25s %3d/100 (10%%)\n" "Dependency ordering" "$s_deps"
351
+ printf " %-25s %3d/100 (15%%)\n" "File path specificity" "$s_paths"
352
+ printf " %-25s %3d/100 (15%%)\n" "Acceptance criteria" "$s_criteria"
353
+ printf " %-25s %3d/100 (10%%)\n" "Batch size" "$s_batch_size"
354
+ printf " %-25s %3d/100 ( 5%%)\n" "TDD structure" "$s_tdd"
355
+ echo "═══════════════════════════════════════════"
356
+ printf " %-25s %3d/100 (min: %d)\n" "TOTAL" "$total" "$MIN_SCORE"
357
+ echo ""
358
+ if [[ "$total" -ge "$MIN_SCORE" ]]; then
359
+ echo "PASSED"
360
+ else
361
+ echo "FAILED (score $total < min $MIN_SCORE)"
362
+ fi
363
+ fi
364
+
365
+ if [[ "$total" -ge "$MIN_SCORE" ]]; then
366
+ exit 0
367
+ else
368
+ exit 1
369
+ fi
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env bash
2
+ # validate-plans.sh — Validate implementation plan structure
3
+ # Exit 0 if clean, exit 1 if violations found. Use --warn to print but exit 0.
4
+ set -euo pipefail
5
+
6
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
+ PLANS_DIR="${PLANS_DIR:-$SCRIPT_DIR/../docs/plans}"
8
+ WARN_ONLY=false
9
+ EXPLICIT_FILES=false
10
+ violations=0
11
+ FILES=()
12
+
13
+ usage() {
14
+ echo "Usage: validate-plans.sh [--warn] [--help] [file ...]"
15
+ echo " Validates plan files (files with ## Batch headers)"
16
+ echo " Without arguments, scans docs/plans/*.md"
17
+ echo " --warn Print violations but exit 0"
18
+ exit 0
19
+ }
20
+
21
+ report_violation() {
22
+ local file="$1" msg="$2"
23
+ echo "${file}: ${msg}"
24
+ ((violations++)) || true
25
+ }
26
+
27
+ # Parse arguments
28
+ while [[ $# -gt 0 ]]; do
29
+ case "$1" in
30
+ --help|-h) usage ;;
31
+ --warn) WARN_ONLY=true; shift ;;
32
+ *) FILES+=("$1"); EXPLICIT_FILES=true; shift ;;
33
+ esac
34
+ done
35
+
36
+ # If no files given, scan PLANS_DIR
37
+ if [[ ${#FILES[@]} -eq 0 ]]; then
38
+ if [[ ! -d "$PLANS_DIR" ]]; then
39
+ echo "validate-plans: plans directory not found: $PLANS_DIR" >&2
40
+ exit 1
41
+ fi
42
+ for f in "$PLANS_DIR"/*.md; do
43
+ [[ -f "$f" ]] || continue
44
+ FILES+=("$f")
45
+ done
46
+ fi
47
+
48
+ validated=0
49
+
50
+ for plan in "${FILES[@]}"; do
51
+ [[ -f "$plan" ]] || continue
52
+ fname="$(basename "$plan")"
53
+
54
+ # Skip files without any Batch headers (design docs) — but only in scan mode
55
+ if ! grep -q '^## Batch [0-9]' "$plan"; then
56
+ if [[ "$EXPLICIT_FILES" == true ]]; then
57
+ report_violation "$fname" "No batches found (missing '## Batch N:' headers)"
58
+ fi
59
+ continue
60
+ fi
61
+
62
+ validated=$((validated + 1))
63
+
64
+ # Extract batch numbers and line numbers
65
+ batch_numbers=()
66
+ batch_lines=()
67
+ while IFS=: read -r line_num line_content; do
68
+ num=$(echo "$line_content" | sed -n 's/^## Batch \([0-9][0-9]*\).*/\1/p')
69
+ if [[ -n "$num" ]]; then
70
+ batch_numbers+=("$num")
71
+ batch_lines+=("$line_num")
72
+ fi
73
+ done < <(grep -n '^## Batch [0-9]' "$plan")
74
+
75
+ # Check: at least one batch
76
+ if [[ ${#batch_numbers[@]} -eq 0 ]]; then
77
+ report_violation "$fname" "No batches found"
78
+ continue
79
+ fi
80
+
81
+ # Check: sequential batch numbers starting from 1
82
+ expected=1
83
+ for num in "${batch_numbers[@]}"; do
84
+ if [[ "$num" -ne "$expected" ]]; then
85
+ report_violation "$fname" "Non-sequential batch numbering: found Batch $num, expected Batch $expected"
86
+ break
87
+ fi
88
+ expected=$((expected + 1))
89
+ done
90
+
91
+ # Check: each batch has at least one task
92
+ total_lines=$(wc -l < "$plan")
93
+ for i in "${!batch_numbers[@]}"; do
94
+ batch_num="${batch_numbers[$i]}"
95
+ start_line="${batch_lines[$i]}"
96
+
97
+ # End is line before next batch start, or EOF for last batch
98
+ if [[ $((i + 1)) -lt ${#batch_lines[@]} ]]; then
99
+ end_line=$(( ${batch_lines[$((i + 1))]} - 1 ))
100
+ else
101
+ end_line="$total_lines"
102
+ fi
103
+
104
+ # Check for ### Task headers between start and end
105
+ task_count=$(sed -n "${start_line},${end_line}p" "$plan" | grep -c '^### Task ' || true)
106
+ if [[ "$task_count" -eq 0 ]]; then
107
+ report_violation "$fname" "Batch $batch_num has no tasks"
108
+ fi
109
+ done
110
+ done
111
+
112
+ if [[ $violations -gt 0 ]]; then
113
+ echo ""
114
+ echo "validate-plans: FAIL ($violations issues)"
115
+ [[ "$WARN_ONLY" == true ]] && exit 0
116
+ exit 1
117
+ else
118
+ echo "validate-plans: PASS"
119
+ exit 0
120
+ fi
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env bash
2
+ # validate-plugin.sh — Validate .claude-plugin/plugin.json and marketplace.json consistency
3
+ # Exit 0 if clean, exit 1 if violations found. Use --warn to print but exit 0.
4
+ set -euo pipefail
5
+
6
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
+ PLUGIN_DIR="${PLUGIN_DIR:-$SCRIPT_DIR/../.claude-plugin}"
8
+ WARN_ONLY=false
9
+ violations=0
10
+
11
+ usage() {
12
+ echo "Usage: validate-plugin.sh [--warn] [--help]"
13
+ echo " Validates .claude-plugin/plugin.json and marketplace.json"
14
+ echo " --warn Print violations but exit 0"
15
+ exit 0
16
+ }
17
+
18
+ report_violation() {
19
+ local file="$1" msg="$2"
20
+ echo "${file}: ${msg}"
21
+ ((violations++)) || true
22
+ }
23
+
24
+ [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]] && usage
25
+ [[ "${1:-}" == "--warn" ]] && WARN_ONLY=true
26
+
27
+ if [[ ! -d "$PLUGIN_DIR" ]]; then
28
+ echo "validate-plugin: plugin directory not found: $PLUGIN_DIR" >&2
29
+ exit 1
30
+ fi
31
+
32
+ # Check files exist
33
+ if [[ ! -f "$PLUGIN_DIR/plugin.json" ]]; then
34
+ report_violation "plugin.json" "plugin.json not found"
35
+ fi
36
+ if [[ ! -f "$PLUGIN_DIR/marketplace.json" ]]; then
37
+ report_violation "marketplace.json" "marketplace.json not found"
38
+ fi
39
+
40
+ if [[ $violations -gt 0 ]]; then
41
+ echo ""
42
+ echo "validate-plugin: FAIL ($violations issues)"
43
+ [[ "$WARN_ONLY" == true ]] && exit 0
44
+ exit 1
45
+ fi
46
+
47
+ # Validate JSON
48
+ if ! jq empty "$PLUGIN_DIR/plugin.json" 2>/dev/null; then
49
+ report_violation "plugin.json" "plugin.json is not valid JSON"
50
+ fi
51
+ if ! jq empty "$PLUGIN_DIR/marketplace.json" 2>/dev/null; then
52
+ report_violation "marketplace.json" "marketplace.json is not valid JSON"
53
+ fi
54
+
55
+ if [[ $violations -gt 0 ]]; then
56
+ echo ""
57
+ echo "validate-plugin: FAIL ($violations issues)"
58
+ [[ "$WARN_ONLY" == true ]] && exit 0
59
+ exit 1
60
+ fi
61
+
62
+ # Extract fields
63
+ plugin_name=$(jq -r '.name' "$PLUGIN_DIR/plugin.json")
64
+ plugin_version=$(jq -r '.version' "$PLUGIN_DIR/plugin.json")
65
+ market_name=$(jq -r '.name' "$PLUGIN_DIR/marketplace.json")
66
+ market_version=$(jq -r '.plugins[0].version' "$PLUGIN_DIR/marketplace.json")
67
+
68
+ # Check name match
69
+ if [[ "$plugin_name" != "$market_name" ]]; then
70
+ report_violation "plugin.json" "name mismatch: plugin.json='$plugin_name' marketplace.json='$market_name'"
71
+ fi
72
+
73
+ # Check version match
74
+ if [[ "$plugin_version" != "$market_version" ]]; then
75
+ report_violation "plugin.json" "version mismatch: plugin.json='$plugin_version' marketplace.json='$market_version'"
76
+ fi
77
+
78
+ if [[ $violations -gt 0 ]]; then
79
+ echo ""
80
+ echo "validate-plugin: FAIL ($violations issues)"
81
+ [[ "$WARN_ONLY" == true ]] && exit 0
82
+ exit 1
83
+ else
84
+ echo "validate-plugin: PASS"
85
+ exit 0
86
+ fi
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env bash
2
+ # validate-policies.sh — Validate policy files exist and policy-check runs clean
3
+ # Used by validate-all.sh. Pass --warn to use advisory mode.
4
+ set -euo pipefail
5
+
6
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
+ TOOLKIT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
8
+ POLICY_DIR="$TOOLKIT_ROOT/policies"
9
+ WARN=false
10
+ EXIT_CODE=0
11
+
12
+ [[ "${1:-}" == "--warn" ]] && WARN=true
13
+ [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]] && { echo "Usage: validate-policies.sh [--warn]"; exit 0; }
14
+
15
+ # Check policies directory exists
16
+ if [[ ! -d "$POLICY_DIR" ]]; then
17
+ echo "FAIL: policies/ directory not found"
18
+ [[ "$WARN" == "true" ]] && exit 0 || exit 1
19
+ fi
20
+
21
+ # Check required policy files exist
22
+ required=(universal python bash testing)
23
+ for name in "${required[@]}"; do
24
+ if [[ ! -f "$POLICY_DIR/$name.md" ]]; then
25
+ echo "FAIL: missing policy file: policies/$name.md"
26
+ EXIT_CODE=1
27
+ fi
28
+ done
29
+
30
+ # Check policy files are non-empty
31
+ for f in "$POLICY_DIR"/*.md; do
32
+ if [[ ! -s "$f" ]]; then
33
+ echo "FAIL: empty policy file: $f"
34
+ EXIT_CODE=1
35
+ fi
36
+ done
37
+
38
+ if [[ $EXIT_CODE -eq 0 ]]; then
39
+ echo "validate-policies: PASS"
40
+ fi
41
+
42
+ [[ "$WARN" == "true" ]] && exit 0 || exit $EXIT_CODE