bmalph 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 (396) hide show
  1. package/README.md +217 -0
  2. package/bin/bmalph.js +14 -0
  3. package/bmad/bmm/agents/analyst.agent.yaml +36 -0
  4. package/bmad/bmm/agents/architect.agent.yaml +28 -0
  5. package/bmad/bmm/agents/dev.agent.yaml +38 -0
  6. package/bmad/bmm/agents/pm.agent.yaml +46 -0
  7. package/bmad/bmm/agents/quick-flow-solo-dev.agent.yaml +32 -0
  8. package/bmad/bmm/agents/sm.agent.yaml +36 -0
  9. package/bmad/bmm/agents/tea.agent.yaml +63 -0
  10. package/bmad/bmm/agents/tech-writer/tech-writer-sidecar/documentation-standards.md +224 -0
  11. package/bmad/bmm/agents/tech-writer/tech-writer.agent.yaml +45 -0
  12. package/bmad/bmm/agents/ux-designer.agent.yaml +26 -0
  13. package/bmad/bmm/data/project-context-template.md +26 -0
  14. package/bmad/bmm/module-help.csv +31 -0
  15. package/bmad/bmm/module.yaml +44 -0
  16. package/bmad/bmm/sub-modules/claude-code/config.yaml +4 -0
  17. package/bmad/bmm/sub-modules/claude-code/injections.yaml +242 -0
  18. package/bmad/bmm/sub-modules/claude-code/readme.md +87 -0
  19. package/bmad/bmm/teams/default-party.csv +21 -0
  20. package/bmad/bmm/teams/team-fullstack.yaml +12 -0
  21. package/bmad/bmm/testarch/knowledge/adr-quality-readiness-checklist.md +350 -0
  22. package/bmad/bmm/testarch/knowledge/api-request.md +442 -0
  23. package/bmad/bmm/testarch/knowledge/api-testing-patterns.md +843 -0
  24. package/bmad/bmm/testarch/knowledge/auth-session.md +552 -0
  25. package/bmad/bmm/testarch/knowledge/burn-in.md +273 -0
  26. package/bmad/bmm/testarch/knowledge/ci-burn-in.md +675 -0
  27. package/bmad/bmm/testarch/knowledge/component-tdd.md +486 -0
  28. package/bmad/bmm/testarch/knowledge/contract-testing.md +957 -0
  29. package/bmad/bmm/testarch/knowledge/data-factories.md +500 -0
  30. package/bmad/bmm/testarch/knowledge/email-auth.md +721 -0
  31. package/bmad/bmm/testarch/knowledge/error-handling.md +725 -0
  32. package/bmad/bmm/testarch/knowledge/feature-flags.md +750 -0
  33. package/bmad/bmm/testarch/knowledge/file-utils.md +463 -0
  34. package/bmad/bmm/testarch/knowledge/fixture-architecture.md +401 -0
  35. package/bmad/bmm/testarch/knowledge/fixtures-composition.md +382 -0
  36. package/bmad/bmm/testarch/knowledge/intercept-network-call.md +430 -0
  37. package/bmad/bmm/testarch/knowledge/log.md +429 -0
  38. package/bmad/bmm/testarch/knowledge/network-error-monitor.md +405 -0
  39. package/bmad/bmm/testarch/knowledge/network-first.md +486 -0
  40. package/bmad/bmm/testarch/knowledge/network-recorder.md +527 -0
  41. package/bmad/bmm/testarch/knowledge/nfr-criteria.md +670 -0
  42. package/bmad/bmm/testarch/knowledge/overview.md +286 -0
  43. package/bmad/bmm/testarch/knowledge/playwright-config.md +730 -0
  44. package/bmad/bmm/testarch/knowledge/probability-impact.md +601 -0
  45. package/bmad/bmm/testarch/knowledge/recurse.md +421 -0
  46. package/bmad/bmm/testarch/knowledge/risk-governance.md +615 -0
  47. package/bmad/bmm/testarch/knowledge/selective-testing.md +732 -0
  48. package/bmad/bmm/testarch/knowledge/selector-resilience.md +527 -0
  49. package/bmad/bmm/testarch/knowledge/test-healing-patterns.md +644 -0
  50. package/bmad/bmm/testarch/knowledge/test-levels-framework.md +473 -0
  51. package/bmad/bmm/testarch/knowledge/test-priorities-matrix.md +373 -0
  52. package/bmad/bmm/testarch/knowledge/test-quality.md +664 -0
  53. package/bmad/bmm/testarch/knowledge/timing-debugging.md +372 -0
  54. package/bmad/bmm/testarch/knowledge/visual-debugging.md +524 -0
  55. package/bmad/bmm/testarch/tea-index.csv +35 -0
  56. package/bmad/bmm/workflows/1-analysis/create-product-brief/product-brief.template.md +10 -0
  57. package/bmad/bmm/workflows/1-analysis/create-product-brief/steps/step-01-init.md +177 -0
  58. package/bmad/bmm/workflows/1-analysis/create-product-brief/steps/step-01b-continue.md +161 -0
  59. package/bmad/bmm/workflows/1-analysis/create-product-brief/steps/step-02-vision.md +199 -0
  60. package/bmad/bmm/workflows/1-analysis/create-product-brief/steps/step-03-users.md +202 -0
  61. package/bmad/bmm/workflows/1-analysis/create-product-brief/steps/step-04-metrics.md +205 -0
  62. package/bmad/bmm/workflows/1-analysis/create-product-brief/steps/step-05-scope.md +219 -0
  63. package/bmad/bmm/workflows/1-analysis/create-product-brief/steps/step-06-complete.md +162 -0
  64. package/bmad/bmm/workflows/1-analysis/create-product-brief/workflow.md +58 -0
  65. package/bmad/bmm/workflows/1-analysis/research/domain-steps/step-01-init.md +137 -0
  66. package/bmad/bmm/workflows/1-analysis/research/domain-steps/step-02-domain-analysis.md +229 -0
  67. package/bmad/bmm/workflows/1-analysis/research/domain-steps/step-03-competitive-landscape.md +238 -0
  68. package/bmad/bmm/workflows/1-analysis/research/domain-steps/step-04-regulatory-focus.md +206 -0
  69. package/bmad/bmm/workflows/1-analysis/research/domain-steps/step-05-technical-trends.md +234 -0
  70. package/bmad/bmm/workflows/1-analysis/research/domain-steps/step-06-research-synthesis.md +443 -0
  71. package/bmad/bmm/workflows/1-analysis/research/market-steps/step-01-init.md +182 -0
  72. package/bmad/bmm/workflows/1-analysis/research/market-steps/step-02-customer-behavior.md +237 -0
  73. package/bmad/bmm/workflows/1-analysis/research/market-steps/step-02-customer-insights.md +200 -0
  74. package/bmad/bmm/workflows/1-analysis/research/market-steps/step-03-customer-pain-points.md +249 -0
  75. package/bmad/bmm/workflows/1-analysis/research/market-steps/step-04-customer-decisions.md +259 -0
  76. package/bmad/bmm/workflows/1-analysis/research/market-steps/step-05-competitive-analysis.md +177 -0
  77. package/bmad/bmm/workflows/1-analysis/research/market-steps/step-06-research-completion.md +475 -0
  78. package/bmad/bmm/workflows/1-analysis/research/research.template.md +29 -0
  79. package/bmad/bmm/workflows/1-analysis/research/technical-steps/step-01-init.md +137 -0
  80. package/bmad/bmm/workflows/1-analysis/research/technical-steps/step-02-technical-overview.md +239 -0
  81. package/bmad/bmm/workflows/1-analysis/research/technical-steps/step-03-integration-patterns.md +248 -0
  82. package/bmad/bmm/workflows/1-analysis/research/technical-steps/step-04-architectural-patterns.md +202 -0
  83. package/bmad/bmm/workflows/1-analysis/research/technical-steps/step-05-implementation-research.md +239 -0
  84. package/bmad/bmm/workflows/1-analysis/research/technical-steps/step-06-research-synthesis.md +486 -0
  85. package/bmad/bmm/workflows/1-analysis/research/workflow.md +173 -0
  86. package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-01-init.md +135 -0
  87. package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-01b-continue.md +127 -0
  88. package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-02-discovery.md +190 -0
  89. package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-03-core-experience.md +216 -0
  90. package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-04-emotional-response.md +219 -0
  91. package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-05-inspiration.md +234 -0
  92. package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-06-design-system.md +252 -0
  93. package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-07-defining-experience.md +254 -0
  94. package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-08-visual-foundation.md +224 -0
  95. package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-09-design-directions.md +224 -0
  96. package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-10-user-journeys.md +241 -0
  97. package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-11-component-strategy.md +248 -0
  98. package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-12-ux-patterns.md +237 -0
  99. package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-13-responsive-accessibility.md +264 -0
  100. package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-14-complete.md +171 -0
  101. package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/ux-design-template.md +13 -0
  102. package/bmad/bmm/workflows/2-plan-workflows/create-ux-design/workflow.md +43 -0
  103. package/bmad/bmm/workflows/2-plan-workflows/prd/data/domain-complexity.csv +13 -0
  104. package/bmad/bmm/workflows/2-plan-workflows/prd/data/prd-purpose.md +197 -0
  105. package/bmad/bmm/workflows/2-plan-workflows/prd/data/project-types.csv +11 -0
  106. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-01-init.md +191 -0
  107. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-01b-continue.md +153 -0
  108. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-02-discovery.md +224 -0
  109. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-03-success.md +226 -0
  110. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-04-journeys.md +213 -0
  111. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-05-domain.md +207 -0
  112. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-06-innovation.md +226 -0
  113. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-07-project-type.md +237 -0
  114. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-08-scoping.md +228 -0
  115. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-09-functional.md +231 -0
  116. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-10-nonfunctional.md +242 -0
  117. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-11-polish.md +217 -0
  118. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-c/step-12-complete.md +124 -0
  119. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-e/step-e-01-discovery.md +247 -0
  120. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-e/step-e-01b-legacy-conversion.md +208 -0
  121. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-e/step-e-02-review.md +249 -0
  122. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-e/step-e-03-edit.md +253 -0
  123. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-e/step-e-04-complete.md +168 -0
  124. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-01-discovery.md +218 -0
  125. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-02-format-detection.md +191 -0
  126. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-02b-parity-check.md +209 -0
  127. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-03-density-validation.md +174 -0
  128. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-04-brief-coverage-validation.md +214 -0
  129. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-05-measurability-validation.md +228 -0
  130. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-06-traceability-validation.md +217 -0
  131. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-07-implementation-leakage-validation.md +205 -0
  132. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-08-domain-compliance-validation.md +243 -0
  133. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-09-project-type-validation.md +263 -0
  134. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-10-smart-validation.md +209 -0
  135. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-11-holistic-quality-validation.md +264 -0
  136. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-12-completeness-validation.md +242 -0
  137. package/bmad/bmm/workflows/2-plan-workflows/prd/steps-v/step-v-13-report-complete.md +231 -0
  138. package/bmad/bmm/workflows/2-plan-workflows/prd/templates/prd-template.md +10 -0
  139. package/bmad/bmm/workflows/2-plan-workflows/prd/validation-report-prd-workflow.md +433 -0
  140. package/bmad/bmm/workflows/2-plan-workflows/prd/workflow.md +150 -0
  141. package/bmad/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-01-document-discovery.md +190 -0
  142. package/bmad/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-02-prd-analysis.md +178 -0
  143. package/bmad/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-03-epic-coverage-validation.md +179 -0
  144. package/bmad/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-04-ux-alignment.md +139 -0
  145. package/bmad/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-05-epic-quality-review.md +252 -0
  146. package/bmad/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-06-final-assessment.md +135 -0
  147. package/bmad/bmm/workflows/3-solutioning/check-implementation-readiness/templates/readiness-report-template.md +4 -0
  148. package/bmad/bmm/workflows/3-solutioning/check-implementation-readiness/workflow.md +55 -0
  149. package/bmad/bmm/workflows/3-solutioning/create-architecture/architecture-decision-template.md +12 -0
  150. package/bmad/bmm/workflows/3-solutioning/create-architecture/data/domain-complexity.csv +11 -0
  151. package/bmad/bmm/workflows/3-solutioning/create-architecture/data/project-types.csv +7 -0
  152. package/bmad/bmm/workflows/3-solutioning/create-architecture/steps/step-01-init.md +153 -0
  153. package/bmad/bmm/workflows/3-solutioning/create-architecture/steps/step-01b-continue.md +164 -0
  154. package/bmad/bmm/workflows/3-solutioning/create-architecture/steps/step-02-context.md +224 -0
  155. package/bmad/bmm/workflows/3-solutioning/create-architecture/steps/step-03-starter.md +331 -0
  156. package/bmad/bmm/workflows/3-solutioning/create-architecture/steps/step-04-decisions.md +318 -0
  157. package/bmad/bmm/workflows/3-solutioning/create-architecture/steps/step-05-patterns.md +359 -0
  158. package/bmad/bmm/workflows/3-solutioning/create-architecture/steps/step-06-structure.md +379 -0
  159. package/bmad/bmm/workflows/3-solutioning/create-architecture/steps/step-07-validation.md +359 -0
  160. package/bmad/bmm/workflows/3-solutioning/create-architecture/steps/step-08-complete.md +76 -0
  161. package/bmad/bmm/workflows/3-solutioning/create-architecture/workflow.md +50 -0
  162. package/bmad/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-01-validate-prerequisites.md +259 -0
  163. package/bmad/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-02-design-epics.md +233 -0
  164. package/bmad/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-03-create-stories.md +272 -0
  165. package/bmad/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-04-final-validation.md +149 -0
  166. package/bmad/bmm/workflows/3-solutioning/create-epics-and-stories/templates/epics-template.md +57 -0
  167. package/bmad/bmm/workflows/3-solutioning/create-epics-and-stories/workflow.md +59 -0
  168. package/bmad/bmm/workflows/4-implementation/code-review/checklist.md +23 -0
  169. package/bmad/bmm/workflows/4-implementation/code-review/instructions.xml +227 -0
  170. package/bmad/bmm/workflows/4-implementation/code-review/workflow.yaml +51 -0
  171. package/bmad/bmm/workflows/4-implementation/correct-course/checklist.md +288 -0
  172. package/bmad/bmm/workflows/4-implementation/correct-course/instructions.md +206 -0
  173. package/bmad/bmm/workflows/4-implementation/correct-course/workflow.yaml +60 -0
  174. package/bmad/bmm/workflows/4-implementation/create-story/checklist.md +358 -0
  175. package/bmad/bmm/workflows/4-implementation/create-story/instructions.xml +345 -0
  176. package/bmad/bmm/workflows/4-implementation/create-story/template.md +49 -0
  177. package/bmad/bmm/workflows/4-implementation/create-story/workflow.yaml +61 -0
  178. package/bmad/bmm/workflows/4-implementation/dev-story/checklist.md +80 -0
  179. package/bmad/bmm/workflows/4-implementation/dev-story/instructions.xml +410 -0
  180. package/bmad/bmm/workflows/4-implementation/dev-story/workflow.yaml +27 -0
  181. package/bmad/bmm/workflows/4-implementation/retrospective/instructions.md +1443 -0
  182. package/bmad/bmm/workflows/4-implementation/retrospective/workflow.yaml +58 -0
  183. package/bmad/bmm/workflows/4-implementation/sprint-planning/checklist.md +33 -0
  184. package/bmad/bmm/workflows/4-implementation/sprint-planning/instructions.md +225 -0
  185. package/bmad/bmm/workflows/4-implementation/sprint-planning/sprint-status-template.yaml +55 -0
  186. package/bmad/bmm/workflows/4-implementation/sprint-planning/workflow.yaml +54 -0
  187. package/bmad/bmm/workflows/4-implementation/sprint-status/instructions.md +229 -0
  188. package/bmad/bmm/workflows/4-implementation/sprint-status/workflow.yaml +36 -0
  189. package/bmad/bmm/workflows/bmad-quick-flow/quick-dev/data/project-levels.yaml +59 -0
  190. package/bmad/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-01-mode-detection.md +156 -0
  191. package/bmad/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-02-context-gathering.md +120 -0
  192. package/bmad/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-03-execute.md +113 -0
  193. package/bmad/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-04-self-check.md +113 -0
  194. package/bmad/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-05-adversarial-review.md +106 -0
  195. package/bmad/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-06-resolve-findings.md +140 -0
  196. package/bmad/bmm/workflows/bmad-quick-flow/quick-dev/workflow.md +50 -0
  197. package/bmad/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-01-understand.md +189 -0
  198. package/bmad/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-02-investigate.md +144 -0
  199. package/bmad/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-03-generate.md +128 -0
  200. package/bmad/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-04-review.md +191 -0
  201. package/bmad/bmm/workflows/bmad-quick-flow/quick-spec/tech-spec-template.md +74 -0
  202. package/bmad/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md +79 -0
  203. package/bmad/bmm/workflows/document-project/checklist.md +245 -0
  204. package/bmad/bmm/workflows/document-project/documentation-requirements.csv +12 -0
  205. package/bmad/bmm/workflows/document-project/instructions.md +221 -0
  206. package/bmad/bmm/workflows/document-project/templates/deep-dive-template.md +345 -0
  207. package/bmad/bmm/workflows/document-project/templates/index-template.md +169 -0
  208. package/bmad/bmm/workflows/document-project/templates/project-overview-template.md +103 -0
  209. package/bmad/bmm/workflows/document-project/templates/project-scan-report-schema.json +160 -0
  210. package/bmad/bmm/workflows/document-project/templates/source-tree-template.md +135 -0
  211. package/bmad/bmm/workflows/document-project/workflow.yaml +30 -0
  212. package/bmad/bmm/workflows/document-project/workflows/deep-dive-instructions.md +298 -0
  213. package/bmad/bmm/workflows/document-project/workflows/deep-dive.yaml +31 -0
  214. package/bmad/bmm/workflows/document-project/workflows/full-scan-instructions.md +1106 -0
  215. package/bmad/bmm/workflows/document-project/workflows/full-scan.yaml +31 -0
  216. package/bmad/bmm/workflows/excalidraw-diagrams/_shared/excalidraw-library.json +90 -0
  217. package/bmad/bmm/workflows/excalidraw-diagrams/_shared/excalidraw-templates.yaml +127 -0
  218. package/bmad/bmm/workflows/excalidraw-diagrams/create-dataflow/checklist.md +39 -0
  219. package/bmad/bmm/workflows/excalidraw-diagrams/create-dataflow/instructions.md +130 -0
  220. package/bmad/bmm/workflows/excalidraw-diagrams/create-dataflow/workflow.yaml +27 -0
  221. package/bmad/bmm/workflows/excalidraw-diagrams/create-diagram/checklist.md +43 -0
  222. package/bmad/bmm/workflows/excalidraw-diagrams/create-diagram/instructions.md +141 -0
  223. package/bmad/bmm/workflows/excalidraw-diagrams/create-diagram/workflow.yaml +27 -0
  224. package/bmad/bmm/workflows/excalidraw-diagrams/create-flowchart/checklist.md +49 -0
  225. package/bmad/bmm/workflows/excalidraw-diagrams/create-flowchart/instructions.md +241 -0
  226. package/bmad/bmm/workflows/excalidraw-diagrams/create-flowchart/workflow.yaml +27 -0
  227. package/bmad/bmm/workflows/excalidraw-diagrams/create-wireframe/checklist.md +38 -0
  228. package/bmad/bmm/workflows/excalidraw-diagrams/create-wireframe/instructions.md +133 -0
  229. package/bmad/bmm/workflows/excalidraw-diagrams/create-wireframe/workflow.yaml +27 -0
  230. package/bmad/bmm/workflows/testarch/atdd/atdd-checklist-template.md +363 -0
  231. package/bmad/bmm/workflows/testarch/atdd/checklist.md +374 -0
  232. package/bmad/bmm/workflows/testarch/atdd/instructions.md +806 -0
  233. package/bmad/bmm/workflows/testarch/atdd/workflow.yaml +47 -0
  234. package/bmad/bmm/workflows/testarch/automate/checklist.md +582 -0
  235. package/bmad/bmm/workflows/testarch/automate/instructions.md +1324 -0
  236. package/bmad/bmm/workflows/testarch/automate/workflow.yaml +54 -0
  237. package/bmad/bmm/workflows/testarch/ci/checklist.md +247 -0
  238. package/bmad/bmm/workflows/testarch/ci/github-actions-template.yaml +198 -0
  239. package/bmad/bmm/workflows/testarch/ci/gitlab-ci-template.yaml +149 -0
  240. package/bmad/bmm/workflows/testarch/ci/instructions.md +536 -0
  241. package/bmad/bmm/workflows/testarch/ci/workflow.yaml +47 -0
  242. package/bmad/bmm/workflows/testarch/framework/checklist.md +320 -0
  243. package/bmad/bmm/workflows/testarch/framework/instructions.md +481 -0
  244. package/bmad/bmm/workflows/testarch/framework/workflow.yaml +49 -0
  245. package/bmad/bmm/workflows/testarch/nfr-assess/checklist.md +407 -0
  246. package/bmad/bmm/workflows/testarch/nfr-assess/instructions.md +726 -0
  247. package/bmad/bmm/workflows/testarch/nfr-assess/nfr-report-template.md +461 -0
  248. package/bmad/bmm/workflows/testarch/nfr-assess/workflow.yaml +49 -0
  249. package/bmad/bmm/workflows/testarch/test-design/checklist.md +407 -0
  250. package/bmad/bmm/workflows/testarch/test-design/instructions.md +1158 -0
  251. package/bmad/bmm/workflows/testarch/test-design/test-design-architecture-template.md +213 -0
  252. package/bmad/bmm/workflows/testarch/test-design/test-design-qa-template.md +286 -0
  253. package/bmad/bmm/workflows/testarch/test-design/test-design-template.md +294 -0
  254. package/bmad/bmm/workflows/testarch/test-design/workflow.yaml +71 -0
  255. package/bmad/bmm/workflows/testarch/test-review/checklist.md +472 -0
  256. package/bmad/bmm/workflows/testarch/test-review/instructions.md +628 -0
  257. package/bmad/bmm/workflows/testarch/test-review/test-review-template.md +390 -0
  258. package/bmad/bmm/workflows/testarch/test-review/workflow.yaml +48 -0
  259. package/bmad/bmm/workflows/testarch/trace/checklist.md +642 -0
  260. package/bmad/bmm/workflows/testarch/trace/instructions.md +1030 -0
  261. package/bmad/bmm/workflows/testarch/trace/trace-template.md +675 -0
  262. package/bmad/bmm/workflows/testarch/trace/workflow.yaml +57 -0
  263. package/bmad/core/agents/bmad-master.agent.yaml +30 -0
  264. package/bmad/core/module-help.csv +11 -0
  265. package/bmad/core/module.yaml +25 -0
  266. package/bmad/core/resources/excalidraw/README.md +160 -0
  267. package/bmad/core/resources/excalidraw/excalidraw-helpers.md +127 -0
  268. package/bmad/core/resources/excalidraw/library-loader.md +50 -0
  269. package/bmad/core/resources/excalidraw/validate-json-instructions.md +79 -0
  270. package/bmad/core/tasks/bmad-help.md +62 -0
  271. package/bmad/core/tasks/editorial-review-prose.xml +91 -0
  272. package/bmad/core/tasks/editorial-review-structure.xml +198 -0
  273. package/bmad/core/tasks/index-docs.xml +65 -0
  274. package/bmad/core/tasks/review-adversarial-general.xml +48 -0
  275. package/bmad/core/tasks/shard-doc.xml +109 -0
  276. package/bmad/core/tasks/workflow.xml +235 -0
  277. package/bmad/core/workflows/advanced-elicitation/methods.csv +51 -0
  278. package/bmad/core/workflows/advanced-elicitation/workflow.xml +117 -0
  279. package/bmad/core/workflows/brainstorming/brain-methods.csv +62 -0
  280. package/bmad/core/workflows/brainstorming/steps/step-01-session-setup.md +197 -0
  281. package/bmad/core/workflows/brainstorming/steps/step-01b-continue.md +122 -0
  282. package/bmad/core/workflows/brainstorming/steps/step-02a-user-selected.md +225 -0
  283. package/bmad/core/workflows/brainstorming/steps/step-02b-ai-recommended.md +237 -0
  284. package/bmad/core/workflows/brainstorming/steps/step-02c-random-selection.md +209 -0
  285. package/bmad/core/workflows/brainstorming/steps/step-02d-progressive-flow.md +264 -0
  286. package/bmad/core/workflows/brainstorming/steps/step-03-technique-execution.md +399 -0
  287. package/bmad/core/workflows/brainstorming/steps/step-04-idea-organization.md +303 -0
  288. package/bmad/core/workflows/brainstorming/template.md +15 -0
  289. package/bmad/core/workflows/brainstorming/workflow.md +58 -0
  290. package/bmad/core/workflows/party-mode/steps/step-01-agent-loading.md +138 -0
  291. package/bmad/core/workflows/party-mode/steps/step-02-discussion-orchestration.md +187 -0
  292. package/bmad/core/workflows/party-mode/steps/step-03-graceful-exit.md +157 -0
  293. package/bmad/core/workflows/party-mode/workflow.md +194 -0
  294. package/dist/cli.d.ts +1 -0
  295. package/dist/cli.js +26 -0
  296. package/dist/commands/doctor.d.ts +1 -0
  297. package/dist/commands/doctor.js +168 -0
  298. package/dist/commands/guide.d.ts +1 -0
  299. package/dist/commands/guide.js +19 -0
  300. package/dist/commands/implement.d.ts +1 -0
  301. package/dist/commands/implement.js +83 -0
  302. package/dist/commands/init.d.ts +6 -0
  303. package/dist/commands/init.js +67 -0
  304. package/dist/commands/plan.d.ts +5 -0
  305. package/dist/commands/plan.js +44 -0
  306. package/dist/commands/reset.d.ts +5 -0
  307. package/dist/commands/reset.js +35 -0
  308. package/dist/commands/resume.d.ts +1 -0
  309. package/dist/commands/resume.js +44 -0
  310. package/dist/commands/start.d.ts +5 -0
  311. package/dist/commands/start.js +54 -0
  312. package/dist/commands/status.d.ts +1 -0
  313. package/dist/commands/status.js +53 -0
  314. package/dist/commands/upgrade.d.ts +1 -0
  315. package/dist/commands/upgrade.js +34 -0
  316. package/dist/installer.d.ts +11 -0
  317. package/dist/installer.js +219 -0
  318. package/dist/transition.d.ts +52 -0
  319. package/dist/transition.js +656 -0
  320. package/dist/utils/config.d.ts +7 -0
  321. package/dist/utils/config.js +14 -0
  322. package/dist/utils/json.d.ts +7 -0
  323. package/dist/utils/json.js +26 -0
  324. package/dist/utils/logger.d.ts +3 -0
  325. package/dist/utils/logger.js +13 -0
  326. package/dist/utils/state.d.ts +29 -0
  327. package/dist/utils/state.js +78 -0
  328. package/dist/utils/validate.d.ts +4 -0
  329. package/dist/utils/validate.js +42 -0
  330. package/package.json +59 -0
  331. package/ralph/lib/circuit_breaker.sh +330 -0
  332. package/ralph/lib/date_utils.sh +53 -0
  333. package/ralph/lib/response_analyzer.sh +768 -0
  334. package/ralph/lib/timeout_utils.sh +145 -0
  335. package/ralph/ralph_loop.sh +1391 -0
  336. package/ralph/templates/AGENT.md +158 -0
  337. package/ralph/templates/PROMPT.md +292 -0
  338. package/ralph/templates/fix_plan.md +27 -0
  339. package/ralph/templates/specs/.gitkeep +2 -0
  340. package/slash-commands/advanced-elicitation.md +1 -0
  341. package/slash-commands/adversarial-review.md +1 -0
  342. package/slash-commands/analyst.md +1 -0
  343. package/slash-commands/architect.md +1 -0
  344. package/slash-commands/atdd.md +1 -0
  345. package/slash-commands/bmad-help.md +1 -0
  346. package/slash-commands/bmalph-implement.md +152 -0
  347. package/slash-commands/bmalph.md +1 -0
  348. package/slash-commands/brainstorm-project.md +1 -0
  349. package/slash-commands/brainstorming.md +1 -0
  350. package/slash-commands/continuous-integration.md +1 -0
  351. package/slash-commands/correct-course.md +1 -0
  352. package/slash-commands/create-architecture.md +1 -0
  353. package/slash-commands/create-brief.md +1 -0
  354. package/slash-commands/create-dataflow.md +1 -0
  355. package/slash-commands/create-diagram.md +1 -0
  356. package/slash-commands/create-epics-stories.md +1 -0
  357. package/slash-commands/create-flowchart.md +1 -0
  358. package/slash-commands/create-prd.md +1 -0
  359. package/slash-commands/create-story.md +1 -0
  360. package/slash-commands/create-ux.md +1 -0
  361. package/slash-commands/create-wireframe.md +1 -0
  362. package/slash-commands/dev.md +1 -0
  363. package/slash-commands/document-project.md +1 -0
  364. package/slash-commands/domain-research.md +1 -0
  365. package/slash-commands/editorial-prose.md +1 -0
  366. package/slash-commands/editorial-structure.md +1 -0
  367. package/slash-commands/execute-workflow.md +1 -0
  368. package/slash-commands/implementation-readiness.md +1 -0
  369. package/slash-commands/index-docs.md +1 -0
  370. package/slash-commands/market-research.md +1 -0
  371. package/slash-commands/nfr-assess.md +1 -0
  372. package/slash-commands/party-mode.md +1 -0
  373. package/slash-commands/pm.md +1 -0
  374. package/slash-commands/quick-dev.md +1 -0
  375. package/slash-commands/quick-flow-solo-dev.md +1 -0
  376. package/slash-commands/retrospective.md +1 -0
  377. package/slash-commands/shard-doc.md +1 -0
  378. package/slash-commands/sm.md +1 -0
  379. package/slash-commands/sprint-planning.md +1 -0
  380. package/slash-commands/sprint-status.md +1 -0
  381. package/slash-commands/tea.md +1 -0
  382. package/slash-commands/tech-spec.md +1 -0
  383. package/slash-commands/technical-research.md +1 -0
  384. package/slash-commands/test-automate.md +1 -0
  385. package/slash-commands/test-design.md +1 -0
  386. package/slash-commands/test-framework.md +1 -0
  387. package/slash-commands/test-review.md +1 -0
  388. package/slash-commands/test-trace.md +1 -0
  389. package/slash-commands/ux-designer.md +1 -0
  390. package/slash-commands/validate-architecture.md +1 -0
  391. package/slash-commands/validate-brief.md +1 -0
  392. package/slash-commands/validate-epics-stories.md +1 -0
  393. package/slash-commands/validate-prd.md +1 -0
  394. package/slash-commands/validate-story.md +1 -0
  395. package/slash-commands/validate-test-design.md +1 -0
  396. package/slash-commands/validate-ux.md +1 -0
@@ -0,0 +1,1391 @@
1
+ #!/bin/bash
2
+
3
+ # Claude Code Ralph Loop with Rate Limiting and Documentation
4
+ # Adaptation of the Ralph technique for Claude Code with usage management
5
+
6
+ set -e # Exit on any error
7
+
8
+ # Source library components
9
+ SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
10
+ source "$SCRIPT_DIR/lib/date_utils.sh"
11
+ source "$SCRIPT_DIR/lib/timeout_utils.sh"
12
+ source "$SCRIPT_DIR/lib/response_analyzer.sh"
13
+ source "$SCRIPT_DIR/lib/circuit_breaker.sh"
14
+
15
+ # Configuration
16
+ # Ralph-specific files live in .ralph/ subfolder
17
+ RALPH_DIR=".ralph"
18
+ PROMPT_FILE="$RALPH_DIR/PROMPT.md"
19
+ LOG_DIR="$RALPH_DIR/logs"
20
+ DOCS_DIR="$RALPH_DIR/docs/generated"
21
+ STATUS_FILE="$RALPH_DIR/status.json"
22
+ PROGRESS_FILE="$RALPH_DIR/progress.json"
23
+ CLAUDE_CODE_CMD="claude"
24
+ MAX_CALLS_PER_HOUR=100 # Adjust based on your plan
25
+ VERBOSE_PROGRESS=false # Default: no verbose progress updates
26
+ CLAUDE_TIMEOUT_MINUTES=20 # Default: 20 minutes timeout for Claude Code execution
27
+ SLEEP_DURATION=3600 # 1 hour in seconds
28
+ CALL_COUNT_FILE="$RALPH_DIR/.call_count"
29
+ TIMESTAMP_FILE="$RALPH_DIR/.last_reset"
30
+ USE_TMUX=false
31
+
32
+ # Modern Claude CLI configuration (Phase 1.1)
33
+ CLAUDE_OUTPUT_FORMAT="json" # Options: json, text
34
+ CLAUDE_ALLOWED_TOOLS="Write,Bash(git *),Read" # Comma-separated list of allowed tools
35
+ CLAUDE_USE_CONTINUE=true # Enable session continuity
36
+ CLAUDE_SESSION_FILE="$RALPH_DIR/.claude_session_id" # Session ID persistence file
37
+ CLAUDE_MIN_VERSION="2.0.76" # Minimum required Claude CLI version
38
+
39
+ # Session management configuration (Phase 1.2)
40
+ # Note: SESSION_EXPIRATION_SECONDS is defined in lib/response_analyzer.sh (86400 = 24 hours)
41
+ RALPH_SESSION_FILE="$RALPH_DIR/.ralph_session" # Ralph-specific session tracking (lifecycle)
42
+ RALPH_SESSION_HISTORY_FILE="$RALPH_DIR/.ralph_session_history" # Session transition history
43
+ # Session expiration: 24 hours default balances project continuity with fresh context
44
+ # Too short = frequent context loss; Too long = stale context causes unpredictable behavior
45
+ CLAUDE_SESSION_EXPIRY_HOURS=${CLAUDE_SESSION_EXPIRY_HOURS:-24}
46
+
47
+ # Valid tool patterns for --allowed-tools validation
48
+ # Tools can be exact matches or pattern matches with wildcards in parentheses
49
+ VALID_TOOL_PATTERNS=(
50
+ "Write"
51
+ "Read"
52
+ "Edit"
53
+ "MultiEdit"
54
+ "Glob"
55
+ "Grep"
56
+ "Task"
57
+ "TodoWrite"
58
+ "WebFetch"
59
+ "WebSearch"
60
+ "Bash"
61
+ "Bash(git *)"
62
+ "Bash(npm *)"
63
+ "Bash(bats *)"
64
+ "Bash(python *)"
65
+ "Bash(node *)"
66
+ "NotebookEdit"
67
+ )
68
+
69
+ # Exit detection configuration
70
+ EXIT_SIGNALS_FILE="$RALPH_DIR/.exit_signals"
71
+ RESPONSE_ANALYSIS_FILE="$RALPH_DIR/.response_analysis"
72
+ MAX_CONSECUTIVE_TEST_LOOPS=3
73
+ MAX_CONSECUTIVE_DONE_SIGNALS=2
74
+ TEST_PERCENTAGE_THRESHOLD=30 # If more than 30% of recent loops are test-only, flag it
75
+
76
+ # Colors for terminal output
77
+ RED='\033[0;31m'
78
+ GREEN='\033[0;32m'
79
+ YELLOW='\033[1;33m'
80
+ BLUE='\033[0;34m'
81
+ PURPLE='\033[0;35m'
82
+ NC='\033[0m' # No Color
83
+
84
+ # Initialize directories
85
+ mkdir -p "$LOG_DIR" "$DOCS_DIR"
86
+
87
+ # Check if tmux is available
88
+ check_tmux_available() {
89
+ if ! command -v tmux &> /dev/null; then
90
+ log_status "ERROR" "tmux is not installed. Please install tmux or run without --monitor flag."
91
+ echo "Install tmux:"
92
+ echo " Ubuntu/Debian: sudo apt-get install tmux"
93
+ echo " macOS: brew install tmux"
94
+ echo " CentOS/RHEL: sudo yum install tmux"
95
+ exit 1
96
+ fi
97
+ }
98
+
99
+ # Setup tmux session with monitor
100
+ setup_tmux_session() {
101
+ local session_name="ralph-$(date +%s)"
102
+ local ralph_home="${RALPH_HOME:-$HOME/.ralph}"
103
+
104
+ log_status "INFO" "Setting up tmux session: $session_name"
105
+
106
+ # Create new tmux session detached
107
+ tmux new-session -d -s "$session_name" -c "$(pwd)"
108
+
109
+ # Split window vertically to create monitor pane on the right
110
+ tmux split-window -h -t "$session_name" -c "$(pwd)"
111
+
112
+ # Start monitor in the right pane
113
+ if command -v ralph-monitor &> /dev/null; then
114
+ tmux send-keys -t "$session_name:0.1" "ralph-monitor" Enter
115
+ else
116
+ tmux send-keys -t "$session_name:0.1" "'$ralph_home/ralph_monitor.sh'" Enter
117
+ fi
118
+
119
+ # Start ralph loop in the left pane (exclude tmux flag to avoid recursion)
120
+ local ralph_cmd
121
+ if command -v ralph &> /dev/null; then
122
+ ralph_cmd="ralph"
123
+ else
124
+ ralph_cmd="'$ralph_home/ralph_loop.sh'"
125
+ fi
126
+
127
+ if [[ "$MAX_CALLS_PER_HOUR" != "100" ]]; then
128
+ ralph_cmd="$ralph_cmd --calls $MAX_CALLS_PER_HOUR"
129
+ fi
130
+ if [[ "$PROMPT_FILE" != "$RALPH_DIR/PROMPT.md" ]]; then
131
+ ralph_cmd="$ralph_cmd --prompt '$PROMPT_FILE'"
132
+ fi
133
+
134
+ tmux send-keys -t "$session_name:0.0" "$ralph_cmd" Enter
135
+
136
+ # Focus on left pane (main ralph loop)
137
+ tmux select-pane -t "$session_name:0.0"
138
+
139
+ # Set window title
140
+ tmux rename-window -t "$session_name:0" "Ralph: Loop | Monitor"
141
+
142
+ log_status "SUCCESS" "Tmux session created. Attaching to session..."
143
+ log_status "INFO" "Use Ctrl+B then D to detach from session"
144
+ log_status "INFO" "Use 'tmux attach -t $session_name' to reattach"
145
+
146
+ # Attach to session (this will block until session ends)
147
+ tmux attach-session -t "$session_name"
148
+
149
+ exit 0
150
+ }
151
+
152
+ # Initialize call tracking
153
+ init_call_tracking() {
154
+ log_status "INFO" "DEBUG: Entered init_call_tracking..."
155
+ local current_hour=$(date +%Y%m%d%H)
156
+ local last_reset_hour=""
157
+
158
+ if [[ -f "$TIMESTAMP_FILE" ]]; then
159
+ last_reset_hour=$(cat "$TIMESTAMP_FILE")
160
+ fi
161
+
162
+ # Reset counter if it's a new hour
163
+ if [[ "$current_hour" != "$last_reset_hour" ]]; then
164
+ echo "0" > "$CALL_COUNT_FILE"
165
+ echo "$current_hour" > "$TIMESTAMP_FILE"
166
+ log_status "INFO" "Call counter reset for new hour: $current_hour"
167
+ fi
168
+
169
+ # Initialize exit signals tracking if it doesn't exist
170
+ if [[ ! -f "$EXIT_SIGNALS_FILE" ]]; then
171
+ echo '{"test_only_loops": [], "done_signals": [], "completion_indicators": []}' > "$EXIT_SIGNALS_FILE"
172
+ fi
173
+
174
+ # Initialize circuit breaker
175
+ init_circuit_breaker
176
+
177
+ log_status "INFO" "DEBUG: Completed init_call_tracking successfully"
178
+ }
179
+
180
+ # Log function with timestamps and colors
181
+ log_status() {
182
+ local level=$1
183
+ local message=$2
184
+ local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
185
+ local color=""
186
+
187
+ case $level in
188
+ "INFO") color=$BLUE ;;
189
+ "WARN") color=$YELLOW ;;
190
+ "ERROR") color=$RED ;;
191
+ "SUCCESS") color=$GREEN ;;
192
+ "LOOP") color=$PURPLE ;;
193
+ esac
194
+
195
+ echo -e "${color}[$timestamp] [$level] $message${NC}"
196
+ echo "[$timestamp] [$level] $message" >> "$LOG_DIR/ralph.log"
197
+ }
198
+
199
+ # Update status JSON for external monitoring
200
+ update_status() {
201
+ local loop_count=$1
202
+ local calls_made=$2
203
+ local last_action=$3
204
+ local status=$4
205
+ local exit_reason=${5:-""}
206
+
207
+ cat > "$STATUS_FILE" << STATUSEOF
208
+ {
209
+ "timestamp": "$(get_iso_timestamp)",
210
+ "loop_count": $loop_count,
211
+ "calls_made_this_hour": $calls_made,
212
+ "max_calls_per_hour": $MAX_CALLS_PER_HOUR,
213
+ "last_action": "$last_action",
214
+ "status": "$status",
215
+ "exit_reason": "$exit_reason",
216
+ "next_reset": "$(get_next_hour_time)"
217
+ }
218
+ STATUSEOF
219
+ }
220
+
221
+ # Check if we can make another call
222
+ can_make_call() {
223
+ local calls_made=0
224
+ if [[ -f "$CALL_COUNT_FILE" ]]; then
225
+ calls_made=$(cat "$CALL_COUNT_FILE")
226
+ fi
227
+
228
+ if [[ $calls_made -ge $MAX_CALLS_PER_HOUR ]]; then
229
+ return 1 # Cannot make call
230
+ else
231
+ return 0 # Can make call
232
+ fi
233
+ }
234
+
235
+ # Increment call counter
236
+ increment_call_counter() {
237
+ local calls_made=0
238
+ if [[ -f "$CALL_COUNT_FILE" ]]; then
239
+ calls_made=$(cat "$CALL_COUNT_FILE")
240
+ fi
241
+
242
+ ((calls_made++))
243
+ echo "$calls_made" > "$CALL_COUNT_FILE"
244
+ echo "$calls_made"
245
+ }
246
+
247
+ # Wait for rate limit reset with countdown
248
+ wait_for_reset() {
249
+ local calls_made=$(cat "$CALL_COUNT_FILE" 2>/dev/null || echo "0")
250
+ log_status "WARN" "Rate limit reached ($calls_made/$MAX_CALLS_PER_HOUR). Waiting for reset..."
251
+
252
+ # Calculate time until next hour
253
+ local current_minute=$(date +%M)
254
+ local current_second=$(date +%S)
255
+ local wait_time=$(((60 - current_minute - 1) * 60 + (60 - current_second)))
256
+
257
+ log_status "INFO" "Sleeping for $wait_time seconds until next hour..."
258
+
259
+ # Countdown display
260
+ while [[ $wait_time -gt 0 ]]; do
261
+ local hours=$((wait_time / 3600))
262
+ local minutes=$(((wait_time % 3600) / 60))
263
+ local seconds=$((wait_time % 60))
264
+
265
+ printf "\r${YELLOW}Time until reset: %02d:%02d:%02d${NC}" $hours $minutes $seconds
266
+ sleep 1
267
+ ((wait_time--))
268
+ done
269
+ printf "\n"
270
+
271
+ # Reset counter
272
+ echo "0" > "$CALL_COUNT_FILE"
273
+ echo "$(date +%Y%m%d%H)" > "$TIMESTAMP_FILE"
274
+ log_status "SUCCESS" "Rate limit reset! Ready for new calls."
275
+ }
276
+
277
+ # Check if we should gracefully exit
278
+ should_exit_gracefully() {
279
+ log_status "INFO" "DEBUG: Checking exit conditions..." >&2
280
+
281
+ if [[ ! -f "$EXIT_SIGNALS_FILE" ]]; then
282
+ log_status "INFO" "DEBUG: No exit signals file found, continuing..." >&2
283
+ return 1 # Don't exit, file doesn't exist
284
+ fi
285
+
286
+ local signals=$(cat "$EXIT_SIGNALS_FILE")
287
+ log_status "INFO" "DEBUG: Exit signals content: $signals" >&2
288
+
289
+ # Count recent signals (last 5 loops) - with error handling
290
+ local recent_test_loops
291
+ local recent_done_signals
292
+ local recent_completion_indicators
293
+
294
+ recent_test_loops=$(echo "$signals" | jq '.test_only_loops | length' 2>/dev/null || echo "0")
295
+ recent_done_signals=$(echo "$signals" | jq '.done_signals | length' 2>/dev/null || echo "0")
296
+ recent_completion_indicators=$(echo "$signals" | jq '.completion_indicators | length' 2>/dev/null || echo "0")
297
+
298
+ log_status "INFO" "DEBUG: Exit counts - test_loops:$recent_test_loops, done_signals:$recent_done_signals, completion:$recent_completion_indicators" >&2
299
+
300
+ # Check for exit conditions
301
+
302
+ # 1. Too many consecutive test-only loops
303
+ if [[ $recent_test_loops -ge $MAX_CONSECUTIVE_TEST_LOOPS ]]; then
304
+ log_status "WARN" "Exit condition: Too many test-focused loops ($recent_test_loops >= $MAX_CONSECUTIVE_TEST_LOOPS)"
305
+ echo "test_saturation"
306
+ return 0
307
+ fi
308
+
309
+ # 2. Multiple "done" signals
310
+ if [[ $recent_done_signals -ge $MAX_CONSECUTIVE_DONE_SIGNALS ]]; then
311
+ log_status "WARN" "Exit condition: Multiple completion signals ($recent_done_signals >= $MAX_CONSECUTIVE_DONE_SIGNALS)"
312
+ echo "completion_signals"
313
+ return 0
314
+ fi
315
+
316
+ # 3. Safety circuit breaker - force exit after 5 consecutive completion indicators
317
+ # Bug #2 Fix: Prevents infinite loops when EXIT_SIGNAL is not explicitly set
318
+ # but completion patterns clearly indicate work is done. Threshold of 5 is higher
319
+ # than normal threshold (2) to avoid false positives while preventing API waste.
320
+ if [[ $recent_completion_indicators -ge 5 ]]; then
321
+ log_status "WARN" "🚨 SAFETY CIRCUIT BREAKER: Force exit after 5 consecutive completion indicators ($recent_completion_indicators)" >&2
322
+ echo "safety_circuit_breaker"
323
+ return 0
324
+ fi
325
+
326
+ # 4. Strong completion indicators (only if Claude's EXIT_SIGNAL is true)
327
+ # This prevents premature exits when heuristics detect completion patterns
328
+ # but Claude explicitly indicates work is still in progress via RALPH_STATUS block.
329
+ # The exit_signal in .response_analysis represents Claude's explicit intent.
330
+ local claude_exit_signal="false"
331
+ if [[ -f "$RESPONSE_ANALYSIS_FILE" ]]; then
332
+ claude_exit_signal=$(jq -r '.analysis.exit_signal // false' "$RESPONSE_ANALYSIS_FILE" 2>/dev/null || echo "false")
333
+ fi
334
+
335
+ if [[ $recent_completion_indicators -ge 2 ]] && [[ "$claude_exit_signal" == "true" ]]; then
336
+ log_status "WARN" "Exit condition: Strong completion indicators ($recent_completion_indicators) with EXIT_SIGNAL=true" >&2
337
+ echo "project_complete"
338
+ return 0
339
+ elif [[ $recent_completion_indicators -ge 2 ]]; then
340
+ log_status "INFO" "DEBUG: Completion indicators ($recent_completion_indicators) present but EXIT_SIGNAL=false, continuing..." >&2
341
+ fi
342
+
343
+ # 5. Check fix_plan.md for completion
344
+ # Bug #3 Fix: Support indented markdown checkboxes with [[:space:]]* pattern
345
+ if [[ -f "$RALPH_DIR/@fix_plan.md" ]]; then
346
+ local total_items=$(grep -cE "^[[:space:]]*- \[" "$RALPH_DIR/@fix_plan.md" 2>/dev/null)
347
+ local completed_items=$(grep -cE "^[[:space:]]*- \[x\]" "$RALPH_DIR/@fix_plan.md" 2>/dev/null)
348
+
349
+ # Handle case where grep returns no matches (exit code 1)
350
+ [[ -z "$total_items" ]] && total_items=0
351
+ [[ -z "$completed_items" ]] && completed_items=0
352
+
353
+ log_status "INFO" "DEBUG: .ralph/@fix_plan.md check - total_items:$total_items, completed_items:$completed_items" >&2
354
+
355
+ if [[ $total_items -gt 0 ]] && [[ $completed_items -eq $total_items ]]; then
356
+ log_status "WARN" "Exit condition: All fix_plan.md items completed ($completed_items/$total_items)" >&2
357
+ echo "plan_complete"
358
+ return 0
359
+ fi
360
+ else
361
+ log_status "INFO" "DEBUG: .ralph/@fix_plan.md file not found" >&2
362
+ fi
363
+
364
+ log_status "INFO" "DEBUG: No exit conditions met, continuing loop" >&2
365
+ echo "" # Return empty string instead of using return code
366
+ }
367
+
368
+ # =============================================================================
369
+ # MODERN CLI HELPER FUNCTIONS (Phase 1.1)
370
+ # =============================================================================
371
+
372
+ # Check Claude CLI version for compatibility with modern flags
373
+ check_claude_version() {
374
+ local version=$($CLAUDE_CODE_CMD --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
375
+
376
+ if [[ -z "$version" ]]; then
377
+ log_status "WARN" "Cannot detect Claude CLI version, assuming compatible"
378
+ return 0
379
+ fi
380
+
381
+ # Compare versions (simplified semver comparison)
382
+ local required="$CLAUDE_MIN_VERSION"
383
+
384
+ # Convert to comparable integers (major * 10000 + minor * 100 + patch)
385
+ local ver_parts=(${version//./ })
386
+ local req_parts=(${required//./ })
387
+
388
+ local ver_num=$((${ver_parts[0]:-0} * 10000 + ${ver_parts[1]:-0} * 100 + ${ver_parts[2]:-0}))
389
+ local req_num=$((${req_parts[0]:-0} * 10000 + ${req_parts[1]:-0} * 100 + ${req_parts[2]:-0}))
390
+
391
+ if [[ $ver_num -lt $req_num ]]; then
392
+ log_status "WARN" "Claude CLI version $version < $required. Some modern features may not work."
393
+ log_status "WARN" "Consider upgrading: npm update -g @anthropic-ai/claude-code"
394
+ return 1
395
+ fi
396
+
397
+ log_status "INFO" "Claude CLI version $version (>= $required) - modern features enabled"
398
+ return 0
399
+ }
400
+
401
+ # Validate allowed tools against whitelist
402
+ # Returns 0 if valid, 1 if invalid with error message
403
+ validate_allowed_tools() {
404
+ local tools_input=$1
405
+
406
+ if [[ -z "$tools_input" ]]; then
407
+ return 0 # Empty is valid (uses defaults)
408
+ fi
409
+
410
+ # Split by comma
411
+ local IFS=','
412
+ read -ra tools <<< "$tools_input"
413
+
414
+ for tool in "${tools[@]}"; do
415
+ # Trim whitespace
416
+ tool=$(echo "$tool" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
417
+
418
+ if [[ -z "$tool" ]]; then
419
+ continue
420
+ fi
421
+
422
+ local valid=false
423
+
424
+ # Check against valid patterns
425
+ for pattern in "${VALID_TOOL_PATTERNS[@]}"; do
426
+ if [[ "$tool" == "$pattern" ]]; then
427
+ valid=true
428
+ break
429
+ fi
430
+
431
+ # Check for Bash(*) pattern - any Bash with parentheses is allowed
432
+ if [[ "$tool" =~ ^Bash\(.+\)$ ]]; then
433
+ valid=true
434
+ break
435
+ fi
436
+ done
437
+
438
+ if [[ "$valid" == "false" ]]; then
439
+ echo "Error: Invalid tool in --allowed-tools: '$tool'"
440
+ echo "Valid tools: ${VALID_TOOL_PATTERNS[*]}"
441
+ echo "Note: Bash(...) patterns with any content are allowed (e.g., 'Bash(git *)')"
442
+ return 1
443
+ fi
444
+ done
445
+
446
+ return 0
447
+ }
448
+
449
+ # Build loop context for Claude Code session
450
+ # Provides loop-specific context via --append-system-prompt
451
+ build_loop_context() {
452
+ local loop_count=$1
453
+ local context=""
454
+
455
+ # Add loop number
456
+ context="Loop #${loop_count}. "
457
+
458
+ # Extract incomplete tasks from @fix_plan.md
459
+ # Bug #3 Fix: Support indented markdown checkboxes with [[:space:]]* pattern
460
+ if [[ -f "$RALPH_DIR/@fix_plan.md" ]]; then
461
+ local incomplete_tasks=$(grep -cE "^[[:space:]]*- \[ \]" "$RALPH_DIR/@fix_plan.md" 2>/dev/null || echo "0")
462
+ context+="Remaining tasks: ${incomplete_tasks}. "
463
+ fi
464
+
465
+ # Add circuit breaker state
466
+ if [[ -f "$RALPH_DIR/.circuit_breaker_state" ]]; then
467
+ local cb_state=$(jq -r '.state // "UNKNOWN"' "$RALPH_DIR/.circuit_breaker_state" 2>/dev/null)
468
+ if [[ "$cb_state" != "CLOSED" && "$cb_state" != "null" && -n "$cb_state" ]]; then
469
+ context+="Circuit breaker: ${cb_state}. "
470
+ fi
471
+ fi
472
+
473
+ # Add previous loop summary (truncated)
474
+ if [[ -f "$RESPONSE_ANALYSIS_FILE" ]]; then
475
+ local prev_summary=$(jq -r '.analysis.work_summary // ""' "$RESPONSE_ANALYSIS_FILE" 2>/dev/null | head -c 200)
476
+ if [[ -n "$prev_summary" && "$prev_summary" != "null" ]]; then
477
+ context+="Previous: ${prev_summary}"
478
+ fi
479
+ fi
480
+
481
+ # Limit total length to ~500 chars
482
+ echo "${context:0:500}"
483
+ }
484
+
485
+ # Get session file age in hours (cross-platform)
486
+ # Returns: age in hours on stdout, or -1 if stat fails
487
+ # Note: Returns 0 for files less than 1 hour old
488
+ get_session_file_age_hours() {
489
+ local file=$1
490
+
491
+ if [[ ! -f "$file" ]]; then
492
+ echo "0"
493
+ return
494
+ fi
495
+
496
+ local os_type
497
+ os_type=$(uname)
498
+
499
+ local file_mtime
500
+ if [[ "$os_type" == "Darwin" ]]; then
501
+ # macOS (BSD stat)
502
+ file_mtime=$(stat -f %m "$file" 2>/dev/null)
503
+ else
504
+ # Linux (GNU stat)
505
+ file_mtime=$(stat -c %Y "$file" 2>/dev/null)
506
+ fi
507
+
508
+ # Handle stat failure - return -1 to indicate error
509
+ # This prevents false expiration when stat fails
510
+ if [[ -z "$file_mtime" || "$file_mtime" == "0" ]]; then
511
+ echo "-1"
512
+ return
513
+ fi
514
+
515
+ local current_time
516
+ current_time=$(date +%s)
517
+
518
+ local age_seconds=$((current_time - file_mtime))
519
+ local age_hours=$((age_seconds / 3600))
520
+
521
+ echo "$age_hours"
522
+ }
523
+
524
+ # Initialize or resume Claude session (with expiration check)
525
+ #
526
+ # Session Expiration Strategy:
527
+ # - Default expiration: 24 hours (configurable via CLAUDE_SESSION_EXPIRY_HOURS)
528
+ # - 24 hours chosen because: long enough for multi-day projects, short enough
529
+ # to prevent stale context from causing unpredictable behavior
530
+ # - Sessions auto-expire to ensure Claude starts fresh periodically
531
+ #
532
+ # Returns (stdout):
533
+ # - Session ID string: when resuming a valid, non-expired session
534
+ # - Empty string: when starting new session (no file, expired, or stat error)
535
+ #
536
+ # Return codes:
537
+ # - 0: Always returns success (caller should check stdout for session ID)
538
+ #
539
+ init_claude_session() {
540
+ if [[ -f "$CLAUDE_SESSION_FILE" ]]; then
541
+ # Check session age
542
+ local age_hours
543
+ age_hours=$(get_session_file_age_hours "$CLAUDE_SESSION_FILE")
544
+
545
+ # Handle stat failure (-1) - treat as needing new session
546
+ # Don't expire sessions when we can't determine age
547
+ if [[ $age_hours -eq -1 ]]; then
548
+ log_status "WARN" "Could not determine session age, starting new session"
549
+ rm -f "$CLAUDE_SESSION_FILE"
550
+ echo ""
551
+ return 0
552
+ fi
553
+
554
+ # Check if session has expired
555
+ if [[ $age_hours -ge $CLAUDE_SESSION_EXPIRY_HOURS ]]; then
556
+ log_status "INFO" "Session expired (${age_hours}h old, max ${CLAUDE_SESSION_EXPIRY_HOURS}h), starting new session"
557
+ rm -f "$CLAUDE_SESSION_FILE"
558
+ echo ""
559
+ return 0
560
+ fi
561
+
562
+ # Session is valid, try to read it
563
+ local session_id=$(cat "$CLAUDE_SESSION_FILE" 2>/dev/null)
564
+ if [[ -n "$session_id" ]]; then
565
+ log_status "INFO" "Resuming Claude session: ${session_id:0:20}... (${age_hours}h old)"
566
+ echo "$session_id"
567
+ return 0
568
+ fi
569
+ fi
570
+
571
+ log_status "INFO" "Starting new Claude session"
572
+ echo ""
573
+ }
574
+
575
+ # Save session ID after successful execution
576
+ save_claude_session() {
577
+ local output_file=$1
578
+
579
+ # Try to extract session ID from JSON output
580
+ if [[ -f "$output_file" ]]; then
581
+ local session_id=$(jq -r '.metadata.session_id // .session_id // empty' "$output_file" 2>/dev/null)
582
+ if [[ -n "$session_id" && "$session_id" != "null" ]]; then
583
+ echo "$session_id" > "$CLAUDE_SESSION_FILE"
584
+ log_status "INFO" "Saved Claude session: ${session_id:0:20}..."
585
+ fi
586
+ fi
587
+ }
588
+
589
+ # =============================================================================
590
+ # SESSION LIFECYCLE MANAGEMENT FUNCTIONS (Phase 1.2)
591
+ # =============================================================================
592
+
593
+ # Get current session ID from Ralph session file
594
+ # Returns: session ID string or empty if not found
595
+ get_session_id() {
596
+ if [[ ! -f "$RALPH_SESSION_FILE" ]]; then
597
+ echo ""
598
+ return 0
599
+ fi
600
+
601
+ # Extract session_id from JSON file (SC2155: separate declare from assign)
602
+ local session_id
603
+ session_id=$(jq -r '.session_id // ""' "$RALPH_SESSION_FILE" 2>/dev/null)
604
+ local jq_status=$?
605
+
606
+ # Handle jq failure or null/empty results
607
+ if [[ $jq_status -ne 0 || -z "$session_id" || "$session_id" == "null" ]]; then
608
+ session_id=""
609
+ fi
610
+ echo "$session_id"
611
+ return 0
612
+ }
613
+
614
+ # Reset session with reason logging
615
+ # Usage: reset_session "reason_for_reset"
616
+ reset_session() {
617
+ local reason=${1:-"manual_reset"}
618
+
619
+ # Get current timestamp
620
+ local reset_timestamp
621
+ reset_timestamp=$(get_iso_timestamp)
622
+
623
+ # Always create/overwrite the session file using jq for safe JSON escaping
624
+ jq -n \
625
+ --arg session_id "" \
626
+ --arg created_at "" \
627
+ --arg last_used "" \
628
+ --arg reset_at "$reset_timestamp" \
629
+ --arg reset_reason "$reason" \
630
+ '{
631
+ session_id: $session_id,
632
+ created_at: $created_at,
633
+ last_used: $last_used,
634
+ reset_at: $reset_at,
635
+ reset_reason: $reset_reason
636
+ }' > "$RALPH_SESSION_FILE"
637
+
638
+ # Also clear the Claude session file for consistency
639
+ rm -f "$CLAUDE_SESSION_FILE" 2>/dev/null
640
+
641
+ # Clear exit signals to prevent stale completion indicators from causing premature exit (issue #91)
642
+ # This ensures a fresh start without leftover state from previous sessions
643
+ if [[ -f "$EXIT_SIGNALS_FILE" ]]; then
644
+ echo '{"test_only_loops": [], "done_signals": [], "completion_indicators": []}' > "$EXIT_SIGNALS_FILE"
645
+ [[ "${VERBOSE_PROGRESS:-}" == "true" ]] && log_status "INFO" "Cleared exit signals file"
646
+ fi
647
+
648
+ # Clear response analysis to prevent stale EXIT_SIGNAL from previous session
649
+ rm -f "$RESPONSE_ANALYSIS_FILE" 2>/dev/null
650
+
651
+ # Log the session transition (non-fatal to prevent script exit under set -e)
652
+ log_session_transition "active" "reset" "$reason" "${loop_count:-0}" || true
653
+
654
+ log_status "INFO" "Session reset: $reason"
655
+ }
656
+
657
+ # Log session state transitions to history file
658
+ # Usage: log_session_transition from_state to_state reason loop_number
659
+ log_session_transition() {
660
+ local from_state=$1
661
+ local to_state=$2
662
+ local reason=$3
663
+ local loop_number=${4:-0}
664
+
665
+ # Get timestamp once (SC2155: separate declare from assign)
666
+ local ts
667
+ ts=$(get_iso_timestamp)
668
+
669
+ # Create transition entry using jq for safe JSON (SC2155: separate declare from assign)
670
+ local transition
671
+ transition=$(jq -n -c \
672
+ --arg timestamp "$ts" \
673
+ --arg from_state "$from_state" \
674
+ --arg to_state "$to_state" \
675
+ --arg reason "$reason" \
676
+ --argjson loop_number "$loop_number" \
677
+ '{
678
+ timestamp: $timestamp,
679
+ from_state: $from_state,
680
+ to_state: $to_state,
681
+ reason: $reason,
682
+ loop_number: $loop_number
683
+ }')
684
+
685
+ # Read history file defensively - fallback to empty array on any failure
686
+ local history
687
+ if [[ -f "$RALPH_SESSION_HISTORY_FILE" ]]; then
688
+ history=$(cat "$RALPH_SESSION_HISTORY_FILE" 2>/dev/null)
689
+ # Validate JSON, fallback to empty array if corrupted
690
+ if ! echo "$history" | jq empty 2>/dev/null; then
691
+ history='[]'
692
+ fi
693
+ else
694
+ history='[]'
695
+ fi
696
+
697
+ # Append transition and keep only last 50 entries
698
+ local updated_history
699
+ updated_history=$(echo "$history" | jq ". += [$transition] | .[-50:]" 2>/dev/null)
700
+ local jq_status=$?
701
+
702
+ # Only write if jq succeeded
703
+ if [[ $jq_status -eq 0 && -n "$updated_history" ]]; then
704
+ echo "$updated_history" > "$RALPH_SESSION_HISTORY_FILE"
705
+ else
706
+ # Fallback: start fresh with just this transition
707
+ echo "[$transition]" > "$RALPH_SESSION_HISTORY_FILE"
708
+ fi
709
+ }
710
+
711
+ # Generate a unique session ID using timestamp and random component
712
+ generate_session_id() {
713
+ local ts
714
+ ts=$(date +%s)
715
+ local rand
716
+ rand=$RANDOM
717
+ echo "ralph-${ts}-${rand}"
718
+ }
719
+
720
+ # Initialize session tracking (called at loop start)
721
+ init_session_tracking() {
722
+ local ts
723
+ ts=$(get_iso_timestamp)
724
+
725
+ # Create session file if it doesn't exist
726
+ if [[ ! -f "$RALPH_SESSION_FILE" ]]; then
727
+ local new_session_id
728
+ new_session_id=$(generate_session_id)
729
+
730
+ jq -n \
731
+ --arg session_id "$new_session_id" \
732
+ --arg created_at "$ts" \
733
+ --arg last_used "$ts" \
734
+ --arg reset_at "" \
735
+ --arg reset_reason "" \
736
+ '{
737
+ session_id: $session_id,
738
+ created_at: $created_at,
739
+ last_used: $last_used,
740
+ reset_at: $reset_at,
741
+ reset_reason: $reset_reason
742
+ }' > "$RALPH_SESSION_FILE"
743
+
744
+ log_status "INFO" "Initialized session tracking (session: $new_session_id)"
745
+ return 0
746
+ fi
747
+
748
+ # Validate existing session file
749
+ if ! jq empty "$RALPH_SESSION_FILE" 2>/dev/null; then
750
+ log_status "WARN" "Corrupted session file detected, recreating..."
751
+ local new_session_id
752
+ new_session_id=$(generate_session_id)
753
+
754
+ jq -n \
755
+ --arg session_id "$new_session_id" \
756
+ --arg created_at "$ts" \
757
+ --arg last_used "$ts" \
758
+ --arg reset_at "$ts" \
759
+ --arg reset_reason "corrupted_file_recovery" \
760
+ '{
761
+ session_id: $session_id,
762
+ created_at: $created_at,
763
+ last_used: $last_used,
764
+ reset_at: $reset_at,
765
+ reset_reason: $reset_reason
766
+ }' > "$RALPH_SESSION_FILE"
767
+ fi
768
+ }
769
+
770
+ # Update last_used timestamp in session file (called on each loop iteration)
771
+ update_session_last_used() {
772
+ if [[ ! -f "$RALPH_SESSION_FILE" ]]; then
773
+ return 0
774
+ fi
775
+
776
+ local ts
777
+ ts=$(get_iso_timestamp)
778
+
779
+ # Update last_used in existing session file
780
+ local updated
781
+ updated=$(jq --arg last_used "$ts" '.last_used = $last_used' "$RALPH_SESSION_FILE" 2>/dev/null)
782
+ local jq_status=$?
783
+
784
+ if [[ $jq_status -eq 0 && -n "$updated" ]]; then
785
+ echo "$updated" > "$RALPH_SESSION_FILE"
786
+ fi
787
+ }
788
+
789
+ # Global array for Claude command arguments (avoids shell injection)
790
+ declare -a CLAUDE_CMD_ARGS=()
791
+
792
+ # Build Claude CLI command with modern flags using array (shell-injection safe)
793
+ # Populates global CLAUDE_CMD_ARGS array for direct execution
794
+ # Uses -p flag with prompt content (Claude CLI does not have --prompt-file)
795
+ build_claude_command() {
796
+ local prompt_file=$1
797
+ local loop_context=$2
798
+ local session_id=$3
799
+
800
+ # Reset global array
801
+ CLAUDE_CMD_ARGS=("$CLAUDE_CODE_CMD")
802
+
803
+ # Check if prompt file exists
804
+ if [[ ! -f "$prompt_file" ]]; then
805
+ log_status "ERROR" "Prompt file not found: $prompt_file"
806
+ return 1
807
+ fi
808
+
809
+ # Add output format flag
810
+ if [[ "$CLAUDE_OUTPUT_FORMAT" == "json" ]]; then
811
+ CLAUDE_CMD_ARGS+=("--output-format" "json")
812
+ fi
813
+
814
+ # Add allowed tools (each tool as separate array element)
815
+ if [[ -n "$CLAUDE_ALLOWED_TOOLS" ]]; then
816
+ CLAUDE_CMD_ARGS+=("--allowedTools")
817
+ # Split by comma and add each tool
818
+ local IFS=','
819
+ read -ra tools_array <<< "$CLAUDE_ALLOWED_TOOLS"
820
+ for tool in "${tools_array[@]}"; do
821
+ # Trim whitespace
822
+ tool=$(echo "$tool" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
823
+ if [[ -n "$tool" ]]; then
824
+ CLAUDE_CMD_ARGS+=("$tool")
825
+ fi
826
+ done
827
+ fi
828
+
829
+ # Add session continuity flag
830
+ if [[ "$CLAUDE_USE_CONTINUE" == "true" ]]; then
831
+ CLAUDE_CMD_ARGS+=("--continue")
832
+ fi
833
+
834
+ # Add loop context as system prompt (no escaping needed - array handles it)
835
+ if [[ -n "$loop_context" ]]; then
836
+ CLAUDE_CMD_ARGS+=("--append-system-prompt" "$loop_context")
837
+ fi
838
+
839
+ # Read prompt file content and use -p flag
840
+ # Note: Claude CLI uses -p for prompts, not --prompt-file (which doesn't exist)
841
+ # Array-based approach maintains shell injection safety
842
+ local prompt_content
843
+ prompt_content=$(cat "$prompt_file")
844
+ CLAUDE_CMD_ARGS+=("-p" "$prompt_content")
845
+ }
846
+
847
+ # Main execution function
848
+ execute_claude_code() {
849
+ local timestamp=$(date '+%Y-%m-%d_%H-%M-%S')
850
+ local output_file="$LOG_DIR/claude_output_${timestamp}.log"
851
+ local loop_count=$1
852
+ local calls_made=$(cat "$CALL_COUNT_FILE" 2>/dev/null || echo "0")
853
+ calls_made=$((calls_made + 1))
854
+
855
+ log_status "LOOP" "Executing Claude Code (Call $calls_made/$MAX_CALLS_PER_HOUR)"
856
+ local timeout_seconds=$((CLAUDE_TIMEOUT_MINUTES * 60))
857
+ log_status "INFO" "⏳ Starting Claude Code execution... (timeout: ${CLAUDE_TIMEOUT_MINUTES}m)"
858
+
859
+ # Build loop context for session continuity
860
+ local loop_context=""
861
+ if [[ "$CLAUDE_USE_CONTINUE" == "true" ]]; then
862
+ loop_context=$(build_loop_context "$loop_count")
863
+ if [[ -n "$loop_context" && "$VERBOSE_PROGRESS" == "true" ]]; then
864
+ log_status "INFO" "Loop context: $loop_context"
865
+ fi
866
+ fi
867
+
868
+ # Initialize or resume session
869
+ local session_id=""
870
+ if [[ "$CLAUDE_USE_CONTINUE" == "true" ]]; then
871
+ session_id=$(init_claude_session)
872
+ fi
873
+
874
+ # Build the Claude CLI command with modern flags
875
+ # Note: We use the modern CLI with -p flag when CLAUDE_OUTPUT_FORMAT is "json"
876
+ # For backward compatibility, fall back to stdin piping for text mode
877
+ local use_modern_cli=false
878
+
879
+ if [[ "$CLAUDE_OUTPUT_FORMAT" == "json" ]]; then
880
+ # Modern approach: use CLI flags (builds CLAUDE_CMD_ARGS array)
881
+ if build_claude_command "$PROMPT_FILE" "$loop_context" "$session_id"; then
882
+ use_modern_cli=true
883
+ log_status "INFO" "Using modern CLI mode (JSON output)"
884
+ else
885
+ log_status "WARN" "Failed to build modern CLI command, falling back to legacy mode"
886
+ fi
887
+ else
888
+ log_status "INFO" "Using legacy CLI mode (text output)"
889
+ fi
890
+
891
+ # Execute Claude Code
892
+ if [[ "$use_modern_cli" == "true" ]]; then
893
+ # Modern execution with command array (shell-injection safe)
894
+ # Execute array directly without bash -c to prevent shell metacharacter interpretation
895
+ if portable_timeout ${timeout_seconds}s "${CLAUDE_CMD_ARGS[@]}" > "$output_file" 2>&1 &
896
+ then
897
+ : # Continue to wait loop
898
+ else
899
+ log_status "ERROR" "❌ Failed to start Claude Code process (modern mode)"
900
+ # Fall back to legacy mode
901
+ log_status "INFO" "Falling back to legacy mode..."
902
+ use_modern_cli=false
903
+ fi
904
+ fi
905
+
906
+ # Fall back to legacy stdin piping if modern mode failed or not enabled
907
+ if [[ "$use_modern_cli" == "false" ]]; then
908
+ if portable_timeout ${timeout_seconds}s $CLAUDE_CODE_CMD < "$PROMPT_FILE" > "$output_file" 2>&1 &
909
+ then
910
+ : # Continue to wait loop
911
+ else
912
+ log_status "ERROR" "❌ Failed to start Claude Code process"
913
+ return 1
914
+ fi
915
+ fi
916
+
917
+ # Get PID and monitor progress
918
+ local claude_pid=$!
919
+ local progress_counter=0
920
+
921
+ # Show progress while Claude Code is running
922
+ while kill -0 $claude_pid 2>/dev/null; do
923
+ progress_counter=$((progress_counter + 1))
924
+ case $((progress_counter % 4)) in
925
+ 1) progress_indicator="⠋" ;;
926
+ 2) progress_indicator="⠙" ;;
927
+ 3) progress_indicator="⠹" ;;
928
+ 0) progress_indicator="⠸" ;;
929
+ esac
930
+
931
+ # Get last line from output if available
932
+ local last_line=""
933
+ if [[ -f "$output_file" && -s "$output_file" ]]; then
934
+ last_line=$(tail -1 "$output_file" 2>/dev/null | head -c 80)
935
+ fi
936
+
937
+ # Update progress file for monitor
938
+ cat > "$PROGRESS_FILE" << EOF
939
+ {
940
+ "status": "executing",
941
+ "indicator": "$progress_indicator",
942
+ "elapsed_seconds": $((progress_counter * 10)),
943
+ "last_output": "$last_line",
944
+ "timestamp": "$(date '+%Y-%m-%d %H:%M:%S')"
945
+ }
946
+ EOF
947
+
948
+ # Only log if verbose mode is enabled
949
+ if [[ "$VERBOSE_PROGRESS" == "true" ]]; then
950
+ if [[ -n "$last_line" ]]; then
951
+ log_status "INFO" "$progress_indicator Claude Code: $last_line... (${progress_counter}0s)"
952
+ else
953
+ log_status "INFO" "$progress_indicator Claude Code working... (${progress_counter}0s elapsed)"
954
+ fi
955
+ fi
956
+
957
+ sleep 10
958
+ done
959
+
960
+ # Wait for the process to finish and get exit code
961
+ # Use || to prevent set -e from killing the script on non-zero (e.g. timeout 124)
962
+ local exit_code=0
963
+ wait $claude_pid || exit_code=$?
964
+
965
+ if [ $exit_code -eq 124 ]; then
966
+ # Timeout - not a failure, just took too long
967
+ log_status "WARN" "⏰ Claude Code timed out after ${CLAUDE_TIMEOUT_MINUTES} minutes"
968
+ log_status "INFO" "Session will be reset and retried in next loop"
969
+ rm -f "$CLAUDE_SESSION_FILE"
970
+ echo '{"status": "timeout", "timestamp": "'$(date '+%Y-%m-%d %H:%M:%S')'"}' > "$PROGRESS_FILE"
971
+ return 4 # Specific return code for timeout
972
+ elif [ $exit_code -eq 0 ]; then
973
+ # Only increment counter on successful execution
974
+ echo "$calls_made" > "$CALL_COUNT_FILE"
975
+
976
+ # Clear progress file
977
+ echo '{"status": "completed", "timestamp": "'$(date '+%Y-%m-%d %H:%M:%S')'"}' > "$PROGRESS_FILE"
978
+
979
+ log_status "SUCCESS" "✅ Claude Code execution completed successfully"
980
+
981
+ # Save session ID from JSON output (Phase 1.1)
982
+ if [[ "$CLAUDE_USE_CONTINUE" == "true" ]]; then
983
+ save_claude_session "$output_file"
984
+ fi
985
+
986
+ # Analyze the response
987
+ log_status "INFO" "🔍 Analyzing Claude Code response..."
988
+ analyze_response "$output_file" "$loop_count"
989
+ local analysis_exit_code=$?
990
+
991
+ # Update exit signals based on analysis
992
+ update_exit_signals
993
+
994
+ # Log analysis summary
995
+ log_analysis_summary
996
+
997
+ # Get file change count for circuit breaker
998
+ local files_changed=$(git diff --name-only 2>/dev/null | wc -l || echo 0)
999
+ local has_errors="false"
1000
+
1001
+ # Two-stage error detection to avoid JSON field false positives
1002
+ # Stage 1: Filter out JSON field patterns like "is_error": false
1003
+ # Stage 2: Look for actual error messages in specific contexts
1004
+ # Avoid type annotations like "error: Error" by requiring lowercase after ": error"
1005
+ if grep -v '"[^"]*error[^"]*":' "$output_file" 2>/dev/null | \
1006
+ grep -qE '(^Error:|^ERROR:|^error:|\]: error|Link: error|Error occurred|failed with error|[Ee]xception|Fatal|FATAL)'; then
1007
+ has_errors="true"
1008
+
1009
+ # Debug logging: show what triggered error detection
1010
+ if [[ "$VERBOSE_PROGRESS" == "true" ]]; then
1011
+ log_status "DEBUG" "Error patterns found:"
1012
+ grep -v '"[^"]*error[^"]*":' "$output_file" 2>/dev/null | \
1013
+ grep -nE '(^Error:|^ERROR:|^error:|\]: error|Link: error|Error occurred|failed with error|[Ee]xception|Fatal|FATAL)' | \
1014
+ head -3 | while IFS= read -r line; do
1015
+ log_status "DEBUG" " $line"
1016
+ done
1017
+ fi
1018
+
1019
+ log_status "WARN" "Errors detected in output, check: $output_file"
1020
+ fi
1021
+ local output_length=$(wc -c < "$output_file" 2>/dev/null || echo 0)
1022
+
1023
+ # Record result in circuit breaker
1024
+ record_loop_result "$loop_count" "$files_changed" "$has_errors" "$output_length"
1025
+ local circuit_result=$?
1026
+
1027
+ if [[ $circuit_result -ne 0 ]]; then
1028
+ log_status "WARN" "Circuit breaker opened - halting execution"
1029
+ return 3 # Special code for circuit breaker trip
1030
+ fi
1031
+
1032
+ return 0
1033
+ else
1034
+ # Clear progress file on failure
1035
+ echo '{"status": "failed", "timestamp": "'$(date '+%Y-%m-%d %H:%M:%S')'"}' > "$PROGRESS_FILE"
1036
+
1037
+ # Check if the failure is due to API 5-hour limit
1038
+ if grep -qi "5.*hour.*limit\|limit.*reached.*try.*back\|usage.*limit.*reached" "$output_file"; then
1039
+ log_status "ERROR" "🚫 Claude API 5-hour usage limit reached"
1040
+ return 2 # Special return code for API limit
1041
+ else
1042
+ log_status "ERROR" "❌ Claude Code execution failed, check: $output_file"
1043
+ return 1
1044
+ fi
1045
+ fi
1046
+ }
1047
+
1048
+ # Cleanup function
1049
+ cleanup() {
1050
+ log_status "INFO" "Ralph loop interrupted. Cleaning up..."
1051
+ reset_session "manual_interrupt"
1052
+ update_status "$loop_count" "$(cat "$CALL_COUNT_FILE" 2>/dev/null || echo "0")" "interrupted" "stopped"
1053
+ exit 0
1054
+ }
1055
+
1056
+ # Set up signal handlers
1057
+ trap cleanup SIGINT SIGTERM
1058
+
1059
+ # Global variable for loop count (needed by cleanup function)
1060
+ loop_count=0
1061
+
1062
+ # Main loop
1063
+ main() {
1064
+
1065
+ log_status "SUCCESS" "🚀 Ralph loop starting with Claude Code"
1066
+ log_status "INFO" "Max calls per hour: $MAX_CALLS_PER_HOUR"
1067
+ log_status "INFO" "Logs: $LOG_DIR/ | Docs: $DOCS_DIR/ | Status: $STATUS_FILE"
1068
+
1069
+ # Check if project uses old flat structure and needs migration
1070
+ if [[ -f "PROMPT.md" ]] && [[ ! -d ".ralph" ]]; then
1071
+ log_status "ERROR" "This project uses the old flat structure."
1072
+ echo ""
1073
+ echo "Ralph v0.10.0+ uses a .ralph/ subfolder to keep your project root clean."
1074
+ echo ""
1075
+ echo "To upgrade your project, run:"
1076
+ echo " ralph-migrate"
1077
+ echo ""
1078
+ echo "This will move Ralph-specific files to .ralph/ while preserving src/ at root."
1079
+ echo "A backup will be created before migration."
1080
+ exit 1
1081
+ fi
1082
+
1083
+ # Check if this is a Ralph project directory
1084
+ if [[ ! -f "$PROMPT_FILE" ]]; then
1085
+ log_status "ERROR" "Prompt file '$PROMPT_FILE' not found!"
1086
+ echo ""
1087
+
1088
+ # Check if this looks like a partial Ralph project
1089
+ if [[ -f "$RALPH_DIR/@fix_plan.md" ]] || [[ -d "$RALPH_DIR/specs" ]] || [[ -f "$RALPH_DIR/@AGENT.md" ]]; then
1090
+ echo "This appears to be a Ralph project but is missing .ralph/PROMPT.md."
1091
+ echo "You may need to create or restore the PROMPT.md file."
1092
+ else
1093
+ echo "This directory is not a Ralph project."
1094
+ fi
1095
+
1096
+ echo ""
1097
+ echo "To fix this:"
1098
+ echo " 1. Create a new project: ralph-setup my-project"
1099
+ echo " 2. Import existing requirements: ralph-import requirements.md"
1100
+ echo " 3. Navigate to an existing Ralph project directory"
1101
+ echo " 4. Or create .ralph/PROMPT.md manually in this directory"
1102
+ echo ""
1103
+ echo "Ralph projects should contain: .ralph/PROMPT.md, .ralph/@fix_plan.md, .ralph/specs/, src/, etc."
1104
+ exit 1
1105
+ fi
1106
+
1107
+ # Initialize session tracking before entering the loop
1108
+ init_session_tracking
1109
+
1110
+ log_status "INFO" "Starting main loop..."
1111
+ log_status "INFO" "DEBUG: About to enter while loop, loop_count=$loop_count"
1112
+
1113
+ while true; do
1114
+ loop_count=$((loop_count + 1))
1115
+ log_status "INFO" "DEBUG: Successfully incremented loop_count to $loop_count"
1116
+
1117
+ # Update session last_used timestamp
1118
+ update_session_last_used
1119
+
1120
+ log_status "INFO" "Loop #$loop_count - calling init_call_tracking..."
1121
+ init_call_tracking
1122
+
1123
+ log_status "LOOP" "=== Starting Loop #$loop_count ==="
1124
+
1125
+ # Check circuit breaker before attempting execution
1126
+ if should_halt_execution; then
1127
+ reset_session "circuit_breaker_open"
1128
+ update_status "$loop_count" "$(cat "$CALL_COUNT_FILE")" "circuit_breaker_open" "halted" "stagnation_detected"
1129
+ log_status "ERROR" "🛑 Circuit breaker has opened - execution halted"
1130
+ break
1131
+ fi
1132
+
1133
+ # Check rate limits
1134
+ if ! can_make_call; then
1135
+ wait_for_reset
1136
+ continue
1137
+ fi
1138
+
1139
+ # Check for graceful exit conditions
1140
+ local exit_reason=$(should_exit_gracefully)
1141
+ if [[ "$exit_reason" != "" ]]; then
1142
+ log_status "SUCCESS" "🏁 Graceful exit triggered: $exit_reason"
1143
+ reset_session "project_complete"
1144
+ update_status "$loop_count" "$(cat "$CALL_COUNT_FILE")" "graceful_exit" "completed" "$exit_reason"
1145
+
1146
+ log_status "SUCCESS" "🎉 Ralph has completed the project! Final stats:"
1147
+ log_status "INFO" " - Total loops: $loop_count"
1148
+ log_status "INFO" " - API calls used: $(cat "$CALL_COUNT_FILE")"
1149
+ log_status "INFO" " - Exit reason: $exit_reason"
1150
+
1151
+ break
1152
+ fi
1153
+
1154
+ # Update status
1155
+ local calls_made=$(cat "$CALL_COUNT_FILE" 2>/dev/null || echo "0")
1156
+ update_status "$loop_count" "$calls_made" "executing" "running"
1157
+
1158
+ # Execute Claude Code
1159
+ local exec_result=0
1160
+ execute_claude_code "$loop_count" || exec_result=$?
1161
+
1162
+ if [ $exec_result -eq 0 ]; then
1163
+ update_status "$loop_count" "$(cat "$CALL_COUNT_FILE")" "completed" "success"
1164
+
1165
+ # Brief pause between successful executions
1166
+ sleep 5
1167
+ elif [ $exec_result -eq 3 ]; then
1168
+ # Circuit breaker opened
1169
+ reset_session "circuit_breaker_trip"
1170
+ update_status "$loop_count" "$(cat "$CALL_COUNT_FILE")" "circuit_breaker_open" "halted" "stagnation_detected"
1171
+ log_status "ERROR" "🛑 Circuit breaker has opened - halting loop"
1172
+ log_status "INFO" "Run 'ralph --reset-circuit' to reset the circuit breaker after addressing issues"
1173
+ break
1174
+ elif [ $exec_result -eq 2 ]; then
1175
+ # API 5-hour limit reached - handle specially
1176
+ update_status "$loop_count" "$(cat "$CALL_COUNT_FILE")" "api_limit" "paused"
1177
+ log_status "WARN" "🛑 Claude API 5-hour limit reached!"
1178
+
1179
+ # Ask user whether to wait or exit
1180
+ echo -e "\n${YELLOW}The Claude API 5-hour usage limit has been reached.${NC}"
1181
+ echo -e "${YELLOW}You can either:${NC}"
1182
+ echo -e " ${GREEN}1)${NC} Wait for the limit to reset (usually within an hour)"
1183
+ echo -e " ${GREEN}2)${NC} Exit the loop and try again later"
1184
+ echo -e "\n${BLUE}Choose an option (1 or 2):${NC} "
1185
+
1186
+ # Read user input with timeout
1187
+ read -t 30 -n 1 user_choice
1188
+ echo # New line after input
1189
+
1190
+ if [[ "$user_choice" == "2" ]] || [[ -z "$user_choice" ]]; then
1191
+ log_status "INFO" "User chose to exit (or timed out). Exiting loop..."
1192
+ update_status "$loop_count" "$(cat "$CALL_COUNT_FILE")" "api_limit_exit" "stopped" "api_5hour_limit"
1193
+ break
1194
+ else
1195
+ log_status "INFO" "User chose to wait. Waiting for API limit reset..."
1196
+ # Wait for longer period when API limit is hit
1197
+ local wait_minutes=60
1198
+ log_status "INFO" "Waiting $wait_minutes minutes before retrying..."
1199
+
1200
+ # Countdown display
1201
+ local wait_seconds=$((wait_minutes * 60))
1202
+ while [[ $wait_seconds -gt 0 ]]; do
1203
+ local minutes=$((wait_seconds / 60))
1204
+ local seconds=$((wait_seconds % 60))
1205
+ printf "\r${YELLOW}Time until retry: %02d:%02d${NC}" $minutes $seconds
1206
+ sleep 1
1207
+ ((wait_seconds--))
1208
+ done
1209
+ printf "\n"
1210
+ fi
1211
+ elif [ $exec_result -eq 4 ]; then
1212
+ # Timeout - non-fatal, session already reset in execute_claude_code
1213
+ update_status "$loop_count" "$(cat "$CALL_COUNT_FILE")" "timeout" "retrying"
1214
+ log_status "INFO" "Retrying with fresh session in 10 seconds..."
1215
+ sleep 10
1216
+ else
1217
+ update_status "$loop_count" "$(cat "$CALL_COUNT_FILE")" "failed" "error"
1218
+ log_status "WARN" "Execution failed, waiting 30 seconds before retry..."
1219
+ sleep 30
1220
+ fi
1221
+
1222
+ log_status "LOOP" "=== Completed Loop #$loop_count ==="
1223
+ done
1224
+ }
1225
+
1226
+ # Help function
1227
+ show_help() {
1228
+ cat << HELPEOF
1229
+ Ralph Loop for Claude Code
1230
+
1231
+ Usage: $0 [OPTIONS]
1232
+
1233
+ IMPORTANT: This command must be run from a Ralph project directory.
1234
+ Use 'ralph-setup project-name' to create a new project first.
1235
+
1236
+ Options:
1237
+ -h, --help Show this help message
1238
+ -c, --calls NUM Set max calls per hour (default: $MAX_CALLS_PER_HOUR)
1239
+ -p, --prompt FILE Set prompt file (default: $PROMPT_FILE)
1240
+ -s, --status Show current status and exit
1241
+ -m, --monitor Start with tmux session and live monitor (requires tmux)
1242
+ -v, --verbose Show detailed progress updates during execution
1243
+ -t, --timeout MIN Set Claude Code execution timeout in minutes (default: $CLAUDE_TIMEOUT_MINUTES)
1244
+ --reset-circuit Reset circuit breaker to CLOSED state
1245
+ --circuit-status Show circuit breaker status and exit
1246
+ --reset-session Reset session state and exit (clears session continuity)
1247
+
1248
+ Modern CLI Options (Phase 1.1):
1249
+ --output-format FORMAT Set Claude output format: json or text (default: $CLAUDE_OUTPUT_FORMAT)
1250
+ --allowed-tools TOOLS Comma-separated list of allowed tools (default: $CLAUDE_ALLOWED_TOOLS)
1251
+ --no-continue Disable session continuity across loops
1252
+ --session-expiry HOURS Set session expiration time in hours (default: $CLAUDE_SESSION_EXPIRY_HOURS)
1253
+
1254
+ Files created:
1255
+ - $LOG_DIR/: All execution logs
1256
+ - $DOCS_DIR/: Generated documentation
1257
+ - $STATUS_FILE: Current status (JSON)
1258
+ - .ralph/.ralph_session: Session lifecycle tracking
1259
+ - .ralph/.ralph_session_history: Session transition history (last 50)
1260
+ - .ralph/.call_count: API call counter for rate limiting
1261
+ - .ralph/.last_reset: Timestamp of last rate limit reset
1262
+
1263
+ Example workflow:
1264
+ ralph-setup my-project # Create project
1265
+ cd my-project # Enter project directory
1266
+ $0 --monitor # Start Ralph with monitoring
1267
+
1268
+ Examples:
1269
+ $0 --calls 50 --prompt my_prompt.md
1270
+ $0 --monitor # Start with integrated tmux monitoring
1271
+ $0 --monitor --timeout 30 # 30-minute timeout for complex tasks
1272
+ $0 --verbose --timeout 5 # 5-minute timeout with detailed progress
1273
+ $0 --output-format text # Use legacy text output format
1274
+ $0 --no-continue # Disable session continuity
1275
+ $0 --session-expiry 48 # 48-hour session expiration
1276
+
1277
+ HELPEOF
1278
+ }
1279
+
1280
+ # Parse command line arguments
1281
+ while [[ $# -gt 0 ]]; do
1282
+ case $1 in
1283
+ -h|--help)
1284
+ show_help
1285
+ exit 0
1286
+ ;;
1287
+ -c|--calls)
1288
+ MAX_CALLS_PER_HOUR="$2"
1289
+ shift 2
1290
+ ;;
1291
+ -p|--prompt)
1292
+ PROMPT_FILE="$2"
1293
+ shift 2
1294
+ ;;
1295
+ -s|--status)
1296
+ if [[ -f "$STATUS_FILE" ]]; then
1297
+ echo "Current Status:"
1298
+ cat "$STATUS_FILE" | jq . 2>/dev/null || cat "$STATUS_FILE"
1299
+ else
1300
+ echo "No status file found. Ralph may not be running."
1301
+ fi
1302
+ exit 0
1303
+ ;;
1304
+ -m|--monitor)
1305
+ USE_TMUX=true
1306
+ shift
1307
+ ;;
1308
+ -v|--verbose)
1309
+ VERBOSE_PROGRESS=true
1310
+ shift
1311
+ ;;
1312
+ -t|--timeout)
1313
+ if [[ "$2" =~ ^[1-9][0-9]*$ ]] && [[ "$2" -le 120 ]]; then
1314
+ CLAUDE_TIMEOUT_MINUTES="$2"
1315
+ else
1316
+ echo "Error: Timeout must be a positive integer between 1 and 120 minutes"
1317
+ exit 1
1318
+ fi
1319
+ shift 2
1320
+ ;;
1321
+ --reset-circuit)
1322
+ # Source the circuit breaker library
1323
+ SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
1324
+ source "$SCRIPT_DIR/lib/circuit_breaker.sh"
1325
+ source "$SCRIPT_DIR/lib/date_utils.sh"
1326
+ reset_circuit_breaker "Manual reset via command line"
1327
+ reset_session "manual_circuit_reset"
1328
+ exit 0
1329
+ ;;
1330
+ --reset-session)
1331
+ # Reset session state only
1332
+ SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
1333
+ source "$SCRIPT_DIR/lib/date_utils.sh"
1334
+ reset_session "manual_reset_flag"
1335
+ echo -e "\033[0;32m✅ Session state reset successfully\033[0m"
1336
+ exit 0
1337
+ ;;
1338
+ --circuit-status)
1339
+ # Source the circuit breaker library
1340
+ SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
1341
+ source "$SCRIPT_DIR/lib/circuit_breaker.sh"
1342
+ show_circuit_status
1343
+ exit 0
1344
+ ;;
1345
+ --output-format)
1346
+ if [[ "$2" == "json" || "$2" == "text" ]]; then
1347
+ CLAUDE_OUTPUT_FORMAT="$2"
1348
+ else
1349
+ echo "Error: --output-format must be 'json' or 'text'"
1350
+ exit 1
1351
+ fi
1352
+ shift 2
1353
+ ;;
1354
+ --allowed-tools)
1355
+ if ! validate_allowed_tools "$2"; then
1356
+ exit 1
1357
+ fi
1358
+ CLAUDE_ALLOWED_TOOLS="$2"
1359
+ shift 2
1360
+ ;;
1361
+ --no-continue)
1362
+ CLAUDE_USE_CONTINUE=false
1363
+ shift
1364
+ ;;
1365
+ --session-expiry)
1366
+ if [[ -z "$2" || ! "$2" =~ ^[1-9][0-9]*$ ]]; then
1367
+ echo "Error: --session-expiry requires a positive integer (hours)"
1368
+ exit 1
1369
+ fi
1370
+ CLAUDE_SESSION_EXPIRY_HOURS="$2"
1371
+ shift 2
1372
+ ;;
1373
+ *)
1374
+ echo "Unknown option: $1"
1375
+ show_help
1376
+ exit 1
1377
+ ;;
1378
+ esac
1379
+ done
1380
+
1381
+ # Only execute when run directly, not when sourced
1382
+ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
1383
+ # If tmux mode requested, set it up
1384
+ if [[ "$USE_TMUX" == "true" ]]; then
1385
+ check_tmux_available
1386
+ setup_tmux_session
1387
+ fi
1388
+
1389
+ # Start the main loop
1390
+ main
1391
+ fi