prizmkit 1.1.99 → 1.1.101

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 (321) hide show
  1. package/bin/create-prizmkit.js +4 -4
  2. package/bundled/VERSION.json +3 -3
  3. package/bundled/dev-pipeline/.env.example +3 -3
  4. package/bundled/dev-pipeline/README.md +110 -90
  5. package/bundled/dev-pipeline/assets/prizm-dev-team-integration.md +1 -1
  6. package/bundled/dev-pipeline/cli.py +27 -0
  7. package/bundled/dev-pipeline/prizmkit_runtime/__init__.py +13 -0
  8. package/bundled/dev-pipeline/prizmkit_runtime/__main__.py +9 -0
  9. package/bundled/dev-pipeline/prizmkit_runtime/cli.py +193 -0
  10. package/bundled/dev-pipeline/prizmkit_runtime/commands.py +313 -0
  11. package/bundled/dev-pipeline/prizmkit_runtime/compat.py +32 -0
  12. package/bundled/dev-pipeline/prizmkit_runtime/config.py +410 -0
  13. package/bundled/dev-pipeline/prizmkit_runtime/daemon.py +478 -0
  14. package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +734 -0
  15. package/bundled/dev-pipeline/prizmkit_runtime/heartbeat.py +256 -0
  16. package/bundled/dev-pipeline/prizmkit_runtime/interoperability.py +109 -0
  17. package/bundled/dev-pipeline/prizmkit_runtime/paths.py +110 -0
  18. package/bundled/dev-pipeline/prizmkit_runtime/processes.py +373 -0
  19. package/bundled/dev-pipeline/prizmkit_runtime/reset.py +389 -0
  20. package/bundled/dev-pipeline/prizmkit_runtime/runner_bookkeeping.py +51 -0
  21. package/bundled/dev-pipeline/prizmkit_runtime/runner_classification.py +179 -0
  22. package/bundled/dev-pipeline/prizmkit_runtime/runner_models.py +345 -0
  23. package/bundled/dev-pipeline/prizmkit_runtime/runner_prompts.py +118 -0
  24. package/bundled/dev-pipeline/prizmkit_runtime/runner_recovery.py +187 -0
  25. package/bundled/dev-pipeline/prizmkit_runtime/runner_status.py +147 -0
  26. package/bundled/dev-pipeline/prizmkit_runtime/runners.py +422 -0
  27. package/bundled/dev-pipeline/prizmkit_runtime/sessions.py +552 -0
  28. package/bundled/dev-pipeline/prizmkit_runtime/status.py +71 -0
  29. package/bundled/dev-pipeline/scripts/check-session-status.py +74 -1
  30. package/bundled/dev-pipeline/scripts/continuation.py +374 -0
  31. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +64 -52
  32. package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +35 -25
  33. package/bundled/dev-pipeline/scripts/generate-recovery-prompt.py +2 -2
  34. package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +15 -20
  35. package/bundled/dev-pipeline/scripts/parse-stream-progress.py +185 -16
  36. package/bundled/dev-pipeline/scripts/update-bug-status.py +214 -6
  37. package/bundled/dev-pipeline/scripts/update-feature-status.py +237 -6
  38. package/bundled/dev-pipeline/scripts/update-refactor-status.py +214 -6
  39. package/bundled/dev-pipeline/templates/agent-prompts/dev-implement.md +8 -2
  40. package/bundled/dev-pipeline/templates/bootstrap-prompt.md +4 -0
  41. package/bundled/dev-pipeline/templates/bootstrap-tier1.md +14 -5
  42. package/bundled/dev-pipeline/templates/bootstrap-tier2.md +16 -6
  43. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +16 -6
  44. package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +1 -1
  45. package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +3 -3
  46. package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +2 -0
  47. package/bundled/dev-pipeline/templates/sections/log-size-awareness.md +13 -69
  48. package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-agent-suffix.md +15 -7
  49. package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +42 -29
  50. package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +41 -39
  51. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-agent.md +4 -0
  52. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-lite.md +4 -0
  53. package/bundled/dev-pipeline/templates/session-status-schema.json +1 -1
  54. package/bundled/dev-pipeline/tests/conftest.py +1 -0
  55. package/bundled/dev-pipeline/tests/test_auto_skip.py +932 -0
  56. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +207 -0
  57. package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +100 -0
  58. package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +43 -0
  59. package/bundled/dev-pipeline/tests/test_python_runner_parity.py +1138 -0
  60. package/bundled/dev-pipeline/tests/test_unified_cli.py +1045 -0
  61. package/bundled/skills/_metadata.json +1 -1
  62. package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +29 -34
  63. package/bundled/skills/bugfix-pipeline-launcher/references/configuration.md +6 -5
  64. package/bundled/skills/feature-pipeline-launcher/SKILL.md +29 -35
  65. package/bundled/skills/feature-pipeline-launcher/references/configuration.md +7 -6
  66. package/bundled/skills/feature-workflow/SKILL.md +3 -6
  67. package/bundled/skills/recovery-workflow/SKILL.md +23 -32
  68. package/bundled/skills/refactor-pipeline-launcher/SKILL.md +29 -35
  69. package/bundled/skills/refactor-pipeline-launcher/references/configuration.md +7 -6
  70. package/bundled/skills/refactor-workflow/SKILL.md +3 -6
  71. package/bundled/templates/hooks/commit-intent.json +2 -2
  72. package/bundled/templates/hooks/diff-prizm-docs.py +226 -0
  73. package/bundled/templates/hooks/prizm-pre-commit.py +45 -0
  74. package/bundled/templates/hooks/validate-prizm-docs.py +240 -0
  75. package/package.json +1 -1
  76. package/src/config.js +33 -12
  77. package/src/index.js +3 -6
  78. package/src/manifest.js +3 -2
  79. package/src/metadata.js +7 -18
  80. package/src/prompts.js +0 -12
  81. package/src/runtimes.js +18 -11
  82. package/src/scaffold.js +133 -116
  83. package/src/upgrade.js +1 -1
  84. package/bundled/dev-pipeline/launch-bugfix-daemon.sh +0 -500
  85. package/bundled/dev-pipeline/launch-feature-daemon.sh +0 -657
  86. package/bundled/dev-pipeline/launch-refactor-daemon.sh +0 -502
  87. package/bundled/dev-pipeline/lib/branch.sh +0 -326
  88. package/bundled/dev-pipeline/lib/common.sh +0 -1257
  89. package/bundled/dev-pipeline/lib/heartbeat.sh +0 -469
  90. package/bundled/dev-pipeline/reset-bug.sh +0 -395
  91. package/bundled/dev-pipeline/reset-feature.sh +0 -406
  92. package/bundled/dev-pipeline/reset-refactor.sh +0 -393
  93. package/bundled/dev-pipeline/run-bugfix.sh +0 -1315
  94. package/bundled/dev-pipeline/run-feature.sh +0 -1602
  95. package/bundled/dev-pipeline/run-recovery.sh +0 -648
  96. package/bundled/dev-pipeline/run-refactor.sh +0 -1348
  97. package/bundled/dev-pipeline/scripts/monitor-log.sh +0 -104
  98. package/bundled/dev-pipeline/tests/test-path-resolution.sh +0 -100
  99. package/bundled/dev-pipeline-windows/.env.example +0 -36
  100. package/bundled/dev-pipeline-windows/README.md +0 -30
  101. package/bundled/dev-pipeline-windows/SCHEMA_ANALYSIS.md +0 -533
  102. package/bundled/dev-pipeline-windows/assets/feature-list-example.json +0 -146
  103. package/bundled/dev-pipeline-windows/assets/prizm-dev-team-integration.md +0 -137
  104. package/bundled/dev-pipeline-windows/launch-bugfix-daemon.ps1 +0 -9
  105. package/bundled/dev-pipeline-windows/launch-feature-daemon.ps1 +0 -9
  106. package/bundled/dev-pipeline-windows/launch-refactor-daemon.ps1 +0 -9
  107. package/bundled/dev-pipeline-windows/lib/branch.ps1 +0 -235
  108. package/bundled/dev-pipeline-windows/lib/common.ps1 +0 -829
  109. package/bundled/dev-pipeline-windows/lib/daemon.ps1 +0 -140
  110. package/bundled/dev-pipeline-windows/lib/pipeline.ps1 +0 -967
  111. package/bundled/dev-pipeline-windows/lib/reset.ps1 +0 -87
  112. package/bundled/dev-pipeline-windows/reset-bug.ps1 +0 -9
  113. package/bundled/dev-pipeline-windows/reset-feature.ps1 +0 -9
  114. package/bundled/dev-pipeline-windows/reset-refactor.ps1 +0 -9
  115. package/bundled/dev-pipeline-windows/run-bugfix.ps1 +0 -9
  116. package/bundled/dev-pipeline-windows/run-feature.ps1 +0 -9
  117. package/bundled/dev-pipeline-windows/run-recovery.ps1 +0 -179
  118. package/bundled/dev-pipeline-windows/run-refactor.ps1 +0 -9
  119. package/bundled/dev-pipeline-windows/scripts/check-session-status.py +0 -228
  120. package/bundled/dev-pipeline-windows/scripts/detect-stuck.py +0 -530
  121. package/bundled/dev-pipeline-windows/scripts/generate-bootstrap-prompt.py +0 -2282
  122. package/bundled/dev-pipeline-windows/scripts/generate-bugfix-prompt.py +0 -767
  123. package/bundled/dev-pipeline-windows/scripts/generate-recovery-prompt.py +0 -805
  124. package/bundled/dev-pipeline-windows/scripts/generate-refactor-prompt.py +0 -845
  125. package/bundled/dev-pipeline-windows/scripts/init-bugfix-pipeline.py +0 -316
  126. package/bundled/dev-pipeline-windows/scripts/init-dev-team.py +0 -134
  127. package/bundled/dev-pipeline-windows/scripts/init-pipeline.py +0 -382
  128. package/bundled/dev-pipeline-windows/scripts/init-refactor-pipeline.py +0 -399
  129. package/bundled/dev-pipeline-windows/scripts/monitor-log.ps1 +0 -102
  130. package/bundled/dev-pipeline-windows/scripts/parse-stream-progress.py +0 -1232
  131. package/bundled/dev-pipeline-windows/scripts/patch-completion-notes.py +0 -191
  132. package/bundled/dev-pipeline-windows/scripts/prizmkit-test-gate.py +0 -446
  133. package/bundled/dev-pipeline-windows/scripts/update-bug-status.py +0 -913
  134. package/bundled/dev-pipeline-windows/scripts/update-checkpoint.py +0 -173
  135. package/bundled/dev-pipeline-windows/scripts/update-feature-status.py +0 -1558
  136. package/bundled/dev-pipeline-windows/scripts/update-refactor-status.py +0 -1119
  137. package/bundled/dev-pipeline-windows/scripts/utils.py +0 -542
  138. package/bundled/dev-pipeline-windows/templates/agent-prompts/critic-plan-challenge.md +0 -7
  139. package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-fix.md +0 -7
  140. package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-implement.md +0 -65
  141. package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-resume.md +0 -5
  142. package/bundled/dev-pipeline-windows/templates/agent-prompts/reviewer-review.md +0 -7
  143. package/bundled/dev-pipeline-windows/templates/bootstrap-prompt.md +0 -73
  144. package/bundled/dev-pipeline-windows/templates/bootstrap-tier1.md +0 -589
  145. package/bundled/dev-pipeline-windows/templates/bootstrap-tier2.md +0 -710
  146. package/bundled/dev-pipeline-windows/templates/bootstrap-tier3.md +0 -791
  147. package/bundled/dev-pipeline-windows/templates/bug-fix-list-schema.json +0 -263
  148. package/bundled/dev-pipeline-windows/templates/bugfix-bootstrap-prompt.md +0 -326
  149. package/bundled/dev-pipeline-windows/templates/feature-list-schema.json +0 -237
  150. package/bundled/dev-pipeline-windows/templates/refactor-bootstrap-prompt.md +0 -340
  151. package/bundled/dev-pipeline-windows/templates/refactor-list-schema.json +0 -270
  152. package/bundled/dev-pipeline-windows/templates/sections/ac-verification-checklist.md +0 -7
  153. package/bundled/dev-pipeline-windows/templates/sections/checkpoint-system.md +0 -91
  154. package/bundled/dev-pipeline-windows/templates/sections/context-budget-rules.md +0 -34
  155. package/bundled/dev-pipeline-windows/templates/sections/critical-paths-agent.md +0 -10
  156. package/bundled/dev-pipeline-windows/templates/sections/critical-paths-full.md +0 -12
  157. package/bundled/dev-pipeline-windows/templates/sections/critical-paths-lite.md +0 -7
  158. package/bundled/dev-pipeline-windows/templates/sections/directory-convention-agent.md +0 -8
  159. package/bundled/dev-pipeline-windows/templates/sections/directory-convention-full.md +0 -9
  160. package/bundled/dev-pipeline-windows/templates/sections/directory-convention-lite.md +0 -6
  161. package/bundled/dev-pipeline-windows/templates/sections/failure-capture.md +0 -21
  162. package/bundled/dev-pipeline-windows/templates/sections/feature-context.md +0 -21
  163. package/bundled/dev-pipeline-windows/templates/sections/log-size-awareness.md +0 -78
  164. package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification-auto.md +0 -283
  165. package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification-opencli.md +0 -112
  166. package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification.md +0 -168
  167. package/bundled/dev-pipeline-windows/templates/sections/phase-commit-full.md +0 -82
  168. package/bundled/dev-pipeline-windows/templates/sections/phase-commit.md +0 -75
  169. package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-agent-suffix.md +0 -23
  170. package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-base.md +0 -14
  171. package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-lite-suffix.md +0 -19
  172. package/bundled/dev-pipeline-windows/templates/sections/phase-critic-plan-full.md +0 -63
  173. package/bundled/dev-pipeline-windows/templates/sections/phase-critic-plan.md +0 -42
  174. package/bundled/dev-pipeline-windows/templates/sections/phase-implement-agent.md +0 -44
  175. package/bundled/dev-pipeline-windows/templates/sections/phase-implement-full.md +0 -59
  176. package/bundled/dev-pipeline-windows/templates/sections/phase-implement-lite.md +0 -39
  177. package/bundled/dev-pipeline-windows/templates/sections/phase-plan-agent.md +0 -27
  178. package/bundled/dev-pipeline-windows/templates/sections/phase-plan-lite.md +0 -27
  179. package/bundled/dev-pipeline-windows/templates/sections/phase-prizmkit-test.md +0 -39
  180. package/bundled/dev-pipeline-windows/templates/sections/phase-review-agent.md +0 -35
  181. package/bundled/dev-pipeline-windows/templates/sections/phase-review-full.md +0 -35
  182. package/bundled/dev-pipeline-windows/templates/sections/phase-specify-plan-full.md +0 -73
  183. package/bundled/dev-pipeline-windows/templates/sections/phase0-init.md +0 -13
  184. package/bundled/dev-pipeline-windows/templates/sections/phase0-test-baseline.md +0 -21
  185. package/bundled/dev-pipeline-windows/templates/sections/session-context.md +0 -5
  186. package/bundled/dev-pipeline-windows/templates/sections/subagent-timeout-recovery.md +0 -6
  187. package/bundled/dev-pipeline-windows/templates/sections/task-contract.md +0 -34
  188. package/bundled/dev-pipeline-windows/templates/sections/test-failure-recovery-agent.md +0 -48
  189. package/bundled/dev-pipeline-windows/templates/sections/test-failure-recovery-lite.md +0 -48
  190. package/bundled/dev-pipeline-windows/templates/session-status-schema.json +0 -83
  191. package/bundled/skills-windows/app-planner/SKILL.md +0 -296
  192. package/bundled/skills-windows/app-planner/assets/app-design-guide.md +0 -101
  193. package/bundled/skills-windows/app-planner/references/architecture-decisions.md +0 -52
  194. package/bundled/skills-windows/app-planner/references/brainstorm-guide.md +0 -101
  195. package/bundled/skills-windows/app-planner/references/frontend-design-guide.md +0 -71
  196. package/bundled/skills-windows/app-planner/references/infrastructure-convention-discovery.md +0 -108
  197. package/bundled/skills-windows/app-planner/references/project-brief-guide.md +0 -82
  198. package/bundled/skills-windows/app-planner/references/project-conventions-discovery.md +0 -59
  199. package/bundled/skills-windows/app-planner/references/project-state-detection.md +0 -90
  200. package/bundled/skills-windows/app-planner/references/red-team-checklist.md +0 -40
  201. package/bundled/skills-windows/app-planner/references/rules/backend/derivation-rules.md +0 -619
  202. package/bundled/skills-windows/app-planner/references/rules/backend/fixed-rules.md +0 -285
  203. package/bundled/skills-windows/app-planner/references/rules/backend/question-bank.md +0 -249
  204. package/bundled/skills-windows/app-planner/references/rules/backend/question-manifest.json +0 -46
  205. package/bundled/skills-windows/app-planner/references/rules/backend/template.md +0 -173
  206. package/bundled/skills-windows/app-planner/references/rules/database/derivation-rules.md +0 -382
  207. package/bundled/skills-windows/app-planner/references/rules/database/fixed-rules.md +0 -211
  208. package/bundled/skills-windows/app-planner/references/rules/database/question-bank.md +0 -184
  209. package/bundled/skills-windows/app-planner/references/rules/database/question-manifest.json +0 -39
  210. package/bundled/skills-windows/app-planner/references/rules/database/template.md +0 -158
  211. package/bundled/skills-windows/app-planner/references/rules/frontend/derivation-rules.md +0 -820
  212. package/bundled/skills-windows/app-planner/references/rules/frontend/fixed-rules.md +0 -188
  213. package/bundled/skills-windows/app-planner/references/rules/frontend/question-bank.md +0 -319
  214. package/bundled/skills-windows/app-planner/references/rules/frontend/question-manifest.json +0 -51
  215. package/bundled/skills-windows/app-planner/references/rules/frontend/template.md +0 -339
  216. package/bundled/skills-windows/app-planner/references/rules/mobile/derivation-rules.md +0 -649
  217. package/bundled/skills-windows/app-planner/references/rules/mobile/fixed-rules.md +0 -290
  218. package/bundled/skills-windows/app-planner/references/rules/mobile/question-bank.md +0 -232
  219. package/bundled/skills-windows/app-planner/references/rules/mobile/question-manifest.json +0 -47
  220. package/bundled/skills-windows/app-planner/references/rules/mobile/template.md +0 -175
  221. package/bundled/skills-windows/app-planner/references/rules-configuration.md +0 -46
  222. package/bundled/skills-windows/bug-fix-workflow/SKILL.md +0 -379
  223. package/bundled/skills-windows/bug-fix-workflow/references/bug-diagnosis.md +0 -41
  224. package/bundled/skills-windows/bug-planner/SKILL.md +0 -402
  225. package/bundled/skills-windows/bug-planner/assets/bug-confirmation-template.md +0 -43
  226. package/bundled/skills-windows/bug-planner/references/critic-and-verification.md +0 -44
  227. package/bundled/skills-windows/bug-planner/references/error-recovery.md +0 -73
  228. package/bundled/skills-windows/bug-planner/references/input-formats.md +0 -53
  229. package/bundled/skills-windows/bug-planner/references/schema-validation.md +0 -25
  230. package/bundled/skills-windows/bug-planner/references/severity-rules.md +0 -16
  231. package/bundled/skills-windows/bug-planner/scripts/validate-bug-list.py +0 -322
  232. package/bundled/skills-windows/bugfix-pipeline-launcher/SKILL.md +0 -304
  233. package/bundled/skills-windows/bugfix-pipeline-launcher/references/configuration.md +0 -84
  234. package/bundled/skills-windows/feature-pipeline-launcher/SKILL.md +0 -381
  235. package/bundled/skills-windows/feature-pipeline-launcher/references/configuration.md +0 -67
  236. package/bundled/skills-windows/feature-pipeline-launcher/scripts/preflight-check.py +0 -462
  237. package/bundled/skills-windows/feature-planner/SKILL.md +0 -397
  238. package/bundled/skills-windows/feature-planner/assets/evaluation-guide.md +0 -64
  239. package/bundled/skills-windows/feature-planner/assets/planning-guide.md +0 -214
  240. package/bundled/skills-windows/feature-planner/references/browser-interaction.md +0 -59
  241. package/bundled/skills-windows/feature-planner/references/completeness-review.md +0 -57
  242. package/bundled/skills-windows/feature-planner/references/decomposition-patterns.md +0 -75
  243. package/bundled/skills-windows/feature-planner/references/error-recovery.md +0 -90
  244. package/bundled/skills-windows/feature-planner/references/incremental-feature-planning.md +0 -112
  245. package/bundled/skills-windows/feature-planner/references/new-project-planning.md +0 -85
  246. package/bundled/skills-windows/feature-planner/scripts/validate-and-generate.py +0 -1020
  247. package/bundled/skills-windows/feature-workflow/SKILL.md +0 -374
  248. package/bundled/skills-windows/feature-workflow/references/brainstorm-guide.md +0 -137
  249. package/bundled/skills-windows/prizm-kit/SKILL.md +0 -93
  250. package/bundled/skills-windows/prizmkit-code-review/SKILL.md +0 -161
  251. package/bundled/skills-windows/prizmkit-code-review/references/dev-agent-prompt.md +0 -30
  252. package/bundled/skills-windows/prizmkit-code-review/references/review-report-template.md +0 -31
  253. package/bundled/skills-windows/prizmkit-code-review/references/reviewer-agent-prompt.md +0 -66
  254. package/bundled/skills-windows/prizmkit-code-review/scripts/check_loop.py +0 -186
  255. package/bundled/skills-windows/prizmkit-committer/SKILL.md +0 -89
  256. package/bundled/skills-windows/prizmkit-deploy/SKILL.md +0 -444
  257. package/bundled/skills-windows/prizmkit-deploy/references/ci-cd-workflows.md +0 -115
  258. package/bundled/skills-windows/prizmkit-deploy/references/cloud-platform-deploy.md +0 -93
  259. package/bundled/skills-windows/prizmkit-deploy/references/data-safety-examples.md +0 -120
  260. package/bundled/skills-windows/prizmkit-deploy/references/database-setup.md +0 -46
  261. package/bundled/skills-windows/prizmkit-deploy/references/deploy-config-schema.md +0 -148
  262. package/bundled/skills-windows/prizmkit-deploy/references/deploy-history-schema.md +0 -62
  263. package/bundled/skills-windows/prizmkit-deploy/references/deployment-modes.md +0 -50
  264. package/bundled/skills-windows/prizmkit-deploy/references/direct-upload.md +0 -26
  265. package/bundled/skills-windows/prizmkit-deploy/references/dns-setup.md +0 -42
  266. package/bundled/skills-windows/prizmkit-deploy/references/docker-deploy.md +0 -31
  267. package/bundled/skills-windows/prizmkit-deploy/references/firewall-setup.md +0 -37
  268. package/bundled/skills-windows/prizmkit-deploy/references/live-validation-notes.md +0 -21
  269. package/bundled/skills-windows/prizmkit-deploy/references/nginx-blue-green.md +0 -59
  270. package/bundled/skills-windows/prizmkit-deploy/references/ssh-bootstrap-flow.md +0 -49
  271. package/bundled/skills-windows/prizmkit-deploy/references/ssh-execution-flow.md +0 -41
  272. package/bundled/skills-windows/prizmkit-deploy/references/ssh-takeover.md +0 -20
  273. package/bundled/skills-windows/prizmkit-deploy/references/ssl-setup.md +0 -56
  274. package/bundled/skills-windows/prizmkit-implement/SKILL.md +0 -71
  275. package/bundled/skills-windows/prizmkit-init/SKILL.md +0 -356
  276. package/bundled/skills-windows/prizmkit-init/assets/project-brief-template.md +0 -82
  277. package/bundled/skills-windows/prizmkit-init/references/config-schema.md +0 -70
  278. package/bundled/skills-windows/prizmkit-init/references/rules/layer-detection.md +0 -41
  279. package/bundled/skills-windows/prizmkit-init/references/tech-stack-catalog.md +0 -13
  280. package/bundled/skills-windows/prizmkit-init/references/update-supplement.md +0 -9
  281. package/bundled/skills-windows/prizmkit-plan/SKILL.md +0 -102
  282. package/bundled/skills-windows/prizmkit-plan/assets/plan-template.md +0 -115
  283. package/bundled/skills-windows/prizmkit-plan/assets/spec-template.md +0 -73
  284. package/bundled/skills-windows/prizmkit-plan/references/clarify-guide.md +0 -67
  285. package/bundled/skills-windows/prizmkit-plan/references/examples.md +0 -85
  286. package/bundled/skills-windows/prizmkit-plan/references/verification-checklist.md +0 -60
  287. package/bundled/skills-windows/prizmkit-prizm-docs/SKILL.md +0 -129
  288. package/bundled/skills-windows/prizmkit-prizm-docs/assets/prizm-docs-format.md +0 -613
  289. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-init.md +0 -45
  290. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-rebuild.md +0 -15
  291. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-status.md +0 -14
  292. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-update.md +0 -19
  293. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-validate.md +0 -17
  294. package/bundled/skills-windows/prizmkit-retrospective/SKILL.md +0 -87
  295. package/bundled/skills-windows/prizmkit-retrospective/references/knowledge-injection-steps.md +0 -50
  296. package/bundled/skills-windows/prizmkit-retrospective/references/structural-sync-steps.md +0 -43
  297. package/bundled/skills-windows/prizmkit-test/SKILL.md +0 -227
  298. package/bundled/skills-windows/prizmkit-test/references/boundary-coverage-protocol.md +0 -220
  299. package/bundled/skills-windows/prizmkit-test/references/examples.md +0 -143
  300. package/bundled/skills-windows/prizmkit-test/references/service-boundary-test-catalog.md +0 -225
  301. package/bundled/skills-windows/prizmkit-test/references/test-generation-steps.md +0 -109
  302. package/bundled/skills-windows/prizmkit-test/references/test-report-template.md +0 -111
  303. package/bundled/skills-windows/prizmkit-test/scripts/validate_boundary_report.py +0 -347
  304. package/bundled/skills-windows/recovery-workflow/SKILL.md +0 -355
  305. package/bundled/skills-windows/recovery-workflow/evals/evals.json +0 -46
  306. package/bundled/skills-windows/recovery-workflow/references/detection.md +0 -58
  307. package/bundled/skills-windows/recovery-workflow/scripts/detect-recovery-state.py +0 -544
  308. package/bundled/skills-windows/refactor-pipeline-launcher/SKILL.md +0 -346
  309. package/bundled/skills-windows/refactor-pipeline-launcher/references/configuration.md +0 -72
  310. package/bundled/skills-windows/refactor-planner/SKILL.md +0 -398
  311. package/bundled/skills-windows/refactor-planner/assets/planning-guide.md +0 -292
  312. package/bundled/skills-windows/refactor-planner/references/behavior-preservation.md +0 -301
  313. package/bundled/skills-windows/refactor-planner/references/fast-path.md +0 -59
  314. package/bundled/skills-windows/refactor-planner/references/planning-phases.md +0 -135
  315. package/bundled/skills-windows/refactor-planner/references/refactor-scoping-guide.md +0 -221
  316. package/bundled/skills-windows/refactor-planner/scripts/validate-and-generate-refactor.py +0 -858
  317. package/bundled/skills-windows/refactor-workflow/SKILL.md +0 -343
  318. package/bundled/skills-windows/refactor-workflow/references/brainstorm-guide.md +0 -116
  319. package/bundled/templates/hooks/diff-prizm-docs.sh +0 -158
  320. package/bundled/templates/hooks/prizm-pre-commit.sh +0 -108
  321. package/bundled/templates/hooks/validate-prizm-docs.sh +0 -139
@@ -1,1602 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- # ============================================================
5
- # dev-pipeline/run-feature.sh - Autonomous Dev Pipeline Runner
6
- #
7
- # Drives the prizm-dev-team multi-agent team through iterative
8
- # AI CLI sessions (CodeBuddy or Claude Code) to build a complete app
9
- # from a feature list.
10
- #
11
- # Usage:
12
- # ./run-feature.sh run [.prizmkit/plans/feature-list.json] [options] Run all features
13
- # ./run-feature.sh run <feature-id> [options] Run a single feature
14
- # ./run-feature.sh status [.prizmkit/plans/feature-list.json] Show pipeline status
15
- # ./run-feature.sh reset Clear all state
16
- #
17
- # Environment Variables:
18
- # MAX_RETRIES Max code retries per feature (default: 3)
19
- # MAX_INFRA_RETRIES Max infrastructure/provider retries per feature (default: 3)
20
- # AI_CLI AI CLI command name (override; also readable from .prizmkit/config.json)
21
- # CODEBUDDY_CLI Legacy alias for AI_CLI (deprecated, use AI_CLI instead)
22
- # PRIZMKIT_PLATFORM Platform hint for custom AI_CLI wrappers: codebuddy, claude, or codex
23
- # MODEL AI model to use (e.g. claude-opus-4.6, claude-sonnet-4.6, claude-haiku-4.5)
24
- # VERBOSE Set to 1 to enable --verbose on AI CLI (shows subagent output)
25
- # HEARTBEAT_INTERVAL Heartbeat log interval in seconds (default: 30)
26
- # STALE_KILL_THRESHOLD Auto-kill session after N seconds of no progress (default: 900)
27
- # HEARTBEAT_STALE_THRESHOLD Heartbeat stale threshold in seconds (default: 600)
28
- # MAX_LOG_SIZE Session log size threshold for compact warning (default: 2097152 = 2MB, set 0 to disable)
29
- # LOG_MONITOR_POLL_INTERVAL Log monitor poll interval in seconds (default: 30)
30
- # PIPELINE_MODE Override mode for all features: lite|standard|full (used by daemon)
31
- # DEV_BRANCH Custom dev branch name (default: auto-generated dev/{feature_id}-YYYYMMDDHHmm)
32
- # AUTO_PUSH Auto-push to remote after successful feature (default: 0). Set to 1 to enable.
33
- # STOP_ON_FAILURE Stop pipeline after a task exhausts all retries (default: 0). Set to 1 to stop.
34
- # ============================================================
35
-
36
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
37
-
38
- # Source shared common helpers (exports PIPELINE_DIR/PRIZMKIT_DIR/PROJECT_ROOT,
39
- # CLI/platform detection, logs, deps)
40
- source "$SCRIPT_DIR/lib/common.sh"
41
-
42
- STATE_DIR="${PRIZMKIT_DIR}/state/features"
43
- SCRIPTS_DIR="$SCRIPT_DIR/scripts"
44
-
45
- # Configuration (override via environment variables)
46
- MAX_RETRIES=${MAX_RETRIES:-3}
47
- MAX_INFRA_RETRIES=${MAX_INFRA_RETRIES:-3}
48
- HEARTBEAT_STALE_THRESHOLD=${HEARTBEAT_STALE_THRESHOLD:-600}
49
- HEARTBEAT_INTERVAL=${HEARTBEAT_INTERVAL:-30}
50
- STALE_KILL_THRESHOLD=${STALE_KILL_THRESHOLD:-900}
51
- VERBOSE=${VERBOSE:-0}
52
- MODEL=${MODEL:-""}
53
- PRIZMKIT_EFFORT=${PRIZMKIT_EFFORT:-""}
54
- DEV_BRANCH=${DEV_BRANCH:-""}
55
- AUTO_PUSH=${AUTO_PUSH:-0}
56
- STOP_ON_FAILURE=${STOP_ON_FAILURE:-0}
57
- ENABLE_DEPLOY=${ENABLE_DEPLOY:-0}
58
-
59
- # Source shared common helpers (CLI/platform detection + logs + deps)
60
- prizm_detect_cli_and_platform
61
-
62
- # Validate PRIZMKIT_EFFORT early (fail-fast before any sessions are spawned)
63
- prizm_validate_effort
64
-
65
- # Source shared heartbeat library
66
- source "$SCRIPT_DIR/lib/heartbeat.sh"
67
-
68
- # Source shared branch library
69
- source "$SCRIPT_DIR/lib/branch.sh"
70
-
71
- # Detect stream-json support
72
- detect_stream_json_support "$CLI_CMD"
73
-
74
- # Feature list path (set in main, used by cleanup trap)
75
- FEATURE_LIST=""
76
-
77
- # Branch tracking (for cleanup on interrupt)
78
- _ORIGINAL_BRANCH=""
79
- _DEV_BRANCH_NAME=""
80
- _SPAWN_FEATURE_SLUG=""
81
- _SPAWN_EXIT_CODE=0
82
-
83
- # ============================================================
84
- # Shared: Spawn an AI CLI session and wait for result
85
- # ============================================================
86
-
87
- # Spawns an AI CLI session with heartbeat + timeout, waits for completion,
88
- # and checks session status. Canonical status updates happen after the caller
89
- # returns to the original branch.
90
- #
91
- # Arguments:
92
- # $1 - feature_id
93
- # $2 - feature_list (absolute path)
94
- # $3 - session_id
95
- # $4 - bootstrap_prompt (path)
96
- # $5 - session_dir
97
- # $6 - max_retries (for status update)
98
- spawn_and_wait_session() {
99
- local feature_id="$1"
100
- local feature_list="$2"
101
- local session_id="$3"
102
- local bootstrap_prompt="$4"
103
- local session_dir="$5"
104
- local max_retries="$6"
105
- local feature_model="${7:-}"
106
- local base_branch="${8:-main}"
107
-
108
- local session_log="$session_dir/logs/session.log"
109
- local progress_json="$session_dir/logs/progress.json"
110
-
111
- _SPAWN_FEATURE_SLUG=""
112
- _SPAWN_EXIT_CODE=0
113
-
114
- local effective_model="${feature_model:-$MODEL}"
115
- local cbc_pid
116
- prizm_start_ai_session "$bootstrap_prompt" "$session_log" "$effective_model"
117
- cbc_pid="$PRIZM_AI_PID"
118
-
119
- # Start progress parser (no-op if stream-json not supported)
120
- start_progress_parser "$session_log" "$progress_json" "$SCRIPTS_DIR"
121
- local parser_pid="${_PARSER_PID:-}"
122
-
123
- # Heartbeat monitor (reads progress.json when available, falls back to tail)
124
- # Also monitors for stale sessions and auto-kills if no progress for STALE_KILL_THRESHOLD seconds
125
- start_heartbeat "$cbc_pid" "$session_log" "$progress_json" "$HEARTBEAT_INTERVAL" "$STALE_KILL_THRESHOLD"
126
- local heartbeat_pid="${_HEARTBEAT_PID:-}"
127
-
128
- # Wait for AI CLI to finish
129
- local exit_code=0
130
- if wait "$cbc_pid" 2>/dev/null; then
131
- exit_code=0
132
- else
133
- exit_code=$?
134
- fi
135
-
136
- # Clean up heartbeat and parser
137
- stop_heartbeat "$heartbeat_pid"
138
- stop_progress_parser "$parser_pid"
139
-
140
- # Recover session log from backup if truncated by subagent stdout redirection
141
- prizm_recover_session_log "$session_log"
142
-
143
- _SPAWN_EXIT_CODE="$exit_code"
144
-
145
- # Check for stale-kill marker (heartbeat killed the process due to no progress)
146
- local stale_kill_marker="$session_dir/logs/stale-kill.json"
147
- local was_stale_killed=false
148
- if [[ -f "$stale_kill_marker" ]]; then
149
- was_stale_killed=true
150
- log_warn "Session was stale-killed by heartbeat monitor (no progress for too long)"
151
- fi
152
-
153
- local was_infra_error=false
154
- if [[ $exit_code -ne 0 ]] && prizm_detect_infra_error "$session_log" "$progress_json"; then
155
- was_infra_error=true
156
- fi
157
-
158
- # Show final session summary
159
- if [[ -f "$session_log" ]]; then
160
- local final_size=$(wc -c < "$session_log" 2>/dev/null | tr -d ' ')
161
- local final_lines=$(wc -l < "$session_log" 2>/dev/null | tr -d ' ')
162
- log_info "Session log: $final_lines lines, $((final_size / 1024))KB"
163
- if [[ "$final_size" -lt 1024 && "$exit_code" -eq 0 ]]; then
164
- log_warn "Session log was truncated during execution (subagent stdout redirection may have severed it)"
165
- log_warn "Proceeding with exit-code-only outcome detection — child transcripts and git state are still valid"
166
- fi
167
- fi
168
- log_info "exit_code=$exit_code"
169
-
170
- # ── Determine session outcome from observable signals ──────────────
171
- # No dependency on session-status.json — uses exit code, git commits,
172
- # and working tree cleanliness as the single source of truth.
173
- local session_status
174
- local project_root
175
- project_root="$PROJECT_ROOT"
176
- local default_branch="$base_branch"
177
-
178
- local semantic_finalized=false
179
- local semantic_feature_slug=""
180
- local semantic_commit_sha=""
181
- local was_ai_runtime_error=false
182
- if prizm_detect_ai_runtime_error "$session_log" "$progress_json"; then
183
- was_ai_runtime_error=true
184
- fi
185
-
186
- if prizm_feature_semantically_complete "$feature_list" "$feature_id" "$project_root" "$default_branch" "$PRIZMKIT_DIR"; then
187
- semantic_finalized=true
188
- semantic_feature_slug="$PRIZM_SEMANTIC_FEATURE_SLUG"
189
- semantic_commit_sha="$PRIZM_SEMANTIC_COMMIT_SHA"
190
- if [[ $exit_code -ne 0 || "$was_stale_killed" == true || "$was_ai_runtime_error" == true ]]; then
191
- log_warn "Session ended with a failure signal after semantic completion; treating as finalized success"
192
- log_warn "Semantic completion commit: ${semantic_commit_sha:-unknown}"
193
- fi
194
- session_status="success"
195
- elif [[ "$was_ai_runtime_error" == true ]]; then
196
- log_warn "Session failed due to structured AI runtime/context error"
197
- log_warn "AI runtime errors are retried without consuming code retry budget"
198
- session_status="infra_error"
199
- elif [[ "$was_infra_error" == true ]]; then
200
- log_warn "Session failed due to AI CLI/provider infrastructure error"
201
- log_warn "Infrastructure errors are retried without consuming code retry budget"
202
- session_status="infra_error"
203
- elif [[ "$was_stale_killed" == true ]]; then
204
- log_warn "Session stale-killed (no progress for ${STALE_KILL_THRESHOLD}s)"
205
- log_warn "Heartbeat-killed sessions are treated as failed; dev branch is preserved for inspection"
206
- session_status="crashed"
207
- elif [[ $exit_code -ne 0 ]]; then
208
- log_warn "Session exited with code $exit_code"
209
- session_status="crashed"
210
- else
211
- # Exit code 0 — check if the session actually produced commits
212
- local has_commits=""
213
- if git -C "$project_root" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
214
- has_commits=$(git -C "$project_root" log "${default_branch}..HEAD" --oneline 2>/dev/null | head -1)
215
- fi
216
-
217
- if [[ -n "$has_commits" ]]; then
218
- session_status="success"
219
- else
220
- # No commits found — check if there are uncommitted changes (session
221
- # did work but didn't commit, e.g. context window exhausted)
222
- local uncommitted=""
223
- uncommitted=$(prizm_git_status_safe "$project_root" | head -1 || true)
224
- if [[ -n "$uncommitted" ]]; then
225
- log_warn "Session exited cleanly but produced no commits (uncommitted changes found) — auto-committing..."
226
- prizm_git_add_all_safe "$project_root" || true
227
- if git -C "$project_root" commit --no-verify -m "chore($feature_id): auto-commit session work" 2>/dev/null; then
228
- log_info "Auto-commit succeeded"
229
- session_status="success"
230
- else
231
- log_warn "Auto-commit failed — no changes to commit"
232
- session_status="crashed"
233
- fi
234
- else
235
- log_warn "Session exited cleanly but produced no commits and no changes"
236
- session_status="crashed"
237
- fi
238
- fi
239
- fi
240
-
241
- # ── Post-success validation ──────────────────────────────────────────
242
- if [[ "$session_status" == "success" ]]; then
243
- if git -C "$project_root" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
244
- local dirty_files=""
245
- dirty_files=$(prizm_git_status_safe "$project_root" || true)
246
- if [[ -n "$dirty_files" ]]; then
247
- log_info "Auto-committing remaining session artifacts..."
248
- prizm_git_add_all_safe "$project_root" || true
249
- git -C "$project_root" commit --no-verify --amend --no-edit 2>/dev/null \
250
- || git -C "$project_root" commit --no-verify -m "chore($feature_id): include remaining session artifacts" 2>/dev/null \
251
- || true
252
- fi
253
- fi
254
- fi
255
-
256
- log_info "Session result: $session_status"
257
-
258
- # Subagent detection
259
- prizm_detect_subagents "$session_log"
260
-
261
- # Write lightweight session summary for post-session inspection
262
- local feature_slug
263
- if [[ -n "$semantic_feature_slug" ]]; then
264
- feature_slug="$semantic_feature_slug"
265
- else
266
- feature_slug=$(python3 -c "
267
- import json, re, sys
268
- flist, fid = sys.argv[1], sys.argv[2]
269
- with open(flist) as f:
270
- data = json.load(f)
271
- for feat in data.get('features', []):
272
- if feat.get('id') == fid:
273
- fnum = feat['id'].replace('F-', '').replace('f-', '').zfill(3)
274
- title = feat.get('title', '').lower()
275
- title = re.sub(r'[^a-z0-9\s-]', '', title)
276
- title = re.sub(r'[\s]+', '-', title.strip())
277
- title = re.sub(r'-+', '-', title).strip('-')
278
- print(f'{fnum}-{title}')
279
- sys.exit(0)
280
- sys.exit(1)
281
- " "$feature_list" "$feature_id" 2>/dev/null) || {
282
- log_warn "Could not resolve feature slug for $feature_id — session summary and artifact validation will be skipped"
283
- feature_slug=""
284
- }
285
- fi
286
- _SPAWN_FEATURE_SLUG="$feature_slug"
287
-
288
- # Validate key artifacts exist after successful session
289
- if [[ "$session_status" == "success" && -n "$feature_slug" ]]; then
290
- local context_snapshot="$PRIZMKIT_DIR/specs/${feature_slug}/context-snapshot.md"
291
- local plan_file="$PRIZMKIT_DIR/specs/${feature_slug}/plan.md"
292
-
293
- if [[ ! -f "$context_snapshot" ]]; then
294
- log_warn "ARTIFACT_MISSING: context-snapshot.md not found at $context_snapshot"
295
- fi
296
- if [[ ! -f "$plan_file" ]]; then
297
- log_warn "ARTIFACT_MISSING: plan.md not found at $plan_file"
298
- fi
299
-
300
- # Validate checkpoint completeness
301
- local checkpoint_file="$PRIZMKIT_DIR/specs/${feature_slug}/workflow-checkpoint.json"
302
- if [[ -f "$checkpoint_file" ]]; then
303
- local checkpoint_result
304
- checkpoint_result=$(python3 -c "
305
- import json, sys
306
- try:
307
- with open(sys.argv[1]) as f:
308
- data = json.load(f)
309
- except json.JSONDecodeError as e:
310
- print('CORRUPTED: {}'.format(e))
311
- sys.exit(2)
312
- incomplete = [s for s in data['steps'] if s['status'] not in ('completed', 'skipped')]
313
- if incomplete:
314
- for s in incomplete:
315
- print('INCOMPLETE: {} {} = {}'.format(s['id'], s['skill'], s['status']))
316
- sys.exit(1)
317
- print('ALL_COMPLETE')
318
- sys.exit(0)
319
- " "$checkpoint_file" 2>&1) || checkpoint_result="CHECK_FAILED"
320
- local check_exit=$?
321
- if [[ "$checkpoint_result" == "CHECK_FAILED" ]]; then
322
- check_exit=2
323
- elif [[ "$checkpoint_result" == *"INCOMPLETE"* ]]; then
324
- check_exit=1
325
- else
326
- check_exit=0
327
- fi
328
- if [[ $check_exit -eq 2 ]]; then
329
- log_warn "CHECKPOINT_CORRUPTED: workflow-checkpoint.json is not valid JSON"
330
- elif [[ $check_exit -eq 1 ]]; then
331
- log_warn "CHECKPOINT_INCOMPLETE: Not all workflow steps completed:"
332
- echo "$checkpoint_result" | while read -r line; do log_warn " $line"; done
333
- else
334
- log_info "CHECKPOINT: All workflow steps completed"
335
- fi
336
- else
337
- log_info "CHECKPOINT: No workflow-checkpoint.json found (checkpoint system not active)"
338
- fi
339
- fi
340
-
341
- # Propagate completion notes for dependency context (only on success)
342
- if [[ "$session_status" == "success" && -n "$feature_slug" ]]; then
343
- local summary_path="$PRIZMKIT_DIR/specs/$feature_slug/completion-summary.json"
344
- if [[ -f "$summary_path" ]]; then
345
- python3 "$SCRIPTS_DIR/patch-completion-notes.py" \
346
- --feature-list "$feature_list" \
347
- --feature-id "$feature_id" \
348
- --summary "$summary_path" >/dev/null 2>&1 && {
349
- log_info "Propagated completion notes for $feature_id to feature-list.json"
350
- } || {
351
- log_warn "Failed to propagate completion notes for $feature_id"
352
- }
353
- else
354
- log_info "No completion-summary.json for $feature_id — dependency context will be limited"
355
- fi
356
- fi
357
-
358
- # Return status via global variable (avoids $() swallowing stdout)
359
- _SPAWN_RESULT="$session_status"
360
- }
361
-
362
- finalize_feature_status_after_branch_return() {
363
- local feature_id="$1"
364
- local feature_list="$2"
365
- local session_id="$3"
366
- local session_status="$4"
367
- local max_retries="$5"
368
- local max_infra_retries="$6"
369
- local session_dir="$7"
370
- local base_branch="${8:-main}"
371
-
372
- local feature_slug="${_SPAWN_FEATURE_SLUG:-}"
373
- local progress_json="$session_dir/logs/progress.json"
374
- local stale_kill_marker="$session_dir/logs/stale-kill.json"
375
- local exit_code="${_SPAWN_EXIT_CODE:-0}"
376
-
377
- # Check if session produced a failure-log for future retries; synthesize one
378
- # after branch return so canonical diagnostics live on the original branch.
379
- if [[ "$session_status" != "success" && -n "$feature_slug" ]]; then
380
- local failure_log="$PRIZMKIT_DIR/specs/${feature_slug}/failure-log.md"
381
- local checkpoint_file_for_failure="$PRIZMKIT_DIR/specs/${feature_slug}/workflow-checkpoint.json"
382
- if [[ -f "$failure_log" ]]; then
383
- log_info "FAILURE_LOG: Session wrote failure-log.md — will be available to next retry"
384
- else
385
- prizm_synthesize_failure_log \
386
- "$failure_log" "$feature_id" "$session_id" "$session_status" "$exit_code" \
387
- "$stale_kill_marker" "$progress_json" "$checkpoint_file_for_failure" "$PROJECT_ROOT" "$base_branch"
388
- if [[ -f "$failure_log" ]]; then
389
- log_info "FAILURE_LOG: Runtime synthesized failure-log.md — will be available to next retry"
390
- else
391
- log_info "FAILURE_LOG: No failure-log.md written by session"
392
- fi
393
- fi
394
- fi
395
-
396
- # Update feature status on the original branch. The caller commits the
397
- # resulting feature-list diff immediately after this helper returns.
398
- local update_output
399
- update_output=$(python3 "$SCRIPTS_DIR/update-feature-status.py" \
400
- --feature-list "$feature_list" \
401
- --state-dir "$STATE_DIR" \
402
- --feature-id "$feature_id" \
403
- --session-status "$session_status" \
404
- --session-id "$session_id" \
405
- --max-retries "$max_retries" \
406
- --max-infra-retries "$max_infra_retries" \
407
- --action update) || {
408
- log_error "Failed to update feature status: $update_output"
409
- log_error ".prizmkit/plans/feature-list.json may be out of sync. Manual intervention needed."
410
- }
411
-
412
- _SPAWN_ITEM_STATUS="$(printf '%s' "$update_output" | prizm_extract_update_new_status)"
413
- }
414
-
415
- # ============================================================
416
- # Graceful Shutdown
417
- # ============================================================
418
-
419
- cleanup() {
420
- echo ""
421
- log_warn "Received interrupt signal. Saving state..."
422
-
423
- # Kill all child processes (claude-internal, heartbeat, progress parser, etc.)
424
- kill 0 2>/dev/null || true
425
-
426
- # Log current branch info for recovery
427
- if [[ -n "$_DEV_BRANCH_NAME" ]]; then
428
- log_info "Development was on branch: $_DEV_BRANCH_NAME"
429
- log_info "Original branch was: $_ORIGINAL_BRANCH"
430
- fi
431
-
432
- # Update status of currently in-progress feature to interrupted
433
- if [[ -n "$FEATURE_LIST" && -f "$FEATURE_LIST" ]]; then
434
- # Find any in-progress feature and mark it as interrupted
435
- local _interrupted_id
436
- _interrupted_id=$(python3 -c "
437
- import json, sys
438
- with open(sys.argv[1]) as f:
439
- data = json.load(f)
440
- for feat in data.get('features', []):
441
- if feat.get('status') == 'in_progress':
442
- print(feat['id'])
443
- break
444
- " "$FEATURE_LIST" 2>/dev/null || echo "")
445
-
446
- if [[ -n "$_interrupted_id" ]]; then
447
- python3 "$SCRIPTS_DIR/update-feature-status.py" \
448
- --feature-list "$FEATURE_LIST" \
449
- --state-dir "$STATE_DIR" \
450
- --feature-id "$_interrupted_id" \
451
- --session-status "failed" \
452
- --max-retries "$MAX_RETRIES" \
453
- --max-infra-retries "$MAX_INFRA_RETRIES" \
454
- --action update 2>/dev/null || true
455
- log_info "Feature $_interrupted_id marked as failed due to interrupt"
456
- fi
457
-
458
- # Pause the pipeline (mark remaining pending items)
459
- python3 "$SCRIPTS_DIR/update-feature-status.py" \
460
- --feature-list "$FEATURE_LIST" \
461
- --state-dir "$STATE_DIR" \
462
- --action pause 2>/dev/null || true
463
- fi
464
-
465
- # GUARANTEED: always return to original branch (save WIP on dev branch first)
466
- branch_ensure_return "$PROJECT_ROOT" "$_ORIGINAL_BRANCH" "$_DEV_BRANCH_NAME"
467
-
468
- log_info "Pipeline paused. Run './run-feature.sh run' to resume."
469
- exit 130
470
- }
471
- trap cleanup SIGINT SIGTERM
472
-
473
- # ============================================================
474
- # Dependency Check
475
- # ============================================================
476
-
477
- check_dependencies() {
478
- prizm_check_common_dependencies "$CLI_CMD"
479
- local _project_root
480
- _project_root="$PROJECT_ROOT"
481
- prizm_ensure_git_repo "$_project_root"
482
- }
483
-
484
- # ============================================================
485
- # run-one: Run a single feature with full control
486
- # ============================================================
487
-
488
- run_one() {
489
- local feature_id=""
490
- local feature_list=""
491
- local dry_run=false
492
- local resume_phase=""
493
- local mode_override=""
494
- local critic_override=""
495
- local do_clean=false
496
- local no_reset=false
497
-
498
- # Parse arguments
499
- while [[ $# -gt 0 ]]; do
500
- case "$1" in
501
- --dry-run)
502
- dry_run=true
503
- shift
504
- ;;
505
- --resume-phase)
506
- shift
507
- if [[ $# -eq 0 ]]; then
508
- log_error "--resume-phase requires a value"
509
- exit 1
510
- fi
511
- resume_phase="$1"
512
- shift
513
- ;;
514
- --mode)
515
- shift
516
- if [[ $# -eq 0 ]]; then
517
- log_error "--mode requires a value (lite|standard|full)"
518
- exit 1
519
- fi
520
- case "$1" in
521
- lite|standard|full)
522
- mode_override="$1"
523
- ;;
524
- *)
525
- log_error "Invalid mode: $1 (must be lite, standard, or full)"
526
- exit 1
527
- ;;
528
- esac
529
- shift
530
- ;;
531
- --clean)
532
- do_clean=true
533
- shift
534
- ;;
535
- --no-reset)
536
- no_reset=true
537
- shift
538
- ;;
539
- --critic)
540
- critic_override="true"
541
- shift
542
- ;;
543
- --no-critic)
544
- critic_override="false"
545
- shift
546
- ;;
547
- --max-infra-retries)
548
- shift
549
- if [[ $# -eq 0 ]]; then
550
- log_error "--max-infra-retries requires a value"
551
- exit 1
552
- fi
553
- prizm_require_positive_int "--max-infra-retries" "$1"
554
- MAX_INFRA_RETRIES="$1"
555
- shift
556
- ;;
557
- F-*|f-*)
558
- feature_id="$1"
559
- shift
560
- ;;
561
- *)
562
- feature_list="$1"
563
- shift
564
- ;;
565
- esac
566
- done
567
-
568
- # Validate required args
569
- if [[ -z "$feature_id" ]]; then
570
- log_error "Feature ID is required (e.g. F-007)"
571
- echo ""
572
- show_help
573
- exit 1
574
- fi
575
-
576
- # Default feature list
577
- if [[ -z "$feature_list" ]]; then
578
- feature_list="$PRIZMKIT_DIR/plans/feature-list.json"
579
- fi
580
-
581
- # Resolve to absolute path
582
- if [[ ! "$feature_list" = /* ]]; then
583
- feature_list="$(pwd)/$feature_list"
584
- fi
585
-
586
- FEATURE_LIST="$feature_list"
587
-
588
- # Default resume phase
589
- if [[ -z "$resume_phase" ]]; then
590
- resume_phase="null"
591
- fi
592
-
593
- # Validation
594
- if [[ ! -f "$feature_list" ]]; then
595
- log_error "Feature list not found: $feature_list"
596
- exit 1
597
- fi
598
-
599
- check_dependencies
600
-
601
- # Initialize pipeline state if needed (same logic as run_all)
602
- if [[ ! -f "$STATE_DIR/pipeline.json" ]]; then
603
- log_info "Initializing pipeline state for single-feature run..."
604
- local init_result init_stderr init_tmpstderr
605
- init_tmpstderr=$(mktemp)
606
- if ! init_result=$(python3 "$SCRIPTS_DIR/init-pipeline.py" \
607
- --feature-list "$feature_list" \
608
- --state-dir "$STATE_DIR" 2>"$init_tmpstderr"); then
609
- init_stderr=$(cat "$init_tmpstderr" 2>/dev/null || true)
610
- rm -f "$init_tmpstderr"
611
- if [[ -n "$init_stderr" ]]; then
612
- log_warn "$init_stderr"
613
- fi
614
- log_error "Pipeline initialization failed (script error)"
615
- exit 1
616
- fi
617
- init_stderr=$(cat "$init_tmpstderr" 2>/dev/null || true)
618
- rm -f "$init_tmpstderr"
619
-
620
- # Show any stderr warnings without corrupting JSON
621
- if [[ -n "$init_stderr" ]]; then
622
- log_warn "$init_stderr"
623
- fi
624
-
625
- local init_valid
626
- init_valid=$(echo "$init_result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('valid', False))" 2>/dev/null || echo "False")
627
-
628
- if [[ "$init_valid" != "True" ]]; then
629
- log_error "Pipeline initialization failed:"
630
- echo "$init_result"
631
- exit 1
632
- fi
633
-
634
- local features_count
635
- features_count=$(echo "$init_result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('features_count', 0))" 2>/dev/null || echo "0")
636
- log_success "Pipeline initialized with $features_count features"
637
- fi
638
-
639
- # Verify feature exists
640
- local feature_title
641
- feature_title=$(python3 -c "
642
- import json, sys
643
- feature_list_path, fid = sys.argv[1], sys.argv[2]
644
- with open(feature_list_path) as f:
645
- data = json.load(f)
646
- for feat in data.get('features', []):
647
- if feat.get('id') == fid:
648
- print(feat.get('title', ''))
649
- sys.exit(0)
650
- sys.exit(1)
651
- " "$feature_list" "$feature_id" 2>/dev/null) || {
652
- log_error "Feature $feature_id not found in $feature_list"
653
- exit 1
654
- }
655
-
656
- # Optional Clean
657
- if [[ "$do_clean" == true ]]; then
658
- if [[ "$dry_run" == true ]]; then
659
- log_warn "Dry-run mode: --clean ignored (no artifacts will be deleted)"
660
- else
661
- log_info "Cleaning artifacts for $feature_id..."
662
-
663
- local feature_slug
664
- feature_slug=$(python3 -c "
665
- import json, re, sys
666
- feature_list_path, fid = sys.argv[1], sys.argv[2]
667
- with open(feature_list_path) as f:
668
- data = json.load(f)
669
- for feat in data.get('features', []):
670
- if feat.get('id') == fid:
671
- fnum = feat['id'].replace('F-', '').replace('f-', '').zfill(3)
672
- title = feat.get('title', '').lower()
673
- title = re.sub(r'[^a-z0-9\s-]', '', title)
674
- title = re.sub(r'[\s]+', '-', title.strip())
675
- title = re.sub(r'-+', '-', title).strip('-')
676
- print(f'{fnum}-{title}')
677
- sys.exit(0)
678
- sys.exit(1)
679
- " "$feature_list" "$feature_id" 2>/dev/null) || {
680
- log_warn "Could not determine feature slug for cleanup"
681
- feature_slug=""
682
- }
683
-
684
- local project_root
685
- project_root="$PROJECT_ROOT"
686
-
687
- if [[ -n "$feature_slug" ]]; then
688
- local specs_dir="$PRIZMKIT_DIR/specs/$feature_slug"
689
- if [[ -d "$specs_dir" ]]; then
690
- rm -rf "$specs_dir"
691
- log_info "Removed $specs_dir"
692
- fi
693
- fi
694
-
695
- local dev_team_dir="$project_root/.dev-team"
696
- if [[ -d "$dev_team_dir" ]]; then
697
- rm -rf "$dev_team_dir"
698
- log_info "Removed $dev_team_dir"
699
- fi
700
-
701
- local feature_state_dir="$STATE_DIR/$feature_id"
702
- if [[ -d "$feature_state_dir" ]]; then
703
- rm -rf "$feature_state_dir"
704
- log_info "Removed $feature_state_dir"
705
- fi
706
- fi
707
- fi
708
-
709
- # Reset Status
710
- if [[ "$no_reset" == false && "$dry_run" == false ]]; then
711
- log_info "Resetting $feature_id status..."
712
- python3 "$SCRIPTS_DIR/update-feature-status.py" \
713
- --feature-list "$feature_list" \
714
- --state-dir "$STATE_DIR" \
715
- --feature-id "$feature_id" \
716
- --action reset >/dev/null 2>&1 || {
717
- log_warn "Failed to reset feature status (may already be pending)"
718
- }
719
- elif [[ "$dry_run" == true && "$no_reset" == false ]]; then
720
- log_info "Dry-run mode: skipping status reset"
721
- fi
722
-
723
- # Generate Bootstrap Prompt
724
- local run_id session_id session_dir bootstrap_prompt
725
- run_id=$(jq -r '.run_id' "$STATE_DIR/pipeline.json")
726
- session_id="${feature_id}-$(date +%Y%m%d%H%M%S)"
727
- session_dir="$STATE_DIR/$feature_id/sessions/$session_id"
728
- mkdir -p "$session_dir/logs"
729
-
730
- bootstrap_prompt="$session_dir/bootstrap-prompt.md"
731
-
732
- # Read retry count from status.json
733
- local retry_count
734
- retry_count=$(python3 -c "
735
- import json, os
736
- status_path = os.path.join('$STATE_DIR', '$feature_id', 'status.json')
737
- if os.path.isfile(status_path):
738
- with open(status_path) as f:
739
- d = json.load(f)
740
- print(d.get('retry_count', 0))
741
- else:
742
- print(0)
743
- " 2>/dev/null || echo "0")
744
-
745
- local prompt_args=(
746
- --feature-list "$feature_list"
747
- --feature-id "$feature_id"
748
- --session-id "$session_id"
749
- --run-id "$run_id"
750
- --retry-count "$retry_count"
751
- --resume-phase "$resume_phase"
752
- --state-dir "$STATE_DIR"
753
- --output "$bootstrap_prompt"
754
- )
755
-
756
- if [[ -n "$mode_override" ]]; then
757
- prompt_args+=(--mode "$mode_override")
758
- fi
759
-
760
- if [[ -n "${critic_override:-}" ]]; then
761
- prompt_args+=(--critic "$critic_override")
762
- elif [[ "${ENABLE_CRITIC:-}" == "true" || "${ENABLE_CRITIC:-}" == "1" ]]; then
763
- prompt_args+=(--critic "true")
764
- elif [[ "${ENABLE_CRITIC:-}" == "false" || "${ENABLE_CRITIC:-}" == "0" ]]; then
765
- prompt_args+=(--critic "false")
766
- fi
767
-
768
- log_info "Generating bootstrap prompt..."
769
- local gen_output
770
- gen_output=$(python3 "$SCRIPTS_DIR/generate-bootstrap-prompt.py" "${prompt_args[@]}" 2>/dev/null) || {
771
- log_error "Failed to generate bootstrap prompt for $feature_id"
772
- return 1
773
- }
774
- local feature_model pipeline_mode agent_count critic_enabled
775
- feature_model=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('model',''))" 2>/dev/null || echo "")
776
- pipeline_mode=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('pipeline_mode','lite'))" 2>/dev/null || echo "lite")
777
- agent_count=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('agent_count',1))" 2>/dev/null || echo "1")
778
- critic_enabled=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('critic_enabled','false'))" 2>/dev/null || echo "false")
779
-
780
- # Dry-Run: Print info and exit
781
- if [[ "$dry_run" == true ]]; then
782
- echo ""
783
- echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
784
- echo -e "${BOLD} Dry Run: $feature_id — $feature_title${NC}"
785
- echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
786
- echo ""
787
- log_info "Session ID: $session_id"
788
- log_info "Resume Phase: $resume_phase"
789
- if [[ -n "$mode_override" ]]; then
790
- log_info "Mode Override: $mode_override"
791
- else
792
- log_info "Mode: auto-detect (from complexity)"
793
- fi
794
- log_info "Pipeline mode: $pipeline_mode"
795
- log_info "Agents: $agent_count (critic: $([ "$critic_enabled" = "true" ] && echo "enabled" || echo "disabled"))"
796
- if [[ -n "$feature_model" ]]; then
797
- log_info "Feature Model: $feature_model"
798
- elif [[ -n "${MODEL:-}" ]]; then
799
- log_info "Model (env): $MODEL"
800
- else
801
- log_info "Model: (CLI default)"
802
- fi
803
- echo ""
804
- log_info "Bootstrap prompt written to:"
805
- echo " $bootstrap_prompt"
806
- echo ""
807
-
808
- local prompt_lines
809
- prompt_lines=$(wc -l < "$bootstrap_prompt" | tr -d ' ')
810
- log_info "Prompt: $prompt_lines lines"
811
- echo ""
812
- echo -e "${BOLD}--- Session Context (from prompt) ---${NC}"
813
- sed -n '/^## Session Context/,/^##[^#]/p' "$bootstrap_prompt" | head -20
814
- echo -e "${BOLD}--- end ---${NC}"
815
- echo ""
816
-
817
- log_success "Dry run complete. Inspect full prompt with:"
818
- echo " cat $bootstrap_prompt"
819
- return 0
820
- fi
821
-
822
- # Log bootstrap prompt in test mode
823
- prizm_log_bootstrap_prompt "$bootstrap_prompt" "$feature_id"
824
-
825
- # Spawn AI CLI Session
826
- echo ""
827
- echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
828
- echo -e "${BOLD} Run: $feature_id — $feature_title${NC}"
829
- echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
830
- log_info "AI CLI: $CLI_CMD (platform: $PLATFORM)"
831
- log_info "Session ID: $session_id"
832
- log_info "Resume Phase: $resume_phase"
833
- local effective_model="${feature_model:-$MODEL}"
834
- if [[ -n "$effective_model" ]]; then
835
- log_info "Model: $effective_model"
836
- else
837
- log_info "Model: (CLI default)"
838
- fi
839
- if [[ -n "$mode_override" ]]; then
840
- log_info "Mode Override: $mode_override"
841
- fi
842
- local _run_one_mode_desc
843
- case "$pipeline_mode" in
844
- lite) _run_one_mode_desc="Tier 1 — Single Agent" ;;
845
- standard) _run_one_mode_desc="Tier 2 — Orchestrator + Dev + Reviewer" ;;
846
- full) _run_one_mode_desc="Tier 3 — Full Team (+ Multi-Critic)" ;;
847
- *) _run_one_mode_desc="$pipeline_mode" ;;
848
- esac
849
- log_info "Pipeline mode: ${BOLD}$pipeline_mode${NC} ($_run_one_mode_desc)"
850
- log_info "Agents: $agent_count (critic: $([ "$critic_enabled" = "true" ] && echo "enabled" || echo "disabled"))"
851
- log_info "Prompt: $bootstrap_prompt"
852
- log_info "Log: $session_dir/logs/session.log"
853
- echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
854
- echo ""
855
-
856
- # Override cleanup trap for single-feature mode (use distinct name to avoid overwriting global cleanup)
857
- cleanup_single_feature() {
858
- echo ""
859
- log_warn "Interrupted. Killing session..."
860
- # Kill all child processes
861
- kill 0 2>/dev/null || true
862
- # Log current branch info
863
- if [[ -n "$_DEV_BRANCH_NAME" ]]; then
864
- log_info "Development was on branch: $_DEV_BRANCH_NAME"
865
- fi
866
- log_info "Session log: $session_dir/logs/session.log"
867
-
868
- # Update feature status to failed on interrupt
869
- if [[ -n "$feature_list" && -f "$feature_list" ]]; then
870
- python3 "$SCRIPTS_DIR/update-feature-status.py" \
871
- --feature-list "$feature_list" \
872
- --state-dir "$STATE_DIR" \
873
- --feature-id "$feature_id" \
874
- --session-status "failed" \
875
- --max-retries "$MAX_RETRIES" \
876
- --max-infra-retries "$MAX_INFRA_RETRIES" \
877
- --action update 2>/dev/null || true
878
- log_info "Feature $feature_id marked as failed due to interrupt"
879
- fi
880
-
881
- # GUARANTEED: always return to original branch (save WIP on dev branch first)
882
- branch_ensure_return "$PROJECT_ROOT" "$_ORIGINAL_BRANCH" "$_DEV_BRANCH_NAME"
883
- exit 130
884
- }
885
- trap cleanup_single_feature SIGINT SIGTERM
886
-
887
- _SPAWN_RESULT=""
888
- _SPAWN_ITEM_STATUS=""
889
-
890
- # Branch lifecycle: create and checkout feature branch
891
- local _proj_root
892
- _proj_root="$PROJECT_ROOT"
893
- local _source_branch
894
- _source_branch=$(git -C "$_proj_root" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "main")
895
- _ORIGINAL_BRANCH="$_source_branch"
896
-
897
- # Mark feature as in-progress (update JSON for runtime monitoring, no commit)
898
- # The status change will be committed together with the final status update
899
- # after the session completes, avoiding an extra noise commit per feature.
900
- python3 "$SCRIPTS_DIR/update-feature-status.py" \
901
- --feature-list "$feature_list" \
902
- --state-dir "$STATE_DIR" \
903
- --feature-id "$feature_id" \
904
- --action start >/dev/null 2>&1 || true
905
-
906
- local _branch_name="${DEV_BRANCH:-dev/${feature_id}-$(date +%Y%m%d%H%M)}"
907
- if branch_create "$_proj_root" "$_branch_name" "$_source_branch"; then
908
- _DEV_BRANCH_NAME="$_branch_name"
909
- else
910
- log_error "Failed to create branch: $_branch_name from $_source_branch — aborting to avoid running on $_source_branch"
911
- return 1
912
- fi
913
-
914
- spawn_and_wait_session \
915
- "$feature_id" "$feature_list" "$session_id" \
916
- "$bootstrap_prompt" "$session_dir" "$MAX_RETRIES" "$feature_model" "$_ORIGINAL_BRANCH"
917
- local session_status="$_SPAWN_RESULT"
918
-
919
- # Merge dev branch back to original on success
920
- if [[ "$session_status" == "success" && -n "$_DEV_BRANCH_NAME" ]]; then
921
- if branch_merge "$_proj_root" "$_DEV_BRANCH_NAME" "$_ORIGINAL_BRANCH" "$AUTO_PUSH"; then
922
- _DEV_BRANCH_NAME=""
923
- else
924
- log_warn "Auto-merge failed — dev branch preserved: $_DEV_BRANCH_NAME"
925
- log_warn "Merge manually: git checkout $_ORIGINAL_BRANCH && git rebase $_DEV_BRANCH_NAME"
926
- session_status="merge_conflict"
927
- fi
928
- elif [[ -n "$_DEV_BRANCH_NAME" ]]; then
929
- # Session failed — preserve dev branch for inspection
930
- log_warn "Session failed — dev branch preserved for inspection: $_DEV_BRANCH_NAME"
931
- _DEV_BRANCH_NAME=""
932
- fi
933
-
934
- # GUARANTEED: always return to original branch regardless of success/failure/merge outcome
935
- branch_ensure_return "$_proj_root" "$_ORIGINAL_BRANCH"
936
-
937
- finalize_feature_status_after_branch_return \
938
- "$feature_id" "$feature_list" "$session_id" "$session_status" "$MAX_RETRIES" "$MAX_INFRA_RETRIES" "$session_dir" "$_ORIGINAL_BRANCH"
939
-
940
- # Commit feature status update on the original branch (after guaranteed return)
941
- if ! git -C "$_proj_root" diff --quiet "$feature_list" 2>/dev/null; then
942
- prizm_git_commit_paths "$_proj_root" "chore($feature_id): update feature status" "$feature_list"
943
- fi
944
-
945
- echo ""
946
- if [[ "$session_status" == "success" ]]; then
947
- log_success "════════════════════════════════════════════════════"
948
- log_success " $feature_id completed successfully!"
949
- log_success "════════════════════════════════════════════════════"
950
- else
951
- log_error "════════════════════════════════════════════════════"
952
- log_error " $feature_id result: $session_status"
953
- log_error " Review log: $session_dir/logs/session.log"
954
- log_error "════════════════════════════════════════════════════"
955
- fi
956
- }
957
-
958
- # ============================================================
959
- # Main Loop: Run all features
960
- # ============================================================
961
-
962
- main() {
963
- local feature_list="${1:-$PRIZMKIT_DIR/plans/feature-list.json}"
964
- local features_filter="${2:-}"
965
-
966
- # Resolve to absolute path
967
- if [[ ! "$feature_list" = /* ]]; then
968
- feature_list="$(pwd)/$feature_list"
969
- fi
970
-
971
- FEATURE_LIST="$feature_list"
972
-
973
- # Validate feature list exists
974
- if [[ ! -f "$feature_list" ]]; then
975
- log_error "Feature list not found: $feature_list"
976
- log_info "Create a feature list first using the feature-planner skill,"
977
- log_info "or provide a path: ./run-feature.sh run <path-to-.prizmkit/plans/feature-list.json>"
978
- exit 1
979
- fi
980
-
981
- # Validate .prizmkit/plans/feature-list.json is under project root
982
- local fl_dir
983
- fl_dir="$(cd "$(dirname "$feature_list")" && pwd)"
984
- if [[ "$fl_dir" != "$PRIZMKIT_DIR/plans" && "$fl_dir" != "$PROJECT_ROOT" ]]; then
985
- log_warn "feature-list.json is not under project root ($PROJECT_ROOT), found at $fl_dir"
986
- log_warn "Pipeline expects feature-list.json at ${PRIZMKIT_DIR}/plans/feature-list.json. Proceeding but results may be unstable."
987
- fi
988
-
989
- check_dependencies
990
-
991
- # Initialize pipeline state if needed
992
- if [[ ! -f "$STATE_DIR/pipeline.json" ]]; then
993
- log_info "Initializing pipeline state..."
994
- local init_result init_stderr init_tmpstderr
995
- init_tmpstderr=$(mktemp)
996
- if ! init_result=$(python3 "$SCRIPTS_DIR/init-pipeline.py" \
997
- --feature-list "$feature_list" \
998
- --state-dir "$STATE_DIR" 2>"$init_tmpstderr"); then
999
- init_stderr=$(cat "$init_tmpstderr" 2>/dev/null || true)
1000
- rm -f "$init_tmpstderr"
1001
- if [[ -n "$init_stderr" ]]; then
1002
- log_warn "$init_stderr"
1003
- fi
1004
- log_error "Pipeline initialization failed (script error)"
1005
- exit 1
1006
- fi
1007
- init_stderr=$(cat "$init_tmpstderr" 2>/dev/null || true)
1008
- rm -f "$init_tmpstderr"
1009
-
1010
- # Show any stderr warnings (e.g. project root detection) without corrupting JSON
1011
- if [[ -n "$init_stderr" ]]; then
1012
- log_warn "$init_stderr"
1013
- fi
1014
-
1015
- local init_valid
1016
- init_valid=$(echo "$init_result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('valid', False))" 2>/dev/null || echo "False")
1017
-
1018
- if [[ "$init_valid" != "True" ]]; then
1019
- log_error "Pipeline initialization failed:"
1020
- echo "$init_result"
1021
- exit 1
1022
- fi
1023
-
1024
- local features_count
1025
- features_count=$(echo "$init_result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('features_count', 0))" 2>/dev/null || echo "0")
1026
- log_success "Pipeline initialized with $features_count features"
1027
- else
1028
- log_info "Resuming existing pipeline..."
1029
- fi
1030
-
1031
- # Print header
1032
- echo ""
1033
- echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
1034
- echo -e "${BOLD} Dev-Pipeline Runner Started${NC}"
1035
- echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
1036
- log_info "Feature list: $feature_list"
1037
- if [[ -n "$features_filter" ]]; then
1038
- log_info "Features filter: $features_filter"
1039
- fi
1040
- log_info "Max code retries per feature: $MAX_RETRIES"
1041
- log_info "Max infrastructure retries per feature: $MAX_INFRA_RETRIES"
1042
- log_info "AI CLI: $CLI_CMD (platform: $PLATFORM)"
1043
- if [[ -n "${MODEL:-}" ]]; then
1044
- log_info "Default Model: $MODEL"
1045
- fi
1046
- if [[ "$STOP_ON_FAILURE" == "1" ]]; then
1047
- log_info "Stop on failure: enabled"
1048
- fi
1049
- echo -e "${BOLD}════════════════════════════════════════════════════${NC}"
1050
- echo ""
1051
-
1052
- # Branch lifecycle: each feature gets its own dev branch (created per-iteration below)
1053
- local _proj_root
1054
- _proj_root="$PROJECT_ROOT"
1055
- local _source_branch
1056
- _source_branch=$(git -C "$_proj_root" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "main")
1057
- _ORIGINAL_BRANCH="$_source_branch"
1058
-
1059
- # Main processing loop
1060
- local session_count=0
1061
- local total_subagent_calls=0
1062
-
1063
- while true; do
1064
- # Safety net: ensure we're on the original branch at the start of each iteration.
1065
- # If a previous iteration's `continue` skipped branch_ensure_return, we could
1066
- # still be on a dev branch. This prevents cascading branch confusion.
1067
- if [[ -n "$_ORIGINAL_BRANCH" ]]; then
1068
- local _cur_branch
1069
- _cur_branch=$(git -C "$_proj_root" rev-parse --abbrev-ref HEAD 2>/dev/null || true)
1070
- if [[ -n "$_cur_branch" && "$_cur_branch" != "$_ORIGINAL_BRANCH" ]]; then
1071
- log_warn "Still on branch $_cur_branch at loop start — returning to $_ORIGINAL_BRANCH"
1072
- branch_ensure_return "$_proj_root" "$_ORIGINAL_BRANCH"
1073
- fi
1074
- fi
1075
-
1076
- # Check for stuck features
1077
- local stuck_result
1078
- stuck_result=$(python3 "$SCRIPTS_DIR/detect-stuck.py" \
1079
- --state-dir "$STATE_DIR" \
1080
- --feature-list "$FEATURE_LIST" \
1081
- --max-retries "$MAX_RETRIES" \
1082
- --stale-threshold "$HEARTBEAT_STALE_THRESHOLD" 2>/dev/null || echo '{"stuck_count": 0}')
1083
-
1084
- local stuck_count
1085
- stuck_count=$(echo "$stuck_result" | python3 -c "import sys,json; print(json.load(sys.stdin).get('stuck_count', 0))" 2>/dev/null || echo "0")
1086
-
1087
- if [[ "$stuck_count" -gt 0 ]]; then
1088
- log_warn "Detected $stuck_count stuck feature(s):"
1089
- echo "$stuck_result" | python3 -c "
1090
- import sys, json
1091
- data = json.load(sys.stdin)
1092
- for f in data.get('stuck_features', []):
1093
- print(f' - {f[\"feature_id\"]}: {f[\"reason\"]} — {f[\"suggestion\"]}')
1094
- " 2>/dev/null || true
1095
- fi
1096
-
1097
- # Find next feature to process
1098
- local next_feature
1099
- local _get_next_args=(
1100
- --feature-list "$feature_list"
1101
- --state-dir "$STATE_DIR"
1102
- --max-retries "$MAX_RETRIES"
1103
- --action get_next
1104
- )
1105
- if [[ -n "$features_filter" ]]; then
1106
- _get_next_args+=(--features "$features_filter")
1107
- fi
1108
- if ! next_feature=$(python3 "$SCRIPTS_DIR/update-feature-status.py" \
1109
- "${_get_next_args[@]}" 2>/dev/null); then
1110
-
1111
- log_error "Failed to get next feature"
1112
- break
1113
- fi
1114
-
1115
-
1116
- if [[ "$next_feature" == "PIPELINE_COMPLETE" ]]; then
1117
- echo ""
1118
- log_success "════════════════════════════════════════════════════"
1119
- log_success " Pipeline finished."
1120
- log_success " Total sessions: $session_count"
1121
- log_success " Total subagent calls: $total_subagent_calls"
1122
- log_success "════════════════════════════════════════════════════"
1123
-
1124
- # Check for auto-skipped features
1125
- local auto_skipped_count
1126
- auto_skipped_count=$(python3 -c "
1127
- import json, sys
1128
- with open(sys.argv[1]) as f:
1129
- data = json.load(f)
1130
- count = sum(1 for f in data.get('features', []) if f.get('status') == 'auto_skipped')
1131
- print(count)
1132
- " "$feature_list" 2>/dev/null || echo "0")
1133
-
1134
- if [[ "$auto_skipped_count" -gt 0 ]]; then
1135
- echo ""
1136
- log_warn "$auto_skipped_count feature(s) were auto-skipped due to failed dependencies."
1137
- log_warn "Run './run-feature.sh status' to see details."
1138
- log_warn "Run './run-feature.sh unskip' to reset and retry them."
1139
- fi
1140
-
1141
- # ── Deploy session (only if ENABLE_DEPLOY=1 and all features completed) ──
1142
- if [[ "$ENABLE_DEPLOY" == "1" ]]; then
1143
- local incomplete_count
1144
- incomplete_count=$({ python3 -c "
1145
- import json, sys
1146
- with open(sys.argv[1]) as f:
1147
- data = json.load(f)
1148
- bad = [f for f in data.get('features', [])
1149
- if f.get('status') not in ('completed', 'skipped')]
1150
- for f in bad:
1151
- print(f\" {f['id']}: {f.get('status', 'unknown')} — {f.get('title', '')}\")
1152
- print(len(bad))
1153
- " "$feature_list" 2>/dev/null || echo "0"; } | tee /dev/stderr | tail -1)
1154
-
1155
- if [[ "$incomplete_count" -gt 0 ]]; then
1156
- echo ""
1157
- log_warn "DEPLOY BLOCKED: $incomplete_count task(s) not completed successfully."
1158
- log_warn "Fix failed tasks and re-run, or manually run /prizmkit-deploy."
1159
- else
1160
- echo ""
1161
- log_info "All tasks completed — starting deploy session..."
1162
- log_info "ENABLE_DEPLOY=1"
1163
-
1164
- local deploy_session_id="deploy-$(date +%Y%m%d%H%M%S)"
1165
- local deploy_session_dir="$STATE_DIR/deploy/$deploy_session_id"
1166
- mkdir -p "$deploy_session_dir/logs"
1167
-
1168
- local deploy_prompt="$deploy_session_dir/bootstrap-prompt.md"
1169
- local _deploy_branch _deploy_commit
1170
- _deploy_branch=$(git -C "$_proj_root" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
1171
- _deploy_commit=$(git -C "$_proj_root" rev-parse --short HEAD 2>/dev/null || echo "unknown")
1172
- cat > "$deploy_prompt" << DEPLOY_PROMPT_EOF
1173
- ## Deploy
1174
-
1175
- All features in the pipeline completed successfully.
1176
-
1177
- - Branch: $_deploy_branch
1178
- - Commit: $_deploy_commit
1179
-
1180
- Run /prizmkit-deploy to deploy the project. Read .prizmkit/deploy/deploy.config.json
1181
- for deployment configuration. If no deploy config exists, guide the user through
1182
- setting one up before deploying.
1183
- DEPLOY_PROMPT_EOF
1184
-
1185
- log_info "Deploy prompt: $deploy_prompt"
1186
- log_info "Deploy log: $deploy_session_dir/logs/session.log"
1187
-
1188
- prizm_run_ai_session "$deploy_prompt" "$deploy_session_dir/logs/session.log"
1189
- local deploy_exit=$?
1190
-
1191
- # Recover log from backup if truncated
1192
- prizm_recover_session_log "$deploy_session_dir/logs/session.log"
1193
-
1194
- if [[ $deploy_exit -eq 0 ]]; then
1195
- log_success "Deploy session completed (exit 0)"
1196
- else
1197
- log_warn "Deploy session exited with code $deploy_exit"
1198
- log_warn "Review log: $deploy_session_dir/logs/session.log"
1199
- fi
1200
- fi
1201
- fi
1202
-
1203
- break
1204
- fi
1205
-
1206
- if [[ "$next_feature" == "PIPELINE_BLOCKED" ]]; then
1207
- log_warn "All remaining features are blocked by dependencies or failed."
1208
- log_warn "Run './run-feature.sh status' to see details."
1209
- log_warn "Waiting 60s before re-checking... (Ctrl+C to stop)"
1210
- sleep 60
1211
- continue
1212
- fi
1213
-
1214
- # Parse feature info
1215
- local feature_id feature_title retry_count infra_error_count resume_phase
1216
- feature_id=$(echo "$next_feature" | jq -r '.feature_id')
1217
- feature_title=$(echo "$next_feature" | jq -r '.title')
1218
- retry_count=$(echo "$next_feature" | jq -r '.retry_count // 0')
1219
- infra_error_count=$(echo "$next_feature" | jq -r '.infra_error_count // 0')
1220
- resume_phase=$(echo "$next_feature" | jq -r '.resume_from_phase // "null"')
1221
-
1222
- echo ""
1223
- echo -e "${BOLD}────────────────────────────────────────────────────${NC}"
1224
- log_info "Feature: ${BOLD}$feature_id${NC} — $feature_title"
1225
- log_info "Code retry: $retry_count / $MAX_RETRIES"
1226
- log_info "Infrastructure retry: $infra_error_count / $MAX_INFRA_RETRIES"
1227
- if [[ "$resume_phase" != "null" ]]; then
1228
- log_info "Resuming from Phase $resume_phase"
1229
- fi
1230
- echo -e "${BOLD}────────────────────────────────────────────────────${NC}"
1231
-
1232
- # Auto-commit any uncommitted workspace changes before starting the pipeline.
1233
- # This ensures a clean baseline without blocking execution.
1234
- local _dirty_files=""
1235
- _dirty_files=$(prizm_git_status_non_bookkeeping "$_proj_root" "$STATE_DIR" "$feature_list" || true)
1236
- if [[ -n "$_dirty_files" ]]; then
1237
- log_info "Auto-committing workspace changes before $feature_id..."
1238
- prizm_git_add_all_safe "$_proj_root"
1239
- git -C "$_proj_root" commit --no-verify -m "chore: workspace snapshot ready for run $feature_id" 2>/dev/null || true
1240
- fi
1241
-
1242
- local _bookkeeping_dirty=""
1243
- _bookkeeping_dirty=$(prizm_git_status_bookkeeping "$_proj_root" "$STATE_DIR" "$feature_list" || true)
1244
- if [[ -n "$_bookkeeping_dirty" ]]; then
1245
- log_info "Committing pending pipeline bookkeeping before $feature_id..."
1246
- prizm_git_commit_paths "$_proj_root" "chore($feature_id): include pipeline bookkeeping" "$feature_list" "$STATE_DIR"
1247
- fi
1248
-
1249
- # Mark feature as in-progress BEFORE creating dev branch
1250
- # This ensures the in_progress status commit lands on the original branch,
1251
- # not the dev branch — preventing rebase conflicts in branch_merge later.
1252
- python3 "$SCRIPTS_DIR/update-feature-status.py" \
1253
- --feature-list "$feature_list" \
1254
- --state-dir "$STATE_DIR" \
1255
- --feature-id "$feature_id" \
1256
- --action start >/dev/null 2>&1 || true
1257
- # Commit the in_progress status on the original branch
1258
- if ! git -C "$_proj_root" diff --quiet "$feature_list" 2>/dev/null; then
1259
- prizm_git_commit_paths "$_proj_root" "chore($feature_id): mark in_progress" "$feature_list"
1260
- fi
1261
-
1262
- # Create per-feature dev branch (from the now-updated original branch)
1263
- local _feature_branch="${DEV_BRANCH:-dev/${feature_id}-$(date +%Y%m%d%H%M)}"
1264
- if branch_create "$_proj_root" "$_feature_branch" "$_ORIGINAL_BRANCH"; then
1265
- _DEV_BRANCH_NAME="$_feature_branch"
1266
- log_info "Dev branch: $_feature_branch"
1267
- else
1268
- log_error "Failed to create dev branch: $_feature_branch from $_ORIGINAL_BRANCH — aborting to avoid running on $_ORIGINAL_BRANCH"
1269
- _DEV_BRANCH_NAME=""
1270
- break
1271
- fi
1272
-
1273
- # Generate session ID and bootstrap prompt
1274
- local session_id run_id
1275
- run_id=$(jq -r '.run_id' "$STATE_DIR/pipeline.json")
1276
- session_id="${feature_id}-$(date +%Y%m%d%H%M%S)"
1277
-
1278
- local session_dir="$STATE_DIR/$feature_id/sessions/$session_id"
1279
- mkdir -p "$session_dir/logs"
1280
-
1281
- local bootstrap_prompt="$session_dir/bootstrap-prompt.md"
1282
-
1283
- local main_prompt_args=(
1284
- --feature-list "$feature_list"
1285
- --feature-id "$feature_id"
1286
- --session-id "$session_id"
1287
- --run-id "$run_id"
1288
- --retry-count "$retry_count"
1289
- --resume-phase "$resume_phase"
1290
- --state-dir "$STATE_DIR"
1291
- --output "$bootstrap_prompt"
1292
- )
1293
-
1294
- # Support PIPELINE_MODE env var (set by launch-feature-daemon.sh --mode)
1295
- if [[ -n "${PIPELINE_MODE:-}" ]]; then
1296
- main_prompt_args+=(--mode "$PIPELINE_MODE")
1297
- fi
1298
-
1299
- # Support ENABLE_CRITIC env var (set by launch-feature-daemon.sh --critic)
1300
- if [[ "${ENABLE_CRITIC:-}" == "true" || "${ENABLE_CRITIC:-}" == "1" ]]; then
1301
- main_prompt_args+=(--critic "true")
1302
- elif [[ "${ENABLE_CRITIC:-}" == "false" || "${ENABLE_CRITIC:-}" == "0" ]]; then
1303
- main_prompt_args+=(--critic "false")
1304
- fi
1305
-
1306
- local gen_output
1307
- gen_output=$(python3 "$SCRIPTS_DIR/generate-bootstrap-prompt.py" "${main_prompt_args[@]}" 2>/dev/null) || {
1308
- log_error "Failed to generate bootstrap prompt for $feature_id"
1309
- branch_ensure_return "$_proj_root" "$_ORIGINAL_BRANCH"
1310
- _DEV_BRANCH_NAME=""
1311
- continue
1312
- }
1313
- local feature_model pipeline_mode agent_count critic_enabled
1314
- feature_model=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('model',''))" 2>/dev/null || echo "")
1315
- pipeline_mode=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('pipeline_mode','lite'))" 2>/dev/null || echo "lite")
1316
- agent_count=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('agent_count',1))" 2>/dev/null || echo "1")
1317
- critic_enabled=$(echo "$gen_output" | python3 -c "import json,sys; print(json.load(sys.stdin).get('critic_enabled','false'))" 2>/dev/null || echo "false")
1318
-
1319
- # Log pipeline mode and agent configuration
1320
- local _mode_desc
1321
- case "$pipeline_mode" in
1322
- lite) _mode_desc="Tier 1 — Single Agent" ;;
1323
- standard) _mode_desc="Tier 2 — Orchestrator + Dev + Reviewer" ;;
1324
- full) _mode_desc="Tier 3 — Full Team (+ Multi-Critic)" ;;
1325
- *) _mode_desc="$pipeline_mode" ;;
1326
- esac
1327
- log_info "Pipeline mode: ${BOLD}$pipeline_mode${NC} ($_mode_desc)"
1328
- log_info "Agents: $agent_count (critic: $([ "$critic_enabled" = "true" ] && echo "enabled" || echo "disabled"))"
1329
-
1330
- # Spawn session and wait
1331
- prizm_log_bootstrap_prompt "$bootstrap_prompt" "$feature_id"
1332
- log_info "Spawning AI CLI session: $session_id"
1333
- if [[ -n "$feature_model" ]]; then
1334
- log_info "Feature model: $feature_model"
1335
- fi
1336
- _SPAWN_RESULT=""
1337
- _SPAWN_ITEM_STATUS=""
1338
-
1339
- spawn_and_wait_session \
1340
- "$feature_id" "$feature_list" "$session_id" \
1341
- "$bootstrap_prompt" "$session_dir" "$MAX_RETRIES" "$feature_model" "$_ORIGINAL_BRANCH"
1342
- local session_status="$_SPAWN_RESULT"
1343
-
1344
- # Merge per-feature dev branch back to original on success
1345
- if [[ "$session_status" == "success" && -n "$_DEV_BRANCH_NAME" ]]; then
1346
- if branch_merge "$_proj_root" "$_DEV_BRANCH_NAME" "$_ORIGINAL_BRANCH" "$AUTO_PUSH"; then
1347
- _DEV_BRANCH_NAME=""
1348
- else
1349
- log_warn "Auto-merge failed — dev branch preserved: $_DEV_BRANCH_NAME"
1350
- log_warn "Merge manually: git checkout $_ORIGINAL_BRANCH && git rebase $_DEV_BRANCH_NAME"
1351
- session_status="merge_conflict"
1352
- fi
1353
- elif [[ -n "$_DEV_BRANCH_NAME" ]]; then
1354
- # Session failed — preserve dev branch for inspection
1355
- log_warn "Session failed — dev branch preserved for inspection: $_DEV_BRANCH_NAME"
1356
- _DEV_BRANCH_NAME=""
1357
- fi
1358
-
1359
- # GUARANTEED: always return to original branch regardless of success/failure/merge outcome
1360
- branch_ensure_return "$_proj_root" "$_ORIGINAL_BRANCH"
1361
-
1362
- finalize_feature_status_after_branch_return \
1363
- "$feature_id" "$feature_list" "$session_id" "$session_status" "$MAX_RETRIES" "$MAX_INFRA_RETRIES" "$session_dir" "$_ORIGINAL_BRANCH"
1364
- local item_status_after_session="${_SPAWN_ITEM_STATUS:-}"
1365
-
1366
- # Commit feature status update on the original branch (after guaranteed return)
1367
- if ! git -C "$_proj_root" diff --quiet "$feature_list" 2>/dev/null; then
1368
- prizm_git_commit_paths "$_proj_root" "chore($feature_id): update feature status" "$feature_list"
1369
- fi
1370
-
1371
- session_count=$((session_count + 1))
1372
- total_subagent_calls=$((total_subagent_calls + _SUBAGENT_COUNT))
1373
-
1374
- # Stop-on-failure: abort only after the task is actually marked failed.
1375
- # Pending retry outcomes keep running; both code and infra failures have
1376
- # bounded budgets in update-feature-status.py.
1377
- if [[ "$session_status" != "success" && "$STOP_ON_FAILURE" == "1" && "$item_status_after_session" == "failed" ]]; then
1378
- echo ""
1379
- log_error "════════════════════════════════════════════════════"
1380
- log_error " STOP_ON_FAILURE: Pipeline halted after $feature_id exhausted retries."
1381
- log_error " Total sessions completed: $session_count"
1382
- log_error " Set STOP_ON_FAILURE=0 to continue past failures."
1383
- log_error "════════════════════════════════════════════════════"
1384
- break
1385
- elif [[ "$session_status" != "success" && "$STOP_ON_FAILURE" == "1" ]]; then
1386
- log_info "STOP_ON_FAILURE: $feature_id is ${item_status_after_session:-unknown}; code/infra retry budget not exhausted, continuing."
1387
- fi
1388
-
1389
- # Brief pause before next iteration
1390
- log_info "Pausing 5s before next feature..."
1391
- sleep 5
1392
- done
1393
- }
1394
-
1395
- # ============================================================
1396
- # Entry Point
1397
- # ============================================================
1398
-
1399
- show_help() {
1400
- echo "Usage: $0 <command> [options]"
1401
- echo ""
1402
- echo "Commands:"
1403
- echo " run [.prizmkit/plans/feature-list.json] [--features <filter>] Run features (all or filtered subset)"
1404
- echo " run <feature-id> [options] Run a single feature"
1405
- echo " status [.prizmkit/plans/feature-list.json] Show pipeline status"
1406
- echo " unskip [feature-id] [.prizmkit/plans/feature-list.json] Reset auto-skipped/failed features"
1407
- echo " test-cli Test AI CLI: show detected CLI, version, and model"
1408
- echo " reset Clear all state and start fresh"
1409
- echo " help Show this help message"
1410
- echo ""
1411
- echo "Feature Filter (--features):"
1412
- echo " --features F-001,F-003,F-005 Run only specified features"
1413
- echo " --features F-001:F-010 Run a range of features (F-001 through F-010)"
1414
- echo " --features F-001,F-005:F-010 Mixed: individual IDs + ranges"
1415
- echo ""
1416
- echo "Single Feature Options (run <feature-id>):"
1417
- echo " --dry-run Generate bootstrap prompt only, don't spawn session"
1418
- echo " --resume-phase N Override resume phase (default: auto-detect)"
1419
- echo " --mode <lite|standard|full> Override pipeline mode (bypasses estimated_complexity)"
1420
- echo " --critic Enable adversarial critic review for this feature"
1421
- echo " --no-critic Disable critic review (overrides feature-list setting)"
1422
- echo " --clean Delete artifacts and reset before running"
1423
- echo " --no-reset Skip feature status reset step"
1424
- echo " --max-infra-retries N Max infrastructure/provider retries (default: 3)"
1425
- echo ""
1426
- echo "Pipeline Options (run all):"
1427
- echo " --max-infra-retries N Max infrastructure/provider retries (default: 3)"
1428
- echo ""
1429
- echo "Environment Variables:"
1430
- echo " MAX_RETRIES Max code retries per feature (default: 3)"
1431
- echo " MAX_INFRA_RETRIES Max infrastructure/provider retries per feature (default: 3)"
1432
- echo " AI_CLI AI CLI command name (auto-detected: cbc, claude, or codex)"
1433
- echo " MODEL AI model ID (e.g. claude-opus-4.6, claude-sonnet-4.6, claude-haiku-4.5)"
1434
- echo " PRIZMKIT_EFFORT AI reasoning effort (low|medium|high|xhigh|max; max is Claude Code only)"
1435
- echo " HEARTBEAT_INTERVAL Heartbeat log interval in seconds (default: 30)"
1436
- echo " STALE_KILL_THRESHOLD Auto-kill session after N seconds of no progress (default: 900)"
1437
- echo " HEARTBEAT_STALE_THRESHOLD Heartbeat stale threshold in seconds (default: 600)"
1438
- echo " MAX_LOG_SIZE Session log size threshold for compact warning (default: 2097152 = 2MB, set 0 to disable)"
1439
- echo " LOG_MONITOR_POLL_INTERVAL Log monitor poll interval in seconds (default: 30)"
1440
- echo " PIPELINE_MODE Override mode for all features: lite|standard|full"
1441
- echo " ENABLE_CRITIC Enable critic review for all features: true|false"
1442
- echo " STOP_ON_FAILURE Stop pipeline when a task exhausts retries: 0|1 (default: 0)"
1443
- echo ""
1444
- echo "Examples:"
1445
- echo " ./run-feature.sh run # Run all features"
1446
- echo " ./run-feature.sh run --features F-001,F-003,F-005 # Run specific features"
1447
- echo " ./run-feature.sh run --features F-001:F-010 # Run features F-001 through F-010"
1448
- echo " ./run-feature.sh run F-007 --dry-run # Inspect generated prompt"
1449
- echo " ./run-feature.sh run F-007 --dry-run --mode lite # Test lite mode"
1450
- echo " ./run-feature.sh run F-007 --resume-phase 6 # Skip to implementation"
1451
- echo " ./run-feature.sh run F-007 --clean --mode standard # Clean + run standard"
1452
- echo " ./run-feature.sh status # Show pipeline status"
1453
- echo " MODEL=claude-sonnet-4.6 ./run-feature.sh run # Use Sonnet model"
1454
- echo " MODEL=claude-haiku-4.5 ./run-feature.sh test-cli # Test with Haiku"
1455
- }
1456
-
1457
- case "${1:-run}" in
1458
- run|resume)
1459
- shift || true
1460
- # Check if first arg is a feature ID (F-xxx pattern)
1461
- if [[ "${1:-}" =~ ^[Ff]-[0-9]+ ]]; then
1462
- run_one "$@"
1463
- else
1464
- # Parse positional and --features flag
1465
- _run_feature_list="$PRIZMKIT_DIR/plans/feature-list.json"
1466
- _run_features_filter=""
1467
- while [[ $# -gt 0 ]]; do
1468
- case "$1" in
1469
- --features)
1470
- shift
1471
- if [[ $# -eq 0 ]]; then
1472
- log_error "--features requires a value (e.g. --features F-001,F-003 or --features F-001:F-010)"
1473
- exit 1
1474
- fi
1475
- _run_features_filter="$1"
1476
- shift
1477
- ;;
1478
- --max-infra-retries)
1479
- shift
1480
- if [[ $# -eq 0 ]]; then
1481
- log_error "--max-infra-retries requires a value"
1482
- exit 1
1483
- fi
1484
- prizm_require_positive_int "--max-infra-retries" "$1"
1485
- MAX_INFRA_RETRIES="$1"
1486
- shift
1487
- ;;
1488
- *)
1489
- _run_feature_list="$1"
1490
- shift
1491
- ;;
1492
- esac
1493
- done
1494
- main "$_run_feature_list" "$_run_features_filter"
1495
- fi
1496
- ;;
1497
- status)
1498
- check_dependencies
1499
- if [[ ! -f "$STATE_DIR/pipeline.json" ]]; then
1500
- log_error "No pipeline state found. Run './run-feature.sh run' first."
1501
- exit 1
1502
- fi
1503
- python3 "$SCRIPTS_DIR/update-feature-status.py" \
1504
- --feature-list "${2:-$PRIZMKIT_DIR/plans/feature-list.json}" \
1505
- --state-dir "$STATE_DIR" \
1506
- --action status
1507
- ;;
1508
- test-cli)
1509
- echo ""
1510
- echo "============================================"
1511
- echo " Dev-Pipeline AI CLI Test"
1512
- echo "============================================"
1513
- echo ""
1514
- echo " Detected CLI: $CLI_CMD"
1515
- echo " Platform: $PLATFORM"
1516
- if [[ -n "$MODEL" ]]; then
1517
- echo " Requested Model: $MODEL"
1518
- fi
1519
-
1520
- # Get CLI version (first line only)
1521
- cli_version=$("$CLI_CMD" -v 2>&1 | head -1 || echo "unknown")
1522
- echo " CLI Version: $cli_version"
1523
- echo ""
1524
- echo " Querying AI model (headless mode)..."
1525
-
1526
- test_prompt="What AI assistant/platform are you and what model are you running? Reply in one line, e.g. \"I'm Claude Code Claude Opnus x.x\".No extra text."
1527
-
1528
- # Run headless query with 30s timeout (background + kill pattern for macOS)
1529
- tmpfile=$(mktemp)
1530
- prompt_file=$(mktemp)
1531
- printf '%s\n' "$test_prompt" > "$prompt_file"
1532
- (
1533
- prizm_run_ai_session "$prompt_file" "$tmpfile" "$MODEL"
1534
- ) &
1535
- query_pid=$!
1536
- ( sleep 30 && kill "$query_pid" 2>/dev/null ) &
1537
- timer_pid=$!
1538
- wait "$query_pid" 2>/dev/null
1539
- kill "$timer_pid" 2>/dev/null
1540
- wait "$timer_pid" 2>/dev/null || true
1541
-
1542
- model_reply=$(cat "$tmpfile" 2>/dev/null | head -3)
1543
- rm -f "$tmpfile" "$prompt_file"
1544
-
1545
- if [[ -z "$model_reply" ]]; then
1546
- model_reply="(no response — CLI may require auth or is unavailable)"
1547
- fi
1548
-
1549
- echo ""
1550
- echo " AI Response: $model_reply"
1551
- echo ""
1552
- echo "============================================"
1553
- echo ""
1554
- ;;
1555
- reset)
1556
- log_warn "Resetting pipeline state..."
1557
- rm -rf "$STATE_DIR"
1558
- log_success "State cleared. Run './run-feature.sh run' to start fresh."
1559
- ;;
1560
- unskip)
1561
- check_dependencies
1562
- if [[ ! -f "$STATE_DIR/pipeline.json" ]]; then
1563
- log_error "No pipeline state found. Run './run-feature.sh run' first."
1564
- exit 1
1565
- fi
1566
- _unskip_feature_list="$PRIZMKIT_DIR/plans/feature-list.json"
1567
- _unskip_feature_id=""
1568
- shift || true
1569
- # Parse arguments: optional feature-id and feature-list path
1570
- while [[ $# -gt 0 ]]; do
1571
- if [[ "$1" =~ ^[Ff]-[0-9]+ ]]; then
1572
- _unskip_feature_id="$1"
1573
- else
1574
- _unskip_feature_list="$1"
1575
- fi
1576
- shift
1577
- done
1578
- _unskip_args=(
1579
- --feature-list "$_unskip_feature_list"
1580
- --state-dir "$STATE_DIR"
1581
- --action unskip
1582
- )
1583
- if [[ -n "$_unskip_feature_id" ]]; then
1584
- _unskip_args+=(--feature-id "$_unskip_feature_id")
1585
- fi
1586
- python3 "$SCRIPTS_DIR/update-feature-status.py" "${_unskip_args[@]}"
1587
-
1588
- # Commit the status change
1589
- if ! git diff --quiet "$_unskip_feature_list" 2>/dev/null; then
1590
- git add "$_unskip_feature_list" 2>/dev/null || true
1591
- git commit -m "chore: unskip auto-skipped features" 2>/dev/null || true
1592
- fi
1593
- ;;
1594
- help|--help|-h)
1595
- show_help
1596
- ;;
1597
- *)
1598
- log_error "Unknown command: $1"
1599
- show_help
1600
- exit 1
1601
- ;;
1602
- esac