prizmkit 1.1.100 → 1.1.102

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