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,146 @@
1
+ #!/usr/bin/env bash
2
+ # module-size-check.sh — Enforce module size limits across the toolkit
3
+ #
4
+ # Usage:
5
+ # module-size-check.sh [options] [path...]
6
+ #
7
+ # Options:
8
+ # --max-lines N Maximum allowed lines per file (default: 300)
9
+ # --exclude PATTERN Glob pattern to exclude (repeatable)
10
+ # --json Output as JSON (for quality-gate integration)
11
+ # --fix-suggestions Include suggested split strategies in output
12
+ # --warn-at N Warn (don't fail) for files between warn-at and max-lines
13
+ # --project-root DIR Project root (default: git root or cwd)
14
+ #
15
+ # If no paths given, scans scripts/**/*.sh (excluding tests/).
16
+ #
17
+ # Exit codes:
18
+ # 0 — all files within limit
19
+ # 1 — one or more files exceed limit
20
+ # 2 — usage error
21
+ set -euo pipefail
22
+
23
+ MAX_LINES=300
24
+ WARN_AT=250
25
+ EXCLUDES=()
26
+ JSON=false
27
+ FIX_SUGGESTIONS=false
28
+ PROJECT_ROOT=""
29
+ PATHS=()
30
+
31
+ while [[ $# -gt 0 ]]; do
32
+ case "$1" in
33
+ --max-lines) MAX_LINES="$2"; shift 2 ;;
34
+ --exclude) EXCLUDES+=("$2"); shift 2 ;;
35
+ --json) JSON=true; shift ;;
36
+ --fix-suggestions) FIX_SUGGESTIONS=true; shift ;;
37
+ --warn-at) WARN_AT="$2"; shift 2 ;;
38
+ --project-root) PROJECT_ROOT="$2"; shift 2 ;;
39
+ --help|-h)
40
+ head -20 "$0" | tail -18
41
+ exit 0
42
+ ;;
43
+ -*) echo "Unknown option: $1" >&2; exit 2 ;;
44
+ *) PATHS+=("$1"); shift ;;
45
+ esac
46
+ done
47
+
48
+ # Resolve project root
49
+ if [[ -z "$PROJECT_ROOT" ]]; then
50
+ PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
51
+ fi
52
+
53
+ # Default scan paths
54
+ if [[ ${#PATHS[@]} -eq 0 ]]; then
55
+ PATHS=("$PROJECT_ROOT/scripts")
56
+ fi
57
+
58
+ # Collect files
59
+ files=()
60
+ for path in "${PATHS[@]}"; do
61
+ if [[ -f "$path" ]]; then
62
+ files+=("$path")
63
+ elif [[ -d "$path" ]]; then
64
+ while IFS= read -r f; do
65
+ files+=("$f")
66
+ done < <(find "$path" -name '*.sh' -not -path '*/tests/*' -not -path '*/.git/*' | sort)
67
+ fi
68
+ done
69
+
70
+ # Apply excludes
71
+ if [[ ${#EXCLUDES[@]} -gt 0 ]]; then
72
+ filtered=()
73
+ for f in "${files[@]}"; do
74
+ skip=false
75
+ for pattern in "${EXCLUDES[@]}"; do
76
+ if [[ "$f" == *"$pattern"* ]]; then
77
+ skip=true
78
+ break
79
+ fi
80
+ done
81
+ [[ "$skip" == false ]] && filtered+=("$f")
82
+ done
83
+ files=("${filtered[@]}")
84
+ fi
85
+
86
+ # Check each file
87
+ violations=0
88
+ warnings=0
89
+ json_entries=()
90
+
91
+ for file in "${files[@]}"; do
92
+ lines=$(wc -l < "$file")
93
+ rel_path="${file#"$PROJECT_ROOT/"}"
94
+
95
+ if [[ $lines -gt $MAX_LINES ]]; then
96
+ violations=$((violations + 1))
97
+ over=$((lines - MAX_LINES))
98
+
99
+ if [[ "$JSON" == true ]]; then
100
+ json_entries+=("{\"file\":\"$rel_path\",\"lines\":$lines,\"limit\":$MAX_LINES,\"over\":$over,\"severity\":\"error\"}")
101
+ else
102
+ echo "ERROR: $rel_path: $lines lines (limit: $MAX_LINES, over by $over)"
103
+ if [[ "$FIX_SUGGESTIONS" == true ]]; then
104
+ # Count functions as a rough split indicator
105
+ func_count=$(grep -cE '^[a-zA-Z_][a-zA-Z_0-9]*\(\)\s*\{' "$file" 2>/dev/null || echo "0")
106
+ if [[ $func_count -gt 1 ]]; then
107
+ echo " Suggestion: $func_count functions detected — extract into separate lib modules"
108
+ else
109
+ echo " Suggestion: look for inline blocks (loops, conditionals) that can become functions"
110
+ fi
111
+ fi
112
+ fi
113
+ elif [[ $lines -gt $WARN_AT ]]; then
114
+ warnings=$((warnings + 1))
115
+ if [[ "$JSON" == true ]]; then
116
+ json_entries+=("{\"file\":\"$rel_path\",\"lines\":$lines,\"limit\":$MAX_LINES,\"severity\":\"warning\"}")
117
+ else
118
+ echo "WARNING: $rel_path: $lines lines (approaching limit of $MAX_LINES)"
119
+ fi
120
+ fi
121
+ done
122
+
123
+ # Output
124
+ if [[ "$JSON" == true ]]; then
125
+ echo "["
126
+ for ((i = 0; i < ${#json_entries[@]}; i++)); do
127
+ if [[ $i -lt $((${#json_entries[@]} - 1)) ]]; then
128
+ echo " ${json_entries[$i]},"
129
+ else
130
+ echo " ${json_entries[$i]}"
131
+ fi
132
+ done
133
+ echo "]"
134
+ fi
135
+
136
+ # Summary
137
+ total=${#files[@]}
138
+ if [[ "$JSON" != true ]]; then
139
+ echo ""
140
+ echo "Scanned $total files: $violations errors, $warnings warnings (limit: $MAX_LINES, warn: $WARN_AT)"
141
+ fi
142
+
143
+ if [[ $violations -gt 0 ]]; then
144
+ exit 1
145
+ fi
146
+ exit 0
@@ -0,0 +1,5 @@
1
+ id: async-no-await
2
+ message: "async def with no await in body — remove async keyword or add await"
3
+ severity: warning
4
+ language: python
5
+ note: "Requires whole-function analysis — this is a simplified pattern"
@@ -0,0 +1,6 @@
1
+ id: bare-except
2
+ message: "Bare except clause swallows all exceptions — catch a specific exception class"
3
+ severity: error
4
+ language: python
5
+ rule:
6
+ pattern: "except: $$$BODY"
@@ -0,0 +1,6 @@
1
+ id: empty-catch
2
+ message: "Empty catch block silently swallows errors — add logging"
3
+ severity: warning
4
+ language: javascript
5
+ rule:
6
+ pattern: "catch ($ERR) {}"
@@ -0,0 +1,9 @@
1
+ id: hardcoded-localhost
2
+ message: "Hardcoded localhost URL — use environment variable or configuration for host/port"
3
+ severity: warning
4
+ language: python
5
+ rule:
6
+ any:
7
+ - pattern: '"http://localhost:$PORT$REST"'
8
+ - pattern: '"http://127.0.0.1:$PORT$REST"'
9
+ note: "Hardcoded URLs break in containers, CI, and multi-host deployments"
@@ -0,0 +1,12 @@
1
+ id: retry-loop-no-backoff
2
+ message: "Retry loop without backoff — add exponential backoff or sleep between retries"
3
+ severity: warning
4
+ language: python
5
+ rule:
6
+ pattern: |
7
+ for $_ in range($RETRIES):
8
+ try:
9
+ $$$BODY
10
+ except $EXC:
11
+ $$$HANDLER
12
+ note: "Tight retry loops without backoff can DDoS external services and hide transient failures"
@@ -0,0 +1,197 @@
1
+ #!/usr/bin/env bash
2
+ # pipeline-status.sh — Single-command view of Code Factory pipeline status
3
+ #
4
+ # Usage: pipeline-status.sh [--help] [--show-costs] [project-root]
5
+ set -euo pipefail
6
+
7
+ SCRIPT_DIR="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)"
8
+ source "$SCRIPT_DIR/lib/common.sh"
9
+
10
+ SHOW_COSTS=false
11
+ PROJECT_ROOT=""
12
+
13
+ # Parse arguments
14
+ for arg in "$@"; do
15
+ case "$arg" in
16
+ --help|-h)
17
+ echo "pipeline-status.sh — Show Code Factory pipeline status"
18
+ echo "Usage: pipeline-status.sh [--show-costs] [project-root]"
19
+ echo ""
20
+ echo "Options:"
21
+ echo " --show-costs Show per-batch cost breakdown from state file"
22
+ exit 0
23
+ ;;
24
+ --show-costs)
25
+ SHOW_COSTS=true
26
+ ;;
27
+ *)
28
+ PROJECT_ROOT="$arg"
29
+ ;;
30
+ esac
31
+ done
32
+
33
+ PROJECT_ROOT="${PROJECT_ROOT:-.}"
34
+
35
+ echo "═══════════════════════════════════════════════"
36
+ echo " Code Factory Pipeline Status"
37
+ echo "═══════════════════════════════════════════════"
38
+ echo "Project: $(basename "$(realpath "$PROJECT_ROOT")")"
39
+ echo "Type: $(detect_project_type "$PROJECT_ROOT")"
40
+ echo ""
41
+
42
+ # Run-plan state
43
+ STATE_FILE="$PROJECT_ROOT/.run-plan-state.json"
44
+ if [[ -f "$STATE_FILE" ]]; then
45
+ echo "--- Run Plan ---"
46
+ plan=$(jq -r '.plan_file // "unknown"' "$STATE_FILE")
47
+ mode=$(jq -r '.mode // "unknown"' "$STATE_FILE")
48
+ current=$(jq -r '.current_batch // 0' "$STATE_FILE")
49
+ completed=$(jq -r '.completed_batches | length' "$STATE_FILE")
50
+ started=$(jq -r '.started_at // "unknown"' "$STATE_FILE")
51
+ echo " Plan: $(basename "$plan")"
52
+ echo " Mode: $mode"
53
+ echo " Progress: $completed batches completed (current: $current)"
54
+ echo " Started: $started"
55
+
56
+ # Last quality gate
57
+ gate_passed=$(jq -r '.last_quality_gate.passed // "n/a"' "$STATE_FILE")
58
+ gate_tests=$(jq -r '.last_quality_gate.test_count // "n/a"' "$STATE_FILE")
59
+ echo " Last gate: passed=$gate_passed, tests=$gate_tests"
60
+
61
+ # Cost summary: total from state file costs map (if present)
62
+ # Fix #70: .costs values may be objects (from record_batch_cost) or plain numbers/strings (legacy).
63
+ # Try .estimated_cost_usd first, then tonumber for backward compat.
64
+ total_cost=$(jq -r '
65
+ if .costs then
66
+ (.costs | to_entries | map(
67
+ if .value | type == "object" then (.value.estimated_cost_usd // 0)
68
+ else (.value | tonumber? // 0) end
69
+ ) | add // 0)
70
+ else 0 end
71
+ ' "$STATE_FILE" 2>/dev/null || echo "0")
72
+ if [[ "$total_cost" != "0" && "$total_cost" != "null" && -n "$total_cost" ]]; then
73
+ echo " Total cost: \$$total_cost"
74
+ fi
75
+ echo ""
76
+ else
77
+ echo "--- Run Plan ---"
78
+ echo " No active run-plan state found"
79
+ echo ""
80
+ fi
81
+
82
+ # PRD status
83
+ if [[ -f "$PROJECT_ROOT/tasks/prd.json" ]]; then
84
+ echo "--- PRD ---"
85
+ total=$(jq 'length' "$PROJECT_ROOT/tasks/prd.json")
86
+ passing=$(jq '[.[] | select(.passes == true)] | length' "$PROJECT_ROOT/tasks/prd.json")
87
+ echo " Tasks: $passing/$total passing"
88
+ echo ""
89
+ else
90
+ echo "--- PRD ---"
91
+ echo " No PRD found (tasks/prd.json)"
92
+ echo ""
93
+ fi
94
+
95
+ # MAB status
96
+ PERF_FILE="$PROJECT_ROOT/logs/strategy-perf.json"
97
+ LESSONS_FILE="$PROJECT_ROOT/logs/mab-lessons.json"
98
+ if [[ -f "$PERF_FILE" ]]; then
99
+ echo "--- MAB (Multi-Armed Bandit) ---"
100
+ cal_count=$(jq -r '.calibration_count // 0' "$PERF_FILE" 2>/dev/null)
101
+ cal_complete=$(jq -r '.calibration_complete // false' "$PERF_FILE" 2>/dev/null)
102
+ echo " Calibration: $cal_count/10 (complete: $cal_complete)"
103
+
104
+ # Per-type win rates
105
+ for bt in "new-file" "refactoring" "integration" "test-only"; do
106
+ sp_w=$(jq -r --arg bt "$bt" '.[$bt].superpowers.wins // 0' "$PERF_FILE" 2>/dev/null)
107
+ sp_l=$(jq -r --arg bt "$bt" '.[$bt].superpowers.losses // 0' "$PERF_FILE" 2>/dev/null)
108
+ r_w=$(jq -r --arg bt "$bt" '.[$bt].ralph.wins // 0' "$PERF_FILE" 2>/dev/null)
109
+ r_l=$(jq -r --arg bt "$bt" '.[$bt].ralph.losses // 0' "$PERF_FILE" 2>/dev/null)
110
+ sp_total=$((sp_w + sp_l))
111
+ r_total=$((r_w + r_l))
112
+ if [[ $sp_total -gt 0 || $r_total -gt 0 ]]; then
113
+ echo " $bt: superpowers=${sp_w}W/${sp_l}L ralph=${r_w}W/${r_l}L"
114
+ fi
115
+ done
116
+
117
+ # Lesson count
118
+ if [[ -f "$LESSONS_FILE" ]]; then
119
+ lesson_count=$(jq 'length' "$LESSONS_FILE" 2>/dev/null || echo "0")
120
+ echo " Lessons: $lesson_count patterns recorded"
121
+ fi
122
+ echo ""
123
+ fi
124
+
125
+ # Cost breakdown (--show-costs) (#42/#43)
126
+ # Filter to numeric-only batch keys before sort to avoid tonumber crash on "final" or other non-numeric keys.
127
+ if [[ "$SHOW_COSTS" == "true" && -f "$STATE_FILE" ]]; then
128
+ echo "--- Cost Breakdown ---"
129
+ has_costs=$(jq -r 'if .costs then "yes" else "no" end' "$STATE_FILE" 2>/dev/null || echo "no")
130
+ if [[ "$has_costs" == "yes" ]]; then
131
+ jq -r '
132
+ .costs // {} |
133
+ to_entries |
134
+ [.[] | select(.key | test("^[0-9]+$"))] |
135
+ sort_by(.key | tonumber) |
136
+ .[] |
137
+ " Batch \(.key): $\(if .value | type == "object" then .value.estimated_cost_usd // 0 else .value end)"
138
+ ' "$STATE_FILE" 2>/dev/null || echo " (cost data unreadable)"
139
+ else
140
+ echo " No cost data in state file"
141
+ fi
142
+ echo ""
143
+ fi
144
+
145
+ # Progress file
146
+ if [[ -f "$PROJECT_ROOT/progress.txt" ]]; then
147
+ echo "--- Progress ---"
148
+ tail -5 "$PROJECT_ROOT/progress.txt" | sed 's/^/ /'
149
+ echo ""
150
+ fi
151
+
152
+ # Routing decisions
153
+ if [[ -f "$PROJECT_ROOT/logs/routing-decisions.log" ]]; then
154
+ echo "--- Routing Decisions ---"
155
+ tail -20 "$PROJECT_ROOT/logs/routing-decisions.log" | sed 's/^/ /'
156
+ echo ""
157
+ fi
158
+
159
+ # Git status
160
+ echo "--- Git ---"
161
+ branch=$(git -C "$PROJECT_ROOT" branch --show-current 2>/dev/null || echo "unknown")
162
+ uncommitted=$(git -C "$PROJECT_ROOT" status --porcelain 2>/dev/null | wc -l || echo 0)
163
+ echo " Branch: $branch"
164
+ echo " Uncommitted: $uncommitted files"
165
+
166
+ # Detailed cost breakdown (only with --show-costs)
167
+ if [[ "$SHOW_COSTS" == true && -f "$STATE_FILE" ]]; then
168
+ echo ""
169
+ echo "--- Cost Details ---"
170
+ jq -r '
171
+ .costs // {} | to_entries | sort_by(.key | tonumber) |
172
+ .[] | " Batch \(.key): $\(.value.estimated_cost_usd) | \(.value.input_tokens) in | \(.value.output_tokens) out | cache: \(.value.cache_read_tokens) read | \(.value.model // "unknown")"
173
+ ' "$STATE_FILE" 2>/dev/null || echo " No cost data"
174
+ total=$(jq -r '.total_cost_usd // 0' "$STATE_FILE")
175
+ echo " Total: \$${total}"
176
+ echo ""
177
+ fi
178
+
179
+ # Trust score (from telemetry)
180
+ if [[ -x "$SCRIPT_DIR/telemetry.sh" ]]; then
181
+ trust_json=$("$SCRIPT_DIR/telemetry.sh" trust --project-root "$PROJECT_ROOT" 2>/dev/null || echo '{}')
182
+ trust_score=$(echo "$trust_json" | jq -r '.score // "n/a"' 2>/dev/null || echo "n/a")
183
+ trust_level=$(echo "$trust_json" | jq -r '.level // "unknown"' 2>/dev/null || echo "unknown")
184
+ trust_runs=$(echo "$trust_json" | jq -r '.runs // 0' 2>/dev/null || echo "0")
185
+ trust_mode=$(echo "$trust_json" | jq -r '.default_mode // "unknown"' 2>/dev/null || echo "unknown")
186
+
187
+ if [[ "$trust_score" != "n/a" && "$trust_runs" != "0" ]]; then
188
+ echo ""
189
+ echo "--- Trust Score ---"
190
+ echo " Score: ${trust_score}/100 ($trust_runs runs)"
191
+ echo " Level: $trust_level"
192
+ echo " Default mode: $trust_mode"
193
+ fi
194
+ fi
195
+
196
+ echo ""
197
+ echo "═══════════════════════════════════════════════"
@@ -0,0 +1,226 @@
1
+ #!/usr/bin/env bash
2
+ # policy-check.sh — Advisory policy checker
3
+ #
4
+ # Usage: policy-check.sh [--project-root <dir>] [--strict] [--scope <tags>]
5
+ #
6
+ # Reads policies/*.md and checks project files for violations.
7
+ # Advisory mode by default (always exits 0).
8
+ # --strict: exit 1 on any violation.
9
+ #
10
+ # Policy files are markdown with code blocks showing positive patterns.
11
+ # This script checks for the ABSENCE of positive patterns (anti-patterns).
12
+
13
+ set -euo pipefail
14
+
15
+ SCRIPT_DIR="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)"
16
+ TOOLKIT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
17
+ PROJECT_ROOT="."
18
+ STRICT=false
19
+ SCOPE_FILTER=""
20
+ VIOLATIONS=0
21
+
22
+ usage() {
23
+ cat <<'EOF'
24
+ policy-check.sh — Advisory policy checker
25
+
26
+ USAGE:
27
+ policy-check.sh [OPTIONS]
28
+
29
+ OPTIONS:
30
+ --project-root <dir> Project to check (default: current directory)
31
+ --strict Exit 1 on violations (default: advisory, always exit 0)
32
+ --scope <tags> Comma-separated scope tags to filter policies
33
+ -h, --help Show this help
34
+
35
+ POLICIES:
36
+ Reads from policies/ directory in the toolkit root.
37
+ Each .md file defines positive patterns for a language or domain.
38
+
39
+ EXIT CODES:
40
+ 0 Advisory mode (default) — always exits 0, prints violations to stdout
41
+ 0 Strict mode — no violations found
42
+ 1 Strict mode — violations found
43
+ EOF
44
+ }
45
+
46
+ # Parse args
47
+ while [[ $# -gt 0 ]]; do
48
+ case $1 in
49
+ --project-root) PROJECT_ROOT="$2"; shift 2 ;;
50
+ --strict) STRICT=true; shift ;;
51
+ --scope) SCOPE_FILTER="$2"; shift 2 ;;
52
+ -h|--help) usage; exit 0 ;;
53
+ -*) echo "Unknown option: $1" >&2; exit 1 ;;
54
+ *) PROJECT_ROOT="$1"; shift ;;
55
+ esac
56
+ done
57
+
58
+ if [[ ! -d "$PROJECT_ROOT" ]]; then
59
+ echo "Error: project directory not found: $PROJECT_ROOT" >&2
60
+ exit 1
61
+ fi
62
+
63
+ POLICY_DIR="$TOOLKIT_ROOT/policies"
64
+ if [[ ! -d "$POLICY_DIR" ]]; then
65
+ echo "Error: policies directory not found: $POLICY_DIR" >&2
66
+ exit 1
67
+ fi
68
+
69
+ # Detect project language
70
+ detect_language() {
71
+ local dir="$1"
72
+ local langs=""
73
+ if [[ -f "$dir/setup.py" ]] || [[ -f "$dir/pyproject.toml" ]] || [[ -f "$dir/requirements.txt" ]]; then
74
+ langs+="python "
75
+ fi
76
+ if [[ -f "$dir/package.json" ]]; then
77
+ langs+="node "
78
+ fi
79
+ # Check for shell scripts
80
+ if find "$dir" -maxdepth 2 -name '*.sh' -print -quit 2>/dev/null | grep -q .; then
81
+ langs+="bash "
82
+ fi
83
+ if [[ -f "$dir/Makefile" ]]; then
84
+ langs+="make "
85
+ fi
86
+ echo "$langs"
87
+ }
88
+
89
+ # Check: bash scripts have strict mode
90
+ check_bash_strict_mode() {
91
+ local dir="$1"
92
+ local count=0
93
+ while IFS= read -r script; do
94
+ [[ -z "$script" ]] && continue
95
+ # Library files (sourced, not executed directly) inherit strict mode
96
+ if [[ "$(basename "$(dirname "$script")")" == "lib" ]]; then
97
+ continue
98
+ fi
99
+ if ! head -15 "$script" | grep -q 'set -.*e'; then
100
+ echo " POLICY: $script — missing strict mode (set -euo pipefail)"
101
+ count=$((count + 1))
102
+ fi
103
+ done < <(find "$dir" -name '*.sh' -not -path '*/.git/*' -not -path '*/node_modules/*' 2>/dev/null)
104
+ return $count
105
+ }
106
+
107
+ # Check: bash scripts quote variables in conditionals
108
+ check_bash_quoting() {
109
+ local dir="$1"
110
+ local count=0
111
+ while IFS= read -r script; do
112
+ [[ -z "$script" ]] && continue
113
+ # Look for unquoted $VAR in [[ ]] conditionals (simplified check)
114
+ if grep -En '\[\[.*\$[A-Za-z_]+[^"}\]]' "$script" 2>/dev/null | grep -v '#' | head -3 | grep -q .; then
115
+ echo " POLICY: $script — possible unquoted variable in conditional"
116
+ count=$((count + 1))
117
+ fi
118
+ done < <(find "$dir" -name '*.sh' -not -path '*/.git/*' -not -path '*/node_modules/*' 2>/dev/null)
119
+ return $count
120
+ }
121
+
122
+ # Check: python files use closing() for sqlite
123
+ check_python_sqlite_closing() {
124
+ local dir="$1"
125
+ local count=0
126
+ while IFS= read -r pyfile; do
127
+ [[ -z "$pyfile" ]] && continue
128
+ if grep -q 'sqlite3\.connect' "$pyfile" 2>/dev/null; then
129
+ if ! grep -q 'closing(' "$pyfile" 2>/dev/null; then
130
+ echo " POLICY: $pyfile — sqlite3.connect without closing() context manager"
131
+ count=$((count + 1))
132
+ fi
133
+ fi
134
+ done < <(find "$dir" -name '*.py' -not -path '*/.git/*' -not -path '*/node_modules/*' -not -path '*/.venv/*' 2>/dev/null)
135
+ return $count
136
+ }
137
+
138
+ # Check: python async defs have await
139
+ check_python_async_await() {
140
+ local dir="$1"
141
+ local count=0
142
+ # This is a simplified heuristic — the lesson-scanner does deeper analysis
143
+ while IFS= read -r pyfile; do
144
+ [[ -z "$pyfile" ]] && continue
145
+ # Find async def functions and check if they contain await
146
+ if grep -q 'async def' "$pyfile" 2>/dev/null; then
147
+ # Very rough check: file has async def but no await at all
148
+ if ! grep -q 'await ' "$pyfile" 2>/dev/null; then
149
+ echo " POLICY: $pyfile — async def without any await (may be unnecessary async)"
150
+ count=$((count + 1))
151
+ fi
152
+ fi
153
+ done < <(find "$dir" -name '*.py' -not -path '*/.git/*' -not -path '*/node_modules/*' -not -path '*/.venv/*' 2>/dev/null)
154
+ return $count
155
+ }
156
+
157
+ # Check: test files don't have hardcoded counts
158
+ check_test_hardcoded_counts() {
159
+ local dir="$1"
160
+ local count=0
161
+ while IFS= read -r testfile; do
162
+ [[ -z "$testfile" ]] && continue
163
+ # Look for exact equality assertions on counts
164
+ if grep -En 'assert.*==[[:space:]]*[0-9]{2,}|assertEquals.*[0-9]{2,}|-eq[[:space:]]+[0-9]{2,}' "$testfile" 2>/dev/null | head -3 | grep -q .; then
165
+ echo " POLICY: $testfile — possible hardcoded test count assertion"
166
+ count=$((count + 1))
167
+ fi
168
+ done < <(find "$dir" \( -name 'test_*.py' -o -name '*_test.py' -o -name 'test-*.sh' -o -name '*.test.js' -o -name '*.test.ts' \) -not -path '*/.git/*' -not -path '*/node_modules/*' -not -path '*/.venv/*' 2>/dev/null)
169
+ return $count
170
+ }
171
+
172
+ # Main
173
+ echo "POLICY CHECK: $PROJECT_ROOT"
174
+ echo ""
175
+
176
+ languages=$(detect_language "$PROJECT_ROOT")
177
+ echo "Detected languages: ${languages:-none}"
178
+ echo ""
179
+
180
+ # Run applicable checks
181
+ for policy_file in "$POLICY_DIR"/*.md; do
182
+ policy_name=$(basename "$policy_file" .md)
183
+
184
+ case "$policy_name" in
185
+ universal)
186
+ echo "Checking: universal policies"
187
+ # Universal checks are mostly process-level, hard to check statically
188
+ echo " (process-level policies — checked by skill, not script)"
189
+ echo ""
190
+ ;;
191
+ bash)
192
+ if echo "$languages" | grep -q 'bash'; then
193
+ echo "Checking: bash policies"
194
+ violations_before=$VIOLATIONS
195
+ check_bash_strict_mode "$PROJECT_ROOT" || VIOLATIONS=$((VIOLATIONS + $?))
196
+ echo ""
197
+ fi
198
+ ;;
199
+ python)
200
+ if echo "$languages" | grep -q 'python'; then
201
+ echo "Checking: python policies"
202
+ check_python_sqlite_closing "$PROJECT_ROOT" || VIOLATIONS=$((VIOLATIONS + $?))
203
+ check_python_async_await "$PROJECT_ROOT" || VIOLATIONS=$((VIOLATIONS + $?))
204
+ echo ""
205
+ fi
206
+ ;;
207
+ testing)
208
+ echo "Checking: testing policies"
209
+ check_test_hardcoded_counts "$PROJECT_ROOT" || VIOLATIONS=$((VIOLATIONS + $?))
210
+ echo ""
211
+ ;;
212
+ esac
213
+ done
214
+
215
+ # Summary
216
+ echo "─────────────────────────────────────"
217
+ if [[ $VIOLATIONS -gt 0 ]]; then
218
+ echo "POLICY CHECK: $VIOLATIONS violation(s) found"
219
+ if [[ "$STRICT" == "true" ]]; then
220
+ exit 1
221
+ fi
222
+ else
223
+ echo "POLICY CHECK: clean (no violations)"
224
+ fi
225
+
226
+ exit 0