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,159 @@
1
+ #!/usr/bin/env bash
2
+ # scope-infer.sh — Infer scope tags for lessons missing them
3
+ # Reads lesson content and applies heuristics to propose scope tags.
4
+ set -euo pipefail
5
+
6
+ SCRIPT_DIR="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)"
7
+
8
+ # Defaults
9
+ LESSONS_DIR="$SCRIPT_DIR/../docs/lessons"
10
+ DRY_RUN=true
11
+ APPLY=false
12
+
13
+ usage() {
14
+ cat <<USAGE
15
+ Usage: scope-infer.sh [--dir <lessons-dir>] [--dry-run] [--apply]
16
+
17
+ Infer scope tags for lesson files that don't have a scope: field.
18
+
19
+ Options:
20
+ --dir <path> Lessons directory (default: docs/lessons/)
21
+ --dry-run Show proposed scope without modifying files (default)
22
+ --apply Write scope field into lesson files
23
+ --help, -h Show this help
24
+ USAGE
25
+ }
26
+
27
+ while [[ $# -gt 0 ]]; do
28
+ case "$1" in
29
+ --dir) LESSONS_DIR="$2"; shift 2 ;;
30
+ --dry-run) DRY_RUN=true; APPLY=false; shift ;;
31
+ --apply) APPLY=true; DRY_RUN=false; shift ;;
32
+ --help|-h) usage; exit 0 ;;
33
+ *) echo "Unknown flag: $1" >&2; usage >&2; exit 1 ;;
34
+ esac
35
+ done
36
+
37
+ # Counters
38
+ total=0
39
+ inferred=0
40
+ skipped=0
41
+ count_universal=0
42
+ count_language=0
43
+ count_domain=0
44
+ count_project=0
45
+
46
+ infer_scope() {
47
+ local file="$1"
48
+ local content
49
+ content=$(cat "$file")
50
+
51
+ # Domain signals (check title + body)
52
+ local title_and_body
53
+ title_and_body=$(echo "$content" | tr '[:upper:]' '[:lower:]')
54
+
55
+ # Domain: ha-aria
56
+ if echo "$title_and_body" | grep -qE '(home assistant|\bha\b|entity.*area|automation.*trigger|hass|ha-aria)'; then
57
+ echo "domain:ha-aria"
58
+ return
59
+ fi
60
+
61
+ # Domain: telegram
62
+ if echo "$title_and_body" | grep -qE '(telegram|bot.*poll|getupdates|chat_id|telegram-brief|telegram-capture)'; then
63
+ echo "domain:telegram"
64
+ return
65
+ fi
66
+
67
+ # Domain: notion
68
+ if echo "$title_and_body" | grep -qE '(\bnotion\b|notion.*sync|notion.*database|notion-tools|notion_api)'; then
69
+ echo "domain:notion"
70
+ return
71
+ fi
72
+
73
+ # Domain: ollama
74
+ if echo "$title_and_body" | grep -qE '(\bollama\b|ollama.*queue|local.*llm|ollama-queue)'; then
75
+ echo "domain:ollama"
76
+ return
77
+ fi
78
+
79
+ # Framework: systemd
80
+ if echo "$title_and_body" | grep -qE '(systemd|systemctl|\.service|\.timer|journalctl|envfile)'; then
81
+ echo "framework:systemd"
82
+ return
83
+ fi
84
+
85
+ # Framework: pytest
86
+ if echo "$title_and_body" | grep -qE '(\bpytest\b|conftest|fixture|parametrize)'; then
87
+ echo "framework:pytest"
88
+ return
89
+ fi
90
+
91
+ # Framework: preact/jsx
92
+ if echo "$title_and_body" | grep -qE '(\bpreact\b|\bjsx\b|esbuild.*jsx|jsx.*factory)'; then
93
+ echo "framework:preact"
94
+ return
95
+ fi
96
+
97
+ # Project-specific: autonomous-coding-toolkit
98
+ if echo "$title_and_body" | grep -qE '(run-plan|quality.gate|lesson-check|mab-run|batch.*audit|ralph.*loop|headless.*mode)'; then
99
+ echo "project:autonomous-coding-toolkit"
100
+ return
101
+ fi
102
+
103
+ # Language: check the languages field
104
+ local languages
105
+ languages=$(sed -n '/^---$/,/^---$/{ /^languages:/p; }' "$file" 2>/dev/null | head -1)
106
+ languages=$(echo "$languages" | sed 's/languages:[[:space:]]*//' | tr -d '[]' | tr ',' ' ' | xargs)
107
+
108
+ if [[ "$languages" == "python" ]]; then
109
+ echo "language:python"
110
+ return
111
+ elif [[ "$languages" == "shell" ]]; then
112
+ echo "language:bash"
113
+ return
114
+ elif [[ "$languages" == "javascript" || "$languages" == "typescript" ]]; then
115
+ echo "language:javascript"
116
+ return
117
+ fi
118
+
119
+ # No signals → universal
120
+ echo "universal"
121
+ }
122
+
123
+ for lesson_file in "$LESSONS_DIR"/[0-9]*.md; do
124
+ [[ -f "$lesson_file" ]] || continue
125
+ total=$((total + 1))
126
+
127
+ # Check if scope already present
128
+ if sed -n '/^---$/,/^---$/p' "$lesson_file" | grep -q '^scope:'; then
129
+ skipped=$((skipped + 1))
130
+ continue
131
+ fi
132
+
133
+ scope=$(infer_scope "$lesson_file")
134
+ inferred=$((inferred + 1))
135
+
136
+ # Count by type
137
+ case "$scope" in
138
+ universal) count_universal=$((count_universal + 1)) ;;
139
+ language:*) count_language=$((count_language + 1)) ;;
140
+ domain:*) count_domain=$((count_domain + 1)) ;;
141
+ project:*) count_project=$((count_project + 1)) ;;
142
+ framework:*) count_language=$((count_language + 1)) ;; # group with language
143
+ esac
144
+
145
+ basename_file=$(basename "$lesson_file")
146
+
147
+ if [[ "$APPLY" == true ]]; then
148
+ # Insert scope: [$scope] after the languages: line in YAML frontmatter
149
+ sed -i "/^languages:/a scope: [$scope]" "$lesson_file"
150
+ echo " APPLIED: $basename_file → scope: [$scope]"
151
+ else
152
+ echo " PROPOSED: $basename_file → scope: [$scope]"
153
+ fi
154
+ done
155
+
156
+ echo ""
157
+ echo "Inferred scope for $inferred lessons: $count_universal universal, $count_domain domain-specific, $count_language language/framework, $count_project project-specific"
158
+ echo "Skipped $skipped lessons (already have scope)"
159
+ echo "Total: $total lessons scanned"
@@ -0,0 +1,155 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Ralph Loop Setup Script
4
+ # Creates state file for in-session Ralph loop
5
+
6
+ set -euo pipefail
7
+
8
+ # Parse arguments
9
+ PROMPT_PARTS=()
10
+ MAX_ITERATIONS=0
11
+ COMPLETION_PROMISE="null"
12
+
13
+ # Parse options and positional arguments
14
+ while [[ $# -gt 0 ]]; do
15
+ case $1 in
16
+ -h|--help)
17
+ cat << 'HELP_EOF'
18
+ Ralph Loop - Interactive self-referential development loop
19
+
20
+ USAGE:
21
+ /ralph-loop [PROMPT...] [OPTIONS]
22
+
23
+ ARGUMENTS:
24
+ PROMPT... Initial prompt to start the loop (can be multiple words without quotes)
25
+
26
+ OPTIONS:
27
+ --max-iterations <n> Maximum iterations before auto-stop (default: unlimited)
28
+ --completion-promise '<text>' Promise phrase (USE QUOTES for multi-word)
29
+ -h, --help Show this help message
30
+
31
+ DESCRIPTION:
32
+ Starts a Ralph Loop in your CURRENT session. The stop hook prevents
33
+ exit and feeds your output back as input until completion or iteration limit.
34
+
35
+ To signal completion, you must output: <promise>YOUR_PHRASE</promise>
36
+
37
+ EXAMPLES:
38
+ /ralph-loop Build a todo API --completion-promise 'DONE' --max-iterations 20
39
+ /ralph-loop --max-iterations 10 Fix the auth bug
40
+ /ralph-loop Refactor cache layer (runs forever)
41
+
42
+ STOPPING:
43
+ Only by reaching --max-iterations or detecting --completion-promise
44
+ No manual stop - Ralph runs infinitely by default!
45
+ HELP_EOF
46
+ exit 0
47
+ ;;
48
+ --max-iterations)
49
+ if [[ -z "${2:-}" ]]; then
50
+ echo "Error: --max-iterations requires a number argument" >&2
51
+ exit 1
52
+ fi
53
+ if ! [[ "$2" =~ ^[0-9]+$ ]]; then
54
+ echo "Error: --max-iterations must be a positive integer or 0, got: $2" >&2
55
+ exit 1
56
+ fi
57
+ MAX_ITERATIONS="$2"
58
+ shift 2
59
+ ;;
60
+ --completion-promise)
61
+ if [[ -z "${2:-}" ]]; then
62
+ echo "Error: --completion-promise requires a text argument" >&2
63
+ exit 1
64
+ fi
65
+ COMPLETION_PROMISE="$2"
66
+ shift 2
67
+ ;;
68
+ *)
69
+ PROMPT_PARTS+=("$1")
70
+ shift
71
+ ;;
72
+ esac
73
+ done
74
+
75
+ # Join all prompt parts with spaces
76
+ PROMPT="${PROMPT_PARTS[*]}"
77
+
78
+ # Validate prompt is non-empty
79
+ if [[ -z "$PROMPT" ]]; then
80
+ echo "Error: No prompt provided" >&2
81
+ echo "Usage: /ralph-loop PROMPT [--max-iterations N] [--completion-promise TEXT]" >&2
82
+ exit 1
83
+ fi
84
+
85
+ # Create state file for stop hook (markdown with YAML frontmatter)
86
+ mkdir -p .claude
87
+
88
+ # Quote completion promise for YAML safely via jq JSON encoding.
89
+ # Note: jq produces JSON-escaped output (\n, \t become literal two-char sequences).
90
+ # This is correct for YAML scalar values parsed by the stop hook's sed-based reader.
91
+ if [[ -n "$COMPLETION_PROMISE" ]] && [[ "$COMPLETION_PROMISE" != "null" ]]; then
92
+ COMPLETION_PROMISE_YAML=$(jq -n --arg cp "$COMPLETION_PROMISE" '$cp')
93
+ else
94
+ COMPLETION_PROMISE_YAML="null"
95
+ fi
96
+
97
+ cat > .claude/ralph-loop.local.md <<EOF
98
+ ---
99
+ active: true
100
+ iteration: 1
101
+ max_iterations: $MAX_ITERATIONS
102
+ completion_promise: $COMPLETION_PROMISE_YAML
103
+ started_at: "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
104
+ ---
105
+
106
+ $PROMPT
107
+ EOF
108
+
109
+ # Output setup message
110
+ cat <<EOF
111
+ Ralph loop activated in this session!
112
+
113
+ Iteration: 1
114
+ Max iterations: $(if [[ $MAX_ITERATIONS -gt 0 ]]; then echo $MAX_ITERATIONS; else echo "unlimited"; fi)
115
+ Completion promise: $(if [[ "$COMPLETION_PROMISE" != "null" ]]; then echo "$COMPLETION_PROMISE (ONLY output when TRUE - do not lie!)"; else echo "none (runs forever)"; fi)
116
+
117
+ The stop hook is now active. When you try to exit, the SAME PROMPT will be
118
+ fed back to you. You'll see your previous work in files, creating a
119
+ self-referential loop where you iteratively improve on the same task.
120
+
121
+ To monitor: head -10 .claude/ralph-loop.local.md
122
+
123
+ WARNING: This loop cannot be stopped manually! It will run infinitely
124
+ unless you set --max-iterations or --completion-promise.
125
+ EOF
126
+
127
+ # Output the initial prompt if provided
128
+ if [[ -n "$PROMPT" ]]; then
129
+ echo ""
130
+ echo "$PROMPT"
131
+ fi
132
+
133
+ # Display completion promise requirements if set
134
+ if [[ "$COMPLETION_PROMISE" != "null" ]]; then
135
+ echo ""
136
+ echo "======================================================="
137
+ echo "CRITICAL - Ralph Loop Completion Promise"
138
+ echo "======================================================="
139
+ echo ""
140
+ echo "To complete this loop, output this EXACT text:"
141
+ echo " <promise>$COMPLETION_PROMISE</promise>"
142
+ echo ""
143
+ echo "STRICT REQUIREMENTS (DO NOT VIOLATE):"
144
+ echo " - Use <promise> XML tags EXACTLY as shown above"
145
+ echo " - The statement MUST be completely and unequivocally TRUE"
146
+ echo " - Do NOT output false statements to exit the loop"
147
+ echo " - Do NOT lie even if you think you should exit"
148
+ echo ""
149
+ echo "IMPORTANT - Do not circumvent the loop:"
150
+ echo " Even if you believe you're stuck, the task is impossible,"
151
+ echo " or you've been running too long - you MUST NOT output a"
152
+ echo " false promise statement. The loop is designed to continue"
153
+ echo " until the promise is GENUINELY TRUE. Trust the process."
154
+ echo "======================================================="
155
+ fi
@@ -0,0 +1,230 @@
1
+ #!/usr/bin/env bash
2
+ # telemetry.sh — Local telemetry capture, dashboard, export, and import
3
+ #
4
+ # Usage:
5
+ # telemetry.sh record --project-root <dir> [--batch-number N] [--passed true|false] ...
6
+ # telemetry.sh show --project-root <dir>
7
+ # telemetry.sh export --project-root <dir>
8
+ # telemetry.sh import --project-root <dir> <file>
9
+ # telemetry.sh reset --project-root <dir> --yes
10
+ set -euo pipefail
11
+
12
+ SCRIPT_DIR="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)"
13
+ source "$SCRIPT_DIR/lib/common.sh"
14
+
15
+ PROJECT_ROOT=""
16
+ SUBCOMMAND=""
17
+
18
+ # --- Parse top-level ---
19
+ SUBCOMMAND="${1:-}"
20
+ shift || true
21
+
22
+ # Parse remaining args
23
+ BATCH_NUMBER=""
24
+ PASSED=""
25
+ STRATEGY=""
26
+ DURATION=""
27
+ COST=""
28
+ TEST_DELTA=""
29
+ LESSONS_TRIGGERED=""
30
+ PLAN_QUALITY=""
31
+ BATCH_TYPE=""
32
+ CONFIRM_YES=false
33
+
34
+ while [[ $# -gt 0 ]]; do
35
+ case "$1" in
36
+ --project-root) PROJECT_ROOT="${2:-}"; shift 2 ;;
37
+ --batch-number) BATCH_NUMBER="${2:-}"; shift 2 ;;
38
+ --passed) PASSED="${2:-}"; shift 2 ;;
39
+ --strategy) STRATEGY="${2:-}"; shift 2 ;;
40
+ --duration) DURATION="${2:-}"; shift 2 ;;
41
+ --cost) COST="${2:-}"; shift 2 ;;
42
+ --test-delta) TEST_DELTA="${2:-}"; shift 2 ;;
43
+ --lessons-triggered) LESSONS_TRIGGERED="${2:-}"; shift 2 ;;
44
+ --plan-quality) PLAN_QUALITY="${2:-}"; shift 2 ;;
45
+ --batch-type) BATCH_TYPE="${2:-}"; shift 2 ;;
46
+ --yes) CONFIRM_YES=true; shift ;;
47
+ --help|-h) echo "Usage: telemetry.sh <record|show|export|import|reset> --project-root <dir> [options]"; exit 0 ;;
48
+ *)
49
+ # Positional arg (for import file)
50
+ if [[ -z "${IMPORT_FILE:-}" ]]; then
51
+ IMPORT_FILE="$1"
52
+ fi
53
+ shift ;;
54
+ esac
55
+ done
56
+
57
+ if [[ -z "$PROJECT_ROOT" ]]; then
58
+ echo "telemetry: --project-root is required" >&2
59
+ exit 1
60
+ fi
61
+
62
+ TELEMETRY_FILE="$PROJECT_ROOT/logs/telemetry.jsonl"
63
+
64
+ case "$SUBCOMMAND" in
65
+ record)
66
+ mkdir -p "$PROJECT_ROOT/logs"
67
+ # Coerce numeric fields to prevent jq tonumber failures on empty strings
68
+ BATCH_NUMBER="${BATCH_NUMBER:-0}"; BATCH_NUMBER="${BATCH_NUMBER:-0}"
69
+ DURATION="${DURATION:-0}"; COST="${COST:-0}"; TEST_DELTA="${TEST_DELTA:-0}"
70
+ jq -cn \
71
+ --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
72
+ --arg bn "${BATCH_NUMBER:-0}" \
73
+ --arg passed "${PASSED:-false}" \
74
+ --arg strategy "${STRATEGY:-unknown}" \
75
+ --arg duration "${DURATION:-0}" \
76
+ --arg cost "${COST:-0}" \
77
+ --arg td "${TEST_DELTA:-0}" \
78
+ --arg lt "${LESSONS_TRIGGERED:-}" \
79
+ --arg pq "${PLAN_QUALITY:-}" \
80
+ --arg bt "${BATCH_TYPE:-unknown}" \
81
+ --arg pt "$(detect_project_type "$PROJECT_ROOT")" \
82
+ '{
83
+ timestamp: $ts,
84
+ project_type: $pt,
85
+ batch_type: $bt,
86
+ batch_number: ($bn | tonumber),
87
+ passed_gate: ($passed == "true"),
88
+ strategy: $strategy,
89
+ duration_seconds: ($duration | tonumber),
90
+ cost_usd: ($cost | tonumber),
91
+ test_count_delta: ($td | tonumber),
92
+ lessons_triggered: (if $lt == "" then [] else ($lt | split(",")) end),
93
+ plan_quality_score: (if $pq == "" then null else ($pq | tonumber) end)
94
+ }' >> "$TELEMETRY_FILE"
95
+ echo "telemetry: recorded batch $BATCH_NUMBER"
96
+ ;;
97
+
98
+ show)
99
+ echo "Autonomous Coding Toolkit — Telemetry Dashboard"
100
+ echo "════════════════════════════════════════════════"
101
+ echo ""
102
+
103
+ if [[ ! -f "$TELEMETRY_FILE" ]] || [[ ! -s "$TELEMETRY_FILE" ]]; then
104
+ echo "No telemetry data yet. Run some batches first."
105
+ exit 0
106
+ fi
107
+
108
+ # Summary stats
109
+ total=$(wc -l < "$TELEMETRY_FILE")
110
+ passed=$(jq -s '[.[] | select(.passed_gate == true)] | length' "$TELEMETRY_FILE")
111
+ total_cost=$(jq -s '[.[].cost_usd] | add // 0' "$TELEMETRY_FILE")
112
+ total_duration=$(jq -s '[.[].duration_seconds] | add // 0' "$TELEMETRY_FILE")
113
+ avg_cost=$(jq -s 'if length > 0 then ([.[].cost_usd] | add) / length else 0 end' "$TELEMETRY_FILE")
114
+
115
+ echo "Runs: $total batches"
116
+ if [[ "$total" -gt 0 ]]; then
117
+ pct=$((passed * 100 / total))
118
+ echo "Success rate: ${pct}% ($passed/$total passed gate on first attempt)"
119
+ fi
120
+ printf "Total cost: \$%.2f (\$%.2f/batch average)\n" "$total_cost" "$avg_cost"
121
+ hours=$(awk "BEGIN {printf \"%.1f\", $total_duration / 3600}")
122
+ echo "Total time: ${hours} hours"
123
+
124
+ # Strategy performance
125
+ echo ""
126
+ echo "Strategy Performance:"
127
+ jq -s '
128
+ group_by(.strategy) | .[] |
129
+ {
130
+ strategy: .[0].strategy,
131
+ wins: [.[] | select(.passed_gate == true)] | length,
132
+ total: length
133
+ } |
134
+ " \(.strategy): \(.wins)/\(.total) (\(if .total > 0 then (.wins * 100 / .total) else 0 end)% win rate)"
135
+ ' "$TELEMETRY_FILE" 2>/dev/null || echo " (no strategy data)"
136
+
137
+ # Top lesson hits
138
+ echo ""
139
+ echo "Top Lesson Hits:"
140
+ jq -s '
141
+ [.[].lessons_triggered | arrays | .[]] |
142
+ group_by(.) | map({lesson: .[0], count: length}) |
143
+ sort_by(-.count) | .[:5] |
144
+ .[] | " \(.lesson): \(.count) hits"
145
+ ' "$TELEMETRY_FILE" 2>/dev/null || echo " (no lesson data)"
146
+ ;;
147
+
148
+ export)
149
+ if [[ ! -f "$TELEMETRY_FILE" ]]; then
150
+ echo "No telemetry data to export." >&2
151
+ exit 1
152
+ fi
153
+ # Anonymize: remove timestamps precision, no file paths
154
+ jq -s '
155
+ [.[] | {
156
+ project_type,
157
+ batch_type,
158
+ passed_gate,
159
+ strategy,
160
+ duration_seconds,
161
+ cost_usd,
162
+ test_count_delta,
163
+ lessons_triggered,
164
+ plan_quality_score
165
+ }]
166
+ ' "$TELEMETRY_FILE"
167
+ ;;
168
+
169
+ import)
170
+ if [[ -z "${IMPORT_FILE:-}" || ! -f "${IMPORT_FILE:-}" ]]; then
171
+ echo "telemetry: import requires a file argument" >&2
172
+ exit 1
173
+ fi
174
+ echo "telemetry: import not yet implemented (planned for community sync)"
175
+ ;;
176
+
177
+ reset)
178
+ if [[ "$CONFIRM_YES" != true ]]; then
179
+ echo "telemetry: use --yes to confirm reset" >&2
180
+ exit 1
181
+ fi
182
+ if [[ -f "$TELEMETRY_FILE" ]]; then
183
+ > "$TELEMETRY_FILE"
184
+ echo "telemetry: cleared $TELEMETRY_FILE"
185
+ else
186
+ echo "telemetry: no telemetry file to reset"
187
+ fi
188
+ ;;
189
+
190
+ trust)
191
+ if [[ ! -f "$TELEMETRY_FILE" ]] || [[ ! -s "$TELEMETRY_FILE" ]]; then
192
+ echo '{"score":0,"level":"new","runs":0,"message":"No telemetry data yet"}'
193
+ exit 0
194
+ fi
195
+
196
+ jq -s '
197
+ def trust_level(score; runs):
198
+ if runs < 10 then "new"
199
+ elif score < 30 then "new"
200
+ elif score < 70 then "growing"
201
+ elif score < 90 then "trusted"
202
+ else "autonomous"
203
+ end;
204
+
205
+ length as $total |
206
+ ([.[] | select(.passed_gate == true)] | length) as $passed |
207
+ (if $total > 0 then ($passed * 100 / $total) else 0 end) as $gate_rate |
208
+ $gate_rate as $score |
209
+ trust_level($score; $total) as $level |
210
+ {
211
+ score: $score,
212
+ level: $level,
213
+ runs: $total,
214
+ gate_pass_rate: $gate_rate,
215
+ default_mode: (
216
+ if $level == "new" then "human checkpoint every batch"
217
+ elif $level == "growing" then "headless with checkpoint every 3rd batch"
218
+ elif $level == "trusted" then "headless with notification on failures only"
219
+ else "full headless, post-run summary only"
220
+ end
221
+ )
222
+ }
223
+ ' "$TELEMETRY_FILE"
224
+ ;;
225
+
226
+ *)
227
+ echo "Usage: telemetry.sh <record|show|export|import|reset|trust> --project-root <dir>" >&2
228
+ exit 1
229
+ ;;
230
+ esac
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # Test runner that executes all test-*.sh files in the same directory
5
+ # Reports per-file pass/fail and exits non-zero if any fail.
6
+
7
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+ TOTAL=0
9
+ PASSED=0
10
+ FAILED=0
11
+
12
+ # Collect all test files
13
+ mapfile -t TEST_FILES < <(find "$SCRIPT_DIR" -maxdepth 1 -name "test-*.sh" -type f | sort)
14
+
15
+ if [[ ${#TEST_FILES[@]} -eq 0 ]]; then
16
+ echo "No test files found matching test-*.sh" >&2
17
+ exit 1
18
+ fi
19
+
20
+ # Run each test
21
+ for test_file in "${TEST_FILES[@]}"; do
22
+ test_name="$(basename "$test_file")"
23
+ TOTAL=$((TOTAL + 1))
24
+
25
+ # Print header
26
+ echo "═══════════════════════════════════════════"
27
+ echo " Running: $test_name"
28
+ echo "═══════════════════════════════════════════"
29
+
30
+ # Run test and capture exit code
31
+ if bash "$test_file"; then
32
+ PASSED=$((PASSED + 1))
33
+ echo ""
34
+ else
35
+ FAILED=$((FAILED + 1))
36
+ echo ""
37
+ fi
38
+ done
39
+
40
+ # Print summary
41
+ echo "═══════════════════════════════════════════"
42
+ echo " TOTAL: $TOTAL test files"
43
+ echo " PASSED: $PASSED"
44
+ echo " FAILED: $FAILED"
45
+ echo "═══════════════════════════════════════════"
46
+
47
+ # Exit non-zero if any failed
48
+ if [[ $FAILED -gt 0 ]]; then
49
+ exit 1
50
+ fi
51
+
52
+ exit 0
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env bash
2
+ # test-act-cli.sh — Tests for bin/act.js CLI router
3
+ set -euo pipefail
4
+
5
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
+ REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
7
+ source "$SCRIPT_DIR/test-helpers.sh"
8
+
9
+ ACT="$REPO_ROOT/bin/act.js"
10
+
11
+ # ---------------------------------------------------------------------------
12
+ # version command
13
+ # ---------------------------------------------------------------------------
14
+ version_output=$(node "$ACT" version 2>&1)
15
+ assert_contains "version outputs 'act v'" "act v" "$version_output"
16
+
17
+ # ---------------------------------------------------------------------------
18
+ # help command
19
+ # ---------------------------------------------------------------------------
20
+ help_output=$(node "$ACT" help 2>&1)
21
+ assert_contains "help outputs usage line" "Usage: act <command>" "$help_output"
22
+ assert_contains "help lists 'plan' command" "plan" "$help_output"
23
+ assert_contains "help lists 'gate' command" "gate" "$help_output"
24
+
25
+ # ---------------------------------------------------------------------------
26
+ # unknown command exits non-zero
27
+ # ---------------------------------------------------------------------------
28
+ assert_exit "nonexistent command exits 1" 1 node "$ACT" nonexistent-command
29
+
30
+ # ---------------------------------------------------------------------------
31
+ # validate routes to validate-all.sh (output contains "validate")
32
+ # ---------------------------------------------------------------------------
33
+ # validate-all.sh runs validators — we just confirm it was reached by checking
34
+ # that output contains "validate" (the script name / summary line).
35
+ validate_output=$(node "$ACT" validate 2>&1 || true)
36
+ assert_contains "validate routes to validate-all.sh" "validate" "$validate_output"
37
+
38
+ # ---------------------------------------------------------------------------
39
+ # lessons without subcommand exits non-zero and shows usage hint
40
+ # ---------------------------------------------------------------------------
41
+ lessons_exit=0
42
+ lessons_output=$(node "$ACT" lessons 2>&1) || lessons_exit=$?
43
+ assert_exit "lessons without subcommand exits 1" 1 node "$ACT" lessons
44
+ assert_contains "lessons shows usage hint" "lessons" "$lessons_output"
45
+
46
+ report_results