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,1327 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Core state machine for updating refactor status in the refactor pipeline.
3
-
4
- Handles eight actions:
5
- - get_next: Find the next refactor to process based on dependency order, priority, complexity
6
- - start: Mark a refactor as in_progress when a session starts
7
- - update: Update a refactor's status based on session outcome
8
- - status: Print a formatted overview of all refactors
9
- - pause: Save pipeline state for graceful shutdown
10
- - reset: Reset a refactor to pending (status + retry count)
11
- - clean: Reset + delete session history + delete refactor artifacts
12
- - unskip: Reset skipped refactors and their downstream dependents back to pending
13
-
14
- Usage:
15
- python3 update-refactor-status.py \
16
- --refactor-list <path> --state-dir <path> \
17
- --action <get_next|start|update|status|pause|reset|clean|unskip> \
18
- [--refactor-id <id>] [--session-status <status>] \
19
- [--session-id <id>] [--max-retries <n>] [--max-infra-retries <n>]
20
- """
21
-
22
- import argparse
23
- import json
24
- import os
25
- import shutil
26
- import sys
27
- from datetime import datetime, timezone
28
-
29
- from utils import (
30
- load_json_file,
31
- write_json_file,
32
- error_out,
33
- pad_right,
34
- _build_progress_bar,
35
- )
36
-
37
-
38
- SESSION_STATUS_VALUES = [
39
- "success",
40
- "partial_resumable",
41
- "partial_not_resumable",
42
- "failed",
43
- "crashed",
44
- "timed_out",
45
- "infra_error",
46
- "context_overflow",
47
- "stalled_context_continuation",
48
- "commit_missing",
49
- "docs_missing",
50
- "merge_conflict",
51
- ]
52
-
53
- TERMINAL_STATUSES = {"completed", "failed", "skipped", "auto_skipped"}
54
-
55
- # Artifact directory names (relative to project root)
56
- REFACTOR_ARTIFACTS_REL = os.path.join(".prizmkit", "refactor")
57
- DEV_TEAM_DIR_NAME = ".dev-team"
58
-
59
- # Priority ordering (lower number = higher priority)
60
- PRIORITY_ORDER = {
61
- "critical": 0,
62
- "high": 1,
63
- "medium": 2,
64
- "low": 3,
65
- }
66
-
67
- # Complexity ordering (lower number = simpler, processed first)
68
- COMPLEXITY_ORDER = {
69
- "low": 0,
70
- "medium": 1,
71
- "high": 2,
72
- }
73
-
74
-
75
- def parse_args():
76
- parser = argparse.ArgumentParser(
77
- description="Core state machine for refactor pipeline status management."
78
- )
79
- parser.add_argument("--refactor-list", required=True, help="Path to the .prizmkit/plans/refactor-list.json file")
80
- parser.add_argument("--state-dir", required=True, help="Path to the state directory (default: .prizmkit/state/refactor)")
81
- parser.add_argument(
82
- "--action", required=True,
83
- choices=["get_next", "start", "update", "status", "pause", "reset", "clean", "unskip", "complete"],
84
- help="Action to perform",
85
- )
86
- parser.add_argument("--refactor-id", default=None, help="Refactor ID (required for 'update'/'reset'/'clean' actions)")
87
- parser.add_argument(
88
- "--session-status", default=None, choices=SESSION_STATUS_VALUES,
89
- help="Session outcome status (required for 'update' action)",
90
- )
91
- parser.add_argument("--session-id", default=None, help="Session ID (optional, for 'update' action)")
92
- parser.add_argument("--max-retries", type=int, default=3, help="Maximum code retry count (default: 3)")
93
- parser.add_argument("--max-infra-retries", type=int, default=3, help="Maximum infrastructure retry count (default: 3)")
94
- parser.add_argument("--project-root", default=None, help="Project root directory. Required for 'clean' action.")
95
- parser.add_argument("--active-dev-branch", default=None, help="Development branch preserved for continuation after context overflow.")
96
- parser.add_argument("--base-branch", default=None, help="Original/base branch for continuation branch reuse.")
97
- parser.add_argument("--last-fatal-error-code", default=None, help="Fatal runtime error code associated with continuation.")
98
- parser.add_argument("--continuation-summary-path", default=None, help="Optional continuation summary artifact path.")
99
- parser.add_argument("--no-progress-count", type=int, default=None, help="Consecutive context-overflow sessions without objective progress.")
100
- parser.add_argument("--progress-fingerprint", default=None, help="JSON progress fingerprint captured after the session.")
101
- return parser.parse_args()
102
-
103
-
104
- def now_iso():
105
- return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
106
-
107
-
108
- def _default_status(refactor_id):
109
- """Create a default refactor runtime status object (no status field)."""
110
- now = now_iso()
111
- return {
112
- "refactor_id": refactor_id,
113
- "retry_count": 0,
114
- "max_retries": 3,
115
- "max_infra_retries": 3,
116
- "infra_error_count": 0,
117
- "last_infra_error_session_id": None,
118
- "sessions": [],
119
- "last_session_id": None,
120
- "resume_from_phase": None,
121
- "created_at": now,
122
- "updated_at": now,
123
- }
124
-
125
-
126
- def load_refactor_status(state_dir, refactor_id):
127
- """Load runtime state from status.json for a refactor.
128
-
129
- Returns runtime fields only (retry_count, sessions, etc.).
130
- The 'status' field is NOT included — status lives exclusively
131
- in refactor-list.json.
132
- """
133
- status_path = os.path.join(state_dir, refactor_id, "status.json")
134
- if not os.path.isfile(status_path):
135
- return _default_status(refactor_id)
136
- data, err = load_json_file(status_path)
137
- if err:
138
- return _default_status(refactor_id)
139
- # Defensively remove status if present (legacy data)
140
- data.pop("status", None)
141
- return data
142
-
143
-
144
- def save_refactor_status(state_dir, refactor_id, status_data):
145
- """Write the status.json for a refactor (runtime fields only)."""
146
- # Defensively strip status — it belongs in refactor-list.json
147
- status_data.pop("status", None)
148
- status_path = os.path.join(state_dir, refactor_id, "status.json")
149
- return write_json_file(status_path, status_data)
150
-
151
-
152
- def get_refactor_status_from_list(refactor_list_path, refactor_id):
153
- """Read a single refactor's status from refactor-list.json."""
154
- data, err = load_json_file(refactor_list_path)
155
- if err:
156
- return "pending"
157
- for r in data.get("refactors", []):
158
- if isinstance(r, dict) and r.get("id") == refactor_id:
159
- return r.get("status", "pending")
160
- return "pending"
161
-
162
-
163
- def update_refactor_in_list(refactor_list_path, refactor_id, new_status):
164
- data, err = load_json_file(refactor_list_path)
165
- if err:
166
- return err
167
- refactors = data.get("refactors", [])
168
- found = False
169
- for refactor in refactors:
170
- if isinstance(refactor, dict) and refactor.get("id") == refactor_id:
171
- refactor["status"] = new_status
172
- found = True
173
- break
174
- if not found:
175
- return "Refactor '{}' not found in .prizmkit/plans/refactor-list.json".format(refactor_id)
176
- return write_json_file(refactor_list_path, data)
177
-
178
-
179
- CONTINUATION_PENDING_FIELDS = [
180
- "active_dev_branch",
181
- "base_branch",
182
- "continuation_pending",
183
- "continuation_reason",
184
- "last_context_overflow_session_id",
185
- "previous_session_id",
186
- "last_fatal_error_code",
187
- "continuation_summary_path",
188
- "no_progress_count",
189
- "last_progress_fingerprint",
190
- "needs_attention",
191
- "stalled_context_continuation",
192
- "stalled_reason",
193
- ]
194
-
195
- CONTINUATION_COUNTER_FIELDS = [
196
- "context_overflow_count",
197
- "continuation_count",
198
- ]
199
-
200
-
201
- def has_pending_continuation_metadata(status_data):
202
- """Return True when runtime state still has pending continuation metadata."""
203
- return any(key in status_data for key in CONTINUATION_PENDING_FIELDS)
204
-
205
-
206
- def clear_pending_continuation_metadata(status_data):
207
- """Clear branch/pending continuation fields while preserving observability counters."""
208
- for key in CONTINUATION_PENDING_FIELDS:
209
- status_data.pop(key, None)
210
-
211
-
212
- def reset_continuation_metadata(status_data):
213
- """Clear all continuation runtime metadata, including manual-reset counters."""
214
- clear_pending_continuation_metadata(status_data)
215
- for key in CONTINUATION_COUNTER_FIELDS:
216
- status_data.pop(key, None)
217
-
218
-
219
- STALL_REASON = "context_overflow_without_git_checkpoint_or_artifact_progress"
220
-
221
-
222
- def _load_progress_fingerprint(raw):
223
- if not raw:
224
- return None
225
- try:
226
- return json.loads(raw)
227
- except (TypeError, ValueError):
228
- return {"unparsed": str(raw)}
229
-
230
-
231
- def _set_continuation_common(status_data, args, session_id):
232
- if args.active_dev_branch:
233
- status_data["active_dev_branch"] = args.active_dev_branch
234
- if args.base_branch:
235
- status_data["base_branch"] = args.base_branch
236
- status_data["last_context_overflow_session_id"] = session_id
237
- status_data["previous_session_id"] = session_id
238
- status_data["last_fatal_error_code"] = args.last_fatal_error_code or "context_overflow"
239
- if args.continuation_summary_path:
240
- status_data["continuation_summary_path"] = args.continuation_summary_path
241
- else:
242
- status_data.pop("continuation_summary_path", None)
243
- if args.no_progress_count is not None:
244
- status_data["no_progress_count"] = max(0, args.no_progress_count)
245
- fingerprint = _load_progress_fingerprint(args.progress_fingerprint)
246
- if fingerprint is not None:
247
- status_data["last_progress_fingerprint"] = fingerprint
248
- status_data["last_infra_error_session_id"] = None
249
- status_data["resume_from_phase"] = None
250
- if session_id:
251
- status_data["last_session_id"] = session_id
252
-
253
-
254
- def set_context_overflow_continuation_metadata(status_data, args, session_id):
255
- """Record continuation metadata for a context-overflow outcome in status.json."""
256
- status_data["context_overflow_count"] = status_data.get("context_overflow_count", 0) + 1
257
- status_data["continuation_count"] = status_data.get("continuation_count", 0) + 1
258
- status_data["continuation_pending"] = True
259
- status_data["continuation_reason"] = "context_overflow"
260
- status_data.pop("needs_attention", None)
261
- status_data.pop("stalled_context_continuation", None)
262
- status_data.pop("stalled_reason", None)
263
- _set_continuation_common(status_data, args, session_id)
264
-
265
-
266
- def set_stalled_context_continuation_metadata(status_data, args, session_id):
267
- """Record no-progress context-overflow stall without consuming retry budgets."""
268
- status_data["context_overflow_count"] = status_data.get("context_overflow_count", 0) + 1
269
- status_data["continuation_count"] = status_data.get("continuation_count", 0) + 1
270
- _set_continuation_common(status_data, args, session_id)
271
- status_data["continuation_pending"] = False
272
- status_data["continuation_reason"] = STALL_REASON
273
- status_data["needs_attention"] = True
274
- status_data["stalled_context_continuation"] = True
275
- status_data["stalled_reason"] = STALL_REASON
276
- if args.no_progress_count is None or args.no_progress_count < 2:
277
- status_data["no_progress_count"] = 2
278
-
279
-
280
- def continuation_metadata_summary(status_data):
281
- """Return additive continuation fields for CLI JSON outputs."""
282
- return {
283
- "active_dev_branch": status_data.get("active_dev_branch"),
284
- "base_branch": status_data.get("base_branch"),
285
- "continuation_pending": status_data.get("continuation_pending", False),
286
- "continuation_reason": status_data.get("continuation_reason"),
287
- "last_context_overflow_session_id": status_data.get("last_context_overflow_session_id"),
288
- "last_fatal_error_code": status_data.get("last_fatal_error_code"),
289
- "previous_session_id": status_data.get("previous_session_id"),
290
- "context_overflow_count": status_data.get("context_overflow_count", 0),
291
- "continuation_count": status_data.get("continuation_count", 0),
292
- "no_progress_count": status_data.get("no_progress_count", 0),
293
- "last_progress_fingerprint": status_data.get("last_progress_fingerprint"),
294
- "needs_attention": status_data.get("needs_attention", False),
295
- "stalled_context_continuation": status_data.get("stalled_context_continuation", False),
296
- "stalled_reason": status_data.get("stalled_reason"),
297
- "continuation_summary_path": status_data.get("continuation_summary_path"),
298
- }
299
-
300
-
301
- # ---------------------------------------------------------------------------
302
- # Action: get_next
303
- # ---------------------------------------------------------------------------
304
-
305
-
306
- def _dependencies_met(refactor, completed_set):
307
- """Check if all dependencies for a refactor are in terminal (completed) status."""
308
- deps = refactor.get("dependencies", [])
309
- if not deps or not isinstance(deps, list):
310
- return True
311
- return all(dep in completed_set for dep in deps)
312
-
313
-
314
- def _count_unmet_deps(refactor, completed_set):
315
- """Count how many dependencies are not yet completed."""
316
- deps = refactor.get("dependencies", [])
317
- if not deps or not isinstance(deps, list):
318
- return 0
319
- return sum(1 for dep in deps if dep not in completed_set)
320
-
321
-
322
- def action_get_next(refactor_list_data, state_dir):
323
- """Find the next refactor to process.
324
-
325
- Priority logic:
326
- 1. Skip terminal statuses (completed, failed, skipped)
327
- 2. Only consider refactors whose dependencies are all completed
328
- 3. Prefer in_progress refactors (interrupted session resume) over pending
329
- 4. Sort by: dependency order (no-dependency items first),
330
- then priority (critical > high > medium > low),
331
- then complexity (low first)
332
- """
333
- refactors = refactor_list_data.get("refactors", [])
334
- if not refactors:
335
- print("PIPELINE_COMPLETE")
336
- return
337
-
338
- # Build status map from refactor-list.json (single source of truth)
339
- status_map = {}
340
- status_data_map = {}
341
- for r in refactors:
342
- if not isinstance(r, dict):
343
- continue
344
- rid = r.get("id")
345
- if not rid:
346
- continue
347
- status_map[rid] = r.get("status", "pending")
348
- rs = load_refactor_status(state_dir, rid)
349
- status_data_map[rid] = rs
350
-
351
- completed_set = {rid for rid, st in status_map.items() if st in TERMINAL_STATUSES}
352
-
353
- # Check if all refactors are terminal
354
- non_terminal = [
355
- r for r in refactors
356
- if isinstance(r, dict) and r.get("id")
357
- and status_map.get(r["id"], "pending") not in TERMINAL_STATUSES
358
- ]
359
- if not non_terminal:
360
- print("PIPELINE_COMPLETE")
361
- return
362
-
363
- # Filter to only those with met dependencies
364
- eligible = [r for r in non_terminal if _dependencies_met(r, completed_set)]
365
- if not eligible:
366
- print("PIPELINE_BLOCKED")
367
- return
368
-
369
- # Separate in_progress from pending
370
- in_progress_refactors = []
371
- pending_refactors = []
372
- for r in eligible:
373
- rid = r.get("id")
374
- rstatus = status_map.get(rid, "pending")
375
- if rstatus == "in_progress":
376
- in_progress_refactors.append(r)
377
- elif rstatus == "pending":
378
- pending_refactors.append(r)
379
-
380
- def sort_key(r):
381
- unmet = _count_unmet_deps(r, completed_set)
382
- priority = PRIORITY_ORDER.get(r.get("priority", "medium"), 2)
383
- complexity = COMPLEXITY_ORDER.get(r.get("complexity", "medium"), 1)
384
- return (unmet, priority, complexity)
385
-
386
- if in_progress_refactors:
387
- candidates = sorted(in_progress_refactors, key=sort_key)
388
- elif pending_refactors:
389
- candidates = sorted(pending_refactors, key=sort_key)
390
- else:
391
- print("PIPELINE_BLOCKED")
392
- return
393
-
394
- chosen = candidates[0]
395
- chosen_id = chosen["id"]
396
- chosen_status_data = status_data_map.get(chosen_id, {})
397
-
398
- result = {
399
- "refactor_id": chosen_id,
400
- "title": chosen.get("title", ""),
401
- "type": chosen.get("type", "restructure"),
402
- "priority": chosen.get("priority", "medium"),
403
- "complexity": chosen.get("complexity", "medium"),
404
- "retry_count": chosen_status_data.get("retry_count", 0),
405
- "infra_error_count": chosen_status_data.get("infra_error_count", 0),
406
- "resume_from_phase": chosen_status_data.get("resume_from_phase", None),
407
- }
408
- result.update(continuation_metadata_summary(chosen_status_data))
409
- print(json.dumps(result, indent=2, ensure_ascii=False))
410
-
411
-
412
- # ---------------------------------------------------------------------------
413
- # Action: update
414
- # ---------------------------------------------------------------------------
415
-
416
- def action_update(args, refactor_list_path, state_dir):
417
- refactor_id = args.refactor_id
418
- session_status = args.session_status
419
- session_id = args.session_id
420
- max_retries = args.max_retries
421
- max_infra_retries = args.max_infra_retries
422
-
423
- if not refactor_id:
424
- error_out("--refactor-id is required for 'update' action")
425
- return
426
- if not session_status:
427
- error_out("--session-status is required for 'update' action")
428
- return
429
-
430
- rs = load_refactor_status(state_dir, refactor_id)
431
-
432
- current_list_status = get_refactor_status_from_list(refactor_list_path, refactor_id)
433
-
434
- # Track what status we write to refactor-list.json
435
- new_status = current_list_status
436
-
437
- if session_status == "success":
438
- rs["infra_error_count"] = 0
439
- rs["last_infra_error_session_id"] = None
440
- clear_pending_continuation_metadata(rs)
441
- new_status = "completed"
442
- rs["resume_from_phase"] = None
443
- err = update_refactor_in_list(refactor_list_path, refactor_id, "completed")
444
- if err:
445
- error_out("Failed to update .prizmkit/plans/refactor-list.json: {}".format(err))
446
- return
447
- elif session_status in ("commit_missing", "docs_missing", "merge_conflict"):
448
- rs["retry_count"] = rs.get("retry_count", 0) + 1
449
-
450
- if rs["retry_count"] >= max_retries:
451
- new_status = "failed"
452
- else:
453
- new_status = "pending"
454
-
455
- rs["degraded_reason"] = session_status
456
- rs["resume_from_phase"] = None
457
- rs["sessions"] = []
458
- rs["last_session_id"] = None
459
-
460
- err = update_refactor_in_list(refactor_list_path, refactor_id, new_status)
461
- if err:
462
- error_out("Failed to update .prizmkit/plans/refactor-list.json: {}".format(err))
463
- return
464
- elif session_status == "infra_error":
465
- # AI CLI/provider outage, auth failure, gateway error, etc.
466
- # Infra failures do not consume the code retry budget, but they still
467
- # need their own bounded budget so a flaky provider cannot loop forever.
468
- infra_error_count = rs.get("infra_error_count", 0) + 1
469
- rs["infra_error_count"] = infra_error_count
470
- rs["last_infra_error_session_id"] = session_id
471
- rs["max_infra_retries"] = max_infra_retries
472
- rs["degraded_reason"] = session_status
473
- if session_id:
474
- rs["last_session_id"] = session_id
475
- rs["resume_from_phase"] = None
476
-
477
- if infra_error_count >= max_infra_retries:
478
- new_status = "failed"
479
- if session_id:
480
- rs["last_failed_session_id"] = session_id
481
- else:
482
- new_status = "pending"
483
-
484
- err = update_refactor_in_list(refactor_list_path, refactor_id, new_status)
485
- if err:
486
- error_out("Failed to update .prizmkit/plans/refactor-list.json: {}".format(err))
487
- return
488
- elif session_status == "context_overflow":
489
- # Context overflow is continuation state, not code or infra retry state.
490
- set_context_overflow_continuation_metadata(rs, args, session_id)
491
- new_status = "in_progress"
492
- if current_list_status != "in_progress":
493
- err = update_refactor_in_list(refactor_list_path, refactor_id, "in_progress")
494
- if err:
495
- error_out("Failed to update .prizmkit/plans/refactor-list.json: {}".format(err))
496
- return
497
- elif session_status == "stalled_context_continuation":
498
- # No-progress context-overflow stall pauses automation without consuming retry budgets.
499
- set_stalled_context_continuation_metadata(rs, args, session_id)
500
- new_status = "failed"
501
- err = update_refactor_in_list(refactor_list_path, refactor_id, new_status)
502
- if err:
503
- error_out("Failed to update .prizmkit/plans/refactor-list.json: {}".format(err))
504
- return
505
- else:
506
- rs["retry_count"] = rs.get("retry_count", 0) + 1
507
-
508
- cleaned = cleanup_refactor_artifacts(
509
- state_dir=state_dir,
510
- refactor_id=refactor_id,
511
- project_root=args.project_root,
512
- )
513
-
514
- if rs["retry_count"] >= max_retries:
515
- new_status = "failed"
516
- else:
517
- new_status = "pending"
518
-
519
- rs["resume_from_phase"] = None
520
- rs["sessions"] = []
521
- rs["last_session_id"] = None
522
-
523
- err = update_refactor_in_list(refactor_list_path, refactor_id, new_status)
524
- if err:
525
- error_out("Failed to update .prizmkit/plans/refactor-list.json: {}".format(err))
526
- return
527
-
528
- if session_status == "success" and session_id:
529
- sessions = rs.get("sessions", [])
530
- if session_id not in sessions:
531
- sessions.append(session_id)
532
- rs["sessions"] = sessions
533
- rs["last_session_id"] = session_id
534
-
535
- rs["updated_at"] = now_iso()
536
-
537
- err = save_refactor_status(state_dir, refactor_id, rs)
538
- if err:
539
- error_out("Failed to save refactor status: {}".format(err))
540
- return
541
-
542
- # Auto-skip downstream refactors when this refactor is marked as failed or skipped
543
- auto_skipped_refactors = []
544
- if new_status in ("failed", "skipped"):
545
- auto_skipped_refactors = auto_skip_blocked_refactors(
546
- refactor_list_path, state_dir, refactor_id
547
- )
548
-
549
- summary = {
550
- "action": "update",
551
- "refactor_id": refactor_id,
552
- "session_status": session_status,
553
- "new_status": new_status,
554
- "retry_count": rs["retry_count"],
555
- "infra_error_count": rs.get("infra_error_count", 0),
556
- "max_infra_retries": max_infra_retries,
557
- "resume_from_phase": rs.get("resume_from_phase"),
558
- "updated_at": rs["updated_at"],
559
- }
560
- if auto_skipped_refactors:
561
- summary["auto_skipped"] = [info["refactor_id"] for info in auto_skipped_refactors]
562
- if session_status in ("commit_missing", "docs_missing", "merge_conflict"):
563
- summary["degraded_reason"] = session_status
564
- summary["restart_policy"] = "finalization_retry"
565
- elif session_status == "infra_error":
566
- summary["restart_policy"] = "infra_retry"
567
- summary["infra_error_count"] = rs.get("infra_error_count", 0)
568
- summary["artifacts_preserved"] = True
569
- elif session_status == "context_overflow":
570
- summary["restart_policy"] = "context_overflow_continuation"
571
- summary.update(continuation_metadata_summary(rs))
572
- summary["artifacts_preserved"] = True
573
- elif session_status == "stalled_context_continuation":
574
- summary["restart_policy"] = "needs_attention"
575
- summary.update(continuation_metadata_summary(rs))
576
- summary["artifacts_preserved"] = True
577
- elif session_status != "success":
578
- summary["restart_policy"] = "full_restart"
579
- summary["cleanup_performed"] = cleaned
580
-
581
- print(json.dumps(summary, indent=2, ensure_ascii=False))
582
-
583
-
584
- def _default_project_root():
585
- env = os.environ.get("PROJECT_ROOT")
586
- if env:
587
- return os.path.abspath(env)
588
- script_dir = os.path.dirname(os.path.abspath(__file__))
589
- pipeline_dir = os.path.dirname(script_dir)
590
- pipeline_parent = os.path.dirname(pipeline_dir)
591
- if os.path.basename(pipeline_parent) == ".prizmkit":
592
- return os.path.dirname(pipeline_parent)
593
- return pipeline_parent
594
-
595
-
596
- def cleanup_refactor_artifacts(state_dir, refactor_id, project_root=None):
597
- """Delete intermediate artifacts for a failed refactor run."""
598
- if not project_root:
599
- project_root = _default_project_root()
600
-
601
- cleaned = []
602
-
603
- # 1) Remove all session history
604
- sessions_dir = os.path.join(state_dir, refactor_id, "sessions")
605
- sessions_deleted = 0
606
- if os.path.isdir(sessions_dir):
607
- for entry in os.listdir(sessions_dir):
608
- entry_path = os.path.join(sessions_dir, entry)
609
- if os.path.isdir(entry_path):
610
- shutil.rmtree(entry_path)
611
- sessions_deleted += 1
612
- cleaned.append("Deleted {} session(s) from {}".format(sessions_deleted, sessions_dir))
613
-
614
- # 2) Remove transient files under refactor dir (keep status.json)
615
- refactor_dir = os.path.join(state_dir, refactor_id)
616
- if os.path.isdir(refactor_dir):
617
- for entry in os.listdir(refactor_dir):
618
- if entry == "status.json" or entry == "sessions":
619
- continue
620
- entry_path = os.path.join(refactor_dir, entry)
621
- if os.path.isdir(entry_path):
622
- shutil.rmtree(entry_path)
623
- cleaned.append("Deleted directory {}".format(entry_path))
624
- elif os.path.isfile(entry_path):
625
- os.remove(entry_path)
626
- cleaned.append("Deleted file {}".format(entry_path))
627
-
628
- # 3) Remove refactor artifacts
629
- refactor_artifact_dir = os.path.join(project_root, REFACTOR_ARTIFACTS_REL, refactor_id)
630
- if os.path.isdir(refactor_artifact_dir):
631
- shutil.rmtree(refactor_artifact_dir)
632
- cleaned.append("Deleted {}".format(refactor_artifact_dir))
633
-
634
- # 4) Remove shared dev-team workspace
635
- dev_team_dir = os.path.join(project_root, DEV_TEAM_DIR_NAME)
636
- if os.path.isdir(dev_team_dir):
637
- shutil.rmtree(dev_team_dir)
638
- cleaned.append("Deleted {}".format(dev_team_dir))
639
-
640
- return cleaned
641
-
642
-
643
- def _resolve_project_file(project_root, path):
644
- if not path:
645
- return None
646
- if os.path.isabs(path):
647
- target = os.path.abspath(path)
648
- else:
649
- target = os.path.abspath(os.path.join(project_root, path))
650
- root = os.path.abspath(project_root)
651
- try:
652
- rel = os.path.relpath(target, root)
653
- except ValueError:
654
- return None
655
- if rel == os.pardir or rel.startswith(os.pardir + os.sep):
656
- return None
657
- return target
658
-
659
-
660
- def cleanup_continuation_artifacts(project_root, status_data, candidate_paths=None):
661
- """Delete durable continuation handoff files for a manual clean reset."""
662
- candidates = []
663
- if isinstance(status_data, dict):
664
- candidates.append(status_data.get("continuation_summary_path"))
665
- candidates.extend(candidate_paths or [])
666
-
667
- cleaned = []
668
- seen = set()
669
- for candidate in candidates:
670
- target = _resolve_project_file(project_root, candidate)
671
- if not target or target in seen:
672
- continue
673
- seen.add(target)
674
- if os.path.basename(target) != "continuation-summary.md":
675
- continue
676
- if os.path.isfile(target):
677
- os.remove(target)
678
- cleaned.append("Deleted continuation artifact {}".format(target))
679
- return cleaned
680
-
681
-
682
- def load_session_status(state_dir, refactor_id, session_id):
683
- session_status_path = os.path.join(state_dir, refactor_id, "sessions",
684
- session_id, "session-status.json"
685
- )
686
- data, err = load_json_file(session_status_path)
687
- if err:
688
- return None, err
689
- return data, None
690
-
691
-
692
- # ---------------------------------------------------------------------------
693
- # Auto-skip: cascade failure to blocked downstream refactors
694
- # ---------------------------------------------------------------------------
695
-
696
- def auto_skip_blocked_refactors(refactor_list_path, state_dir, failed_refactor_id):
697
- """Recursively mark all downstream refactors blocked by a failed refactor as auto_skipped.
698
-
699
- When a refactor is marked as failed, any refactor whose dependency chain includes
700
- the failed refactor can never be executed. This function propagates the failure
701
- by marking those blocked refactors as auto_skipped, allowing the pipeline to
702
- continue processing unblocked refactors and eventually reach PIPELINE_COMPLETE.
703
-
704
- Re-reads .prizmkit/plans/refactor-list.json from disk to get the latest state (including the
705
- just-written failed status from update_refactor_in_list).
706
-
707
- NOTE: This function performs a read-modify-write on .prizmkit/plans/refactor-list.json without
708
- file locking. The caller (action_update) also writes to .prizmkit/plans/refactor-list.json
709
- immediately before calling this. Safe for single-pipeline execution, but if
710
- multiple pipeline instances share the same .prizmkit/plans/refactor-list.json concurrently,
711
- a race condition may cause lost writes. Add file locking if parallel pipelines
712
- are introduced.
713
- """
714
- data, err = load_json_file(refactor_list_path)
715
- if err:
716
- return []
717
- refactors = data.get("refactors", [])
718
-
719
- # Build current status map
720
- status_map = {}
721
- for r in refactors:
722
- if isinstance(r, dict) and r.get("id"):
723
- status_map[r["id"]] = r.get("status", "pending")
724
-
725
- # Collect all refactors to auto-skip (recursive propagation)
726
- to_skip = set()
727
- changed = True
728
- while changed:
729
- changed = False
730
- for r in refactors:
731
- if not isinstance(r, dict):
732
- continue
733
- rid = r.get("id")
734
- if not rid or rid in to_skip:
735
- continue
736
- current = status_map.get(rid, "pending")
737
- if current in TERMINAL_STATUSES:
738
- continue
739
- deps = r.get("dependencies", [])
740
- for dep_id in deps:
741
- dep_status = status_map.get(dep_id, "pending")
742
- if dep_status in ("failed", "skipped", "auto_skipped") or dep_id in to_skip:
743
- to_skip.add(rid)
744
- status_map[rid] = "auto_skipped"
745
- changed = True
746
- break
747
-
748
- if not to_skip:
749
- return []
750
-
751
- # Batch-write to .prizmkit/plans/refactor-list.json
752
- for r in refactors:
753
- if isinstance(r, dict) and r.get("id") in to_skip:
754
- r["status"] = "auto_skipped"
755
- write_json_file(refactor_list_path, data)
756
-
757
- # Update timestamps in status.json for each auto-skipped refactor
758
- for rid in to_skip:
759
- rs = load_refactor_status(state_dir, rid)
760
- rs["updated_at"] = now_iso()
761
- save_refactor_status(state_dir, rid, rs)
762
-
763
- # Build blocking reason map for logging
764
- skipped_info = []
765
- for r in refactors:
766
- if not isinstance(r, dict):
767
- continue
768
- rid = r.get("id")
769
- if rid not in to_skip:
770
- continue
771
- deps = r.get("dependencies", [])
772
- blockers = [
773
- d for d in deps
774
- if d == failed_refactor_id or d in to_skip
775
- ]
776
- skipped_info.append({
777
- "refactor_id": rid,
778
- "title": r.get("title", ""),
779
- "blocked_by": blockers,
780
- })
781
-
782
- print(
783
- "[auto-skip] {} refactor(s) auto-skipped due to failed {}:".format(
784
- len(skipped_info), failed_refactor_id
785
- ),
786
- file=sys.stderr,
787
- )
788
- for info in skipped_info:
789
- print(
790
- " {} ({}) — blocked by {}".format(
791
- info["refactor_id"],
792
- info["title"],
793
- ", ".join(info["blocked_by"]),
794
- ),
795
- file=sys.stderr,
796
- )
797
-
798
- return skipped_info
799
-
800
-
801
- # ---------------------------------------------------------------------------
802
- # Action: status
803
- # ---------------------------------------------------------------------------
804
-
805
- COLOR_GREEN = "\033[92m"
806
- COLOR_YELLOW = "\033[93m"
807
- COLOR_RED = "\033[91m"
808
- COLOR_GRAY = "\033[90m"
809
- COLOR_MAGENTA = "\033[95m"
810
- COLOR_CYAN = "\033[96m"
811
- COLOR_BOLD = "\033[1m"
812
- COLOR_RESET = "\033[0m"
813
-
814
- BOX_WIDTH = 72
815
-
816
- TYPE_ICONS = {
817
- "extract": "📦",
818
- "rename": "🏷️",
819
- "restructure": "🏗️",
820
- "simplify": "✂️",
821
- "decouple": "🔗",
822
- "migrate": "🚀",
823
- }
824
-
825
- COMPLEXITY_BADGES = {
826
- "low": COLOR_GREEN + "[LOW]" + COLOR_RESET,
827
- "medium": COLOR_YELLOW + "[MED]" + COLOR_RESET,
828
- "high": COLOR_RED + "[HI]" + COLOR_RESET,
829
- }
830
-
831
-
832
- def action_status(refactor_list_data, state_dir):
833
- refactors = refactor_list_data.get("refactors", [])
834
- project_name = refactor_list_data.get("project_name", "Unknown")
835
-
836
- counts = {"completed": 0, "in_progress": 0, "failed": 0, "pending": 0, "skipped": 0, "auto_skipped": 0}
837
- refactor_lines = []
838
-
839
- for r in refactors:
840
- if not isinstance(r, dict):
841
- continue
842
- rid = r.get("id")
843
- title = r.get("title", "Untitled")
844
- rtype = r.get("type", "restructure")
845
- complexity = r.get("complexity", "medium")
846
- if not rid:
847
- continue
848
-
849
- rstatus = r.get("status", "pending")
850
- rs = load_refactor_status(state_dir, rid)
851
- retry_count = rs.get("retry_count", 0)
852
- max_retries_val = rs.get("max_retries", 3)
853
- resume_phase = rs.get("resume_from_phase")
854
-
855
- if rstatus in counts:
856
- counts[rstatus] += 1
857
- else:
858
- counts["pending"] += 1
859
-
860
- # Status icon
861
- if rstatus == "completed":
862
- icon = COLOR_GREEN + "[✓]" + COLOR_RESET
863
- elif rstatus == "in_progress":
864
- icon = COLOR_YELLOW + "[→]" + COLOR_RESET
865
- elif rstatus == "failed":
866
- icon = COLOR_RED + "[✗]" + COLOR_RESET
867
- elif rstatus == "skipped":
868
- icon = COLOR_GRAY + "[—]" + COLOR_RESET
869
- elif rstatus == "auto_skipped":
870
- icon = COLOR_GRAY + "[⊘]" + COLOR_RESET
871
- else:
872
- icon = COLOR_GRAY + "[ ]" + COLOR_RESET
873
-
874
- # Type badge
875
- type_icon = TYPE_ICONS.get(rtype, "🔧")
876
- type_badge = "[{}]".format(rtype[:6].upper())
877
-
878
- # Complexity badge
879
- cmplx_badge = COMPLEXITY_BADGES.get(complexity, "[MED]")
880
-
881
- # Detail
882
- detail = ""
883
- if rstatus == "in_progress":
884
- parts = []
885
- if retry_count > 0:
886
- parts.append("retry {}/{}".format(retry_count, max_retries_val))
887
- if resume_phase is not None:
888
- parts.append("CP-RF-{}".format(resume_phase))
889
- if parts:
890
- detail = " ({})".format(", ".join(parts))
891
- elif rstatus == "failed":
892
- detail = " (failed after {} retries)".format(retry_count)
893
-
894
- # Colorize title based on status
895
- if rstatus == "completed":
896
- colored_title = COLOR_GREEN + title + COLOR_RESET
897
- elif rstatus == "in_progress":
898
- colored_title = COLOR_YELLOW + title + COLOR_RESET
899
- elif rstatus == "failed":
900
- colored_title = COLOR_RED + title + COLOR_RESET
901
- else:
902
- colored_title = COLOR_GRAY + title + COLOR_RESET
903
-
904
- line_content = "{} {} {} {} {} {} {}{}".format(
905
- rid, icon, type_badge, cmplx_badge, type_icon, colored_title, "", detail
906
- )
907
-
908
- refactor_lines.append(line_content)
909
-
910
- total = len(refactors)
911
- completed = counts["completed"]
912
- percent = round(completed / total * 100, 1) if total > 0 else 0.0
913
- progress_bar = _build_progress_bar(percent, width=24)
914
-
915
- summary_line = "Total: {} refactors | Completed: {} | In Progress: {}".format(
916
- total, completed, counts["in_progress"]
917
- )
918
- summary_line2 = "Failed: {} | Pending: {} | Skipped: {} | Auto-skipped: {}".format(
919
- counts["failed"], counts["pending"], counts["skipped"], counts["auto_skipped"]
920
- )
921
-
922
- inner = BOX_WIDTH - 2
923
- print("╔" + "═" * BOX_WIDTH + "╗")
924
- print("║" + pad_right(COLOR_BOLD + " Refactor Pipeline Status" + COLOR_RESET, inner) + " ║")
925
- print("╠" + "═" * BOX_WIDTH + "╣")
926
- print("║" + pad_right(" Project: {}".format(project_name), inner) + " ║")
927
- print("║" + pad_right(" {}".format(summary_line), inner) + " ║")
928
- print("║" + pad_right(" {}".format(summary_line2), inner) + " ║")
929
- print("╠" + "─" * BOX_WIDTH + "╣")
930
- print("║" + pad_right(" Progress: {}".format(progress_bar), inner) + " ║")
931
- print("╠" + "═" * BOX_WIDTH + "╣")
932
- for line in refactor_lines:
933
- print("║" + pad_right(" {}".format(line), inner) + " ║")
934
- print("╚" + "═" * BOX_WIDTH + "╝")
935
-
936
-
937
- # ---------------------------------------------------------------------------
938
- # Action: reset
939
- # ---------------------------------------------------------------------------
940
-
941
- def action_reset(args, refactor_list_path, state_dir):
942
- refactor_id = args.refactor_id
943
- if not refactor_id:
944
- error_out("--refactor-id is required for 'reset' action")
945
- return
946
-
947
- rs = load_refactor_status(state_dir, refactor_id)
948
- old_status = get_refactor_status_from_list(refactor_list_path, refactor_id)
949
- old_retry = rs.get("retry_count", 0)
950
-
951
- rs["retry_count"] = 0
952
- rs["infra_error_count"] = 0
953
- rs["last_infra_error_session_id"] = None
954
- rs["sessions"] = []
955
- rs["last_session_id"] = None
956
- rs["resume_from_phase"] = None
957
- reset_continuation_metadata(rs)
958
- rs["updated_at"] = now_iso()
959
-
960
- err = save_refactor_status(state_dir, refactor_id, rs)
961
- if err:
962
- error_out("Failed to save refactor status: {}".format(err))
963
- return
964
-
965
- err = update_refactor_in_list(refactor_list_path, refactor_id, "pending")
966
- if err:
967
- error_out("Failed to update .prizmkit/plans/refactor-list.json: {}".format(err))
968
- return
969
-
970
- result = {
971
- "action": "reset",
972
- "refactor_id": refactor_id,
973
- "old_status": old_status,
974
- "old_retry_count": old_retry,
975
- "new_status": "pending",
976
- }
977
- print(json.dumps(result, indent=2, ensure_ascii=False))
978
-
979
-
980
- # ---------------------------------------------------------------------------
981
- # Action: clean
982
- # ---------------------------------------------------------------------------
983
-
984
- def action_clean(args, refactor_list_path, state_dir):
985
- refactor_id = args.refactor_id
986
- project_root = args.project_root
987
-
988
- if not refactor_id:
989
- error_out("--refactor-id is required for 'clean' action")
990
- return
991
- if not project_root:
992
- error_out("--project-root is required for 'clean' action")
993
- return
994
-
995
- cleaned = []
996
-
997
- # 1. Delete session history
998
- sessions_dir = os.path.join(state_dir, refactor_id, "sessions")
999
- sessions_deleted = 0
1000
- if os.path.isdir(sessions_dir):
1001
- for entry in os.listdir(sessions_dir):
1002
- entry_path = os.path.join(sessions_dir, entry)
1003
- if os.path.isdir(entry_path):
1004
- shutil.rmtree(entry_path)
1005
- sessions_deleted += 1
1006
- cleaned.append("Deleted {} session(s) from {}".format(sessions_deleted, sessions_dir))
1007
-
1008
- # 2. Delete refactor artifacts for this refactor
1009
- refactor_artifact_dir = os.path.join(project_root, REFACTOR_ARTIFACTS_REL, refactor_id)
1010
- if os.path.isdir(refactor_artifact_dir):
1011
- shutil.rmtree(refactor_artifact_dir)
1012
- cleaned.append("Deleted {}".format(refactor_artifact_dir))
1013
-
1014
- # 3. Delete shared dev-team workspace
1015
- dev_team_dir = os.path.join(project_root, DEV_TEAM_DIR_NAME)
1016
- if os.path.isdir(dev_team_dir):
1017
- shutil.rmtree(dev_team_dir)
1018
- cleaned.append("Deleted {}".format(dev_team_dir))
1019
-
1020
- # 4. Reset status
1021
- rs = load_refactor_status(state_dir, refactor_id)
1022
- old_status = get_refactor_status_from_list(refactor_list_path, refactor_id)
1023
- old_retry = rs.get("retry_count", 0)
1024
-
1025
- continuation_candidates = [
1026
- os.path.join(".prizmkit", "refactor", refactor_id, "continuation-summary.md"),
1027
- os.path.join(".prizmkit", "specs", refactor_id, "continuation-summary.md"),
1028
- ]
1029
- cleaned.extend(cleanup_continuation_artifacts(project_root, rs, continuation_candidates))
1030
-
1031
- rs["retry_count"] = 0
1032
- rs["infra_error_count"] = 0
1033
- rs["last_infra_error_session_id"] = None
1034
- rs["sessions"] = []
1035
- rs["last_session_id"] = None
1036
- rs["resume_from_phase"] = None
1037
- reset_continuation_metadata(rs)
1038
- rs["updated_at"] = now_iso()
1039
-
1040
- err = save_refactor_status(state_dir, refactor_id, rs)
1041
- if err:
1042
- error_out("Failed to save refactor status: {}".format(err))
1043
- return
1044
-
1045
- err = update_refactor_in_list(refactor_list_path, refactor_id, "pending")
1046
- if err:
1047
- error_out("Failed to update .prizmkit/plans/refactor-list.json: {}".format(err))
1048
- return
1049
-
1050
- result = {
1051
- "action": "clean",
1052
- "refactor_id": refactor_id,
1053
- "old_status": old_status,
1054
- "old_retry_count": old_retry,
1055
- "new_status": "pending",
1056
- "sessions_deleted": sessions_deleted,
1057
- "cleaned": cleaned,
1058
- }
1059
- print(json.dumps(result, indent=2, ensure_ascii=False))
1060
-
1061
-
1062
- # ---------------------------------------------------------------------------
1063
- # Action: pause
1064
- # ---------------------------------------------------------------------------
1065
-
1066
- def action_pause(state_dir):
1067
- pipeline_path = os.path.join(state_dir, "pipeline.json")
1068
- data, err = load_json_file(pipeline_path)
1069
- if err:
1070
- data = {"status": "paused", "paused_at": now_iso()}
1071
- else:
1072
- data["status"] = "paused"
1073
- data["paused_at"] = now_iso()
1074
-
1075
- err = write_json_file(pipeline_path, data)
1076
- if err:
1077
- error_out("Failed to write pipeline.json: {}".format(err))
1078
- return
1079
-
1080
- result = {
1081
- "action": "pause",
1082
- "status": "paused",
1083
- "paused_at": data["paused_at"],
1084
- }
1085
- print(json.dumps(result, indent=2, ensure_ascii=False))
1086
-
1087
-
1088
- # ---------------------------------------------------------------------------
1089
- # Action: start
1090
- # ---------------------------------------------------------------------------
1091
-
1092
- def action_start(args, refactor_list_path, state_dir):
1093
- """Mark a refactor as in_progress when a session starts.
1094
-
1095
- This keeps refactor-list.json/state status in sync during execution,
1096
- instead of only updating after session end.
1097
- """
1098
- refactor_id = args.refactor_id
1099
- if not refactor_id:
1100
- error_out("--refactor-id is required for 'start' action")
1101
- return
1102
-
1103
- rs = load_refactor_status(state_dir, refactor_id)
1104
- old_status = get_refactor_status_from_list(refactor_list_path, refactor_id)
1105
-
1106
- rs["updated_at"] = now_iso()
1107
-
1108
- err = save_refactor_status(state_dir, refactor_id, rs)
1109
- if err:
1110
- error_out("Failed to save refactor status: {}".format(err))
1111
- return
1112
-
1113
- if old_status != "in_progress":
1114
- err = update_refactor_in_list(refactor_list_path, refactor_id, "in_progress")
1115
- if err:
1116
- error_out("Failed to update .prizmkit/plans/refactor-list.json: {}".format(err))
1117
- return
1118
-
1119
- result = {
1120
- "action": "start",
1121
- "refactor_id": refactor_id,
1122
- "old_status": old_status,
1123
- "new_status": "in_progress",
1124
- "retry_count": rs.get("retry_count", 0),
1125
- "infra_error_count": rs.get("infra_error_count", 0),
1126
- "updated_at": rs["updated_at"],
1127
- }
1128
- print(json.dumps(result, indent=2, ensure_ascii=False))
1129
-
1130
-
1131
- # ---------------------------------------------------------------------------
1132
- # Action: unskip
1133
- # ---------------------------------------------------------------------------
1134
-
1135
- def action_unskip(args, refactor_list_path, state_dir):
1136
- """Recover skipped/auto_skipped/failed refactors by resetting them and their failed upstream.
1137
-
1138
- Two modes:
1139
- - --refactor-id R-001: Reset the specified failed/skipped/auto_skipped refactor + all
1140
- downstream auto_skipped refactors whose dependency chain includes it.
1141
- If the target is auto_skipped, also walk upstream to find and reset the
1142
- failed/skipped ancestor that caused the cascade.
1143
- - No --refactor-id: Reset ALL failed, skipped, and auto_skipped refactors to pending.
1144
- """
1145
- refactor_id = args.refactor_id
1146
-
1147
- data, err = load_json_file(refactor_list_path)
1148
- if err:
1149
- error_out("Cannot load refactor list: {}".format(err))
1150
- return
1151
- refactors = data.get("refactors", [])
1152
-
1153
- to_reset = set()
1154
-
1155
- if refactor_id:
1156
- # Find the target refactor
1157
- target = None
1158
- for r in refactors:
1159
- if isinstance(r, dict) and r.get("id") == refactor_id:
1160
- target = r
1161
- break
1162
- if not target:
1163
- error_out("Refactor '{}' not found in .prizmkit/plans/refactor-list.json".format(refactor_id))
1164
- return
1165
- if target.get("status") not in ("failed", "skipped", "auto_skipped"):
1166
- error_out(
1167
- "Refactor '{}' has status '{}', expected 'failed', 'skipped', or 'auto_skipped'".format(
1168
- refactor_id, target.get("status", "unknown")
1169
- )
1170
- )
1171
- return
1172
-
1173
- # If target is failed or skipped, reset it and find all auto_skipped descendants
1174
- if target.get("status") in ("failed", "skipped"):
1175
- to_reset.add(refactor_id)
1176
- # Find all auto_skipped refactors that depend (transitively) on this one
1177
- changed = True
1178
- while changed:
1179
- changed = False
1180
- for r in refactors:
1181
- if not isinstance(r, dict):
1182
- continue
1183
- rid = r.get("id")
1184
- if not rid or rid in to_reset:
1185
- continue
1186
- if r.get("status") != "auto_skipped":
1187
- continue
1188
- deps = r.get("dependencies", [])
1189
- if any(d in to_reset for d in deps):
1190
- to_reset.add(rid)
1191
- changed = True
1192
-
1193
- # If target is auto_skipped, reset it and its failed upstream + siblings
1194
- elif target.get("status") == "auto_skipped":
1195
- to_reset.add(refactor_id)
1196
- # Transitively walk upstream to find ALL failed/auto_skipped ancestors
1197
- # (e.g., R-001 failed → R-002 auto_skipped → R-003 auto_skipped;
1198
- # unskip R-003 must also find and reset R-001)
1199
- upstream_changed = True
1200
- while upstream_changed:
1201
- upstream_changed = False
1202
- for r in refactors:
1203
- if not isinstance(r, dict):
1204
- continue
1205
- rid = r.get("id")
1206
- if not rid or rid not in to_reset:
1207
- continue
1208
- for dep_id in r.get("dependencies", []):
1209
- if dep_id in to_reset:
1210
- continue
1211
- for dep_r in refactors:
1212
- if isinstance(dep_r, dict) and dep_r.get("id") == dep_id:
1213
- if dep_r.get("status") in ("failed", "skipped", "auto_skipped"):
1214
- to_reset.add(dep_id)
1215
- upstream_changed = True
1216
- # Also reset downstream auto_skipped refactors blocked by the same upstreams
1217
- changed = True
1218
- while changed:
1219
- changed = False
1220
- for r in refactors:
1221
- if not isinstance(r, dict):
1222
- continue
1223
- rid = r.get("id")
1224
- if not rid or rid in to_reset:
1225
- continue
1226
- if r.get("status") != "auto_skipped":
1227
- continue
1228
- rdeps = r.get("dependencies", [])
1229
- if any(d in to_reset for d in rdeps):
1230
- to_reset.add(rid)
1231
- changed = True
1232
- else:
1233
- # No refactor-id: reset ALL failed + skipped + auto_skipped
1234
- for r in refactors:
1235
- if isinstance(r, dict) and r.get("id"):
1236
- if r.get("status") in ("failed", "skipped", "auto_skipped"):
1237
- to_reset.add(r["id"])
1238
-
1239
- if not to_reset:
1240
- error_out("No refactors to unskip")
1241
- return
1242
-
1243
- # Reset all collected refactors in refactor-list.json
1244
- reset_details = []
1245
- for r in refactors:
1246
- if isinstance(r, dict) and r.get("id") in to_reset:
1247
- old_status = r.get("status", "unknown")
1248
- r["status"] = "pending"
1249
- reset_details.append({
1250
- "refactor_id": r["id"],
1251
- "title": r.get("title", ""),
1252
- "old_status": old_status,
1253
- })
1254
-
1255
- err = write_json_file(refactor_list_path, data)
1256
- if err:
1257
- error_out("Failed to write .prizmkit/plans/refactor-list.json: {}".format(err))
1258
- return
1259
-
1260
- # Reset runtime fields in status.json for each refactor
1261
- for rid in to_reset:
1262
- rs = load_refactor_status(state_dir, rid)
1263
- rs["retry_count"] = 0
1264
- rs["infra_error_count"] = 0
1265
- rs["last_infra_error_session_id"] = None
1266
- rs["sessions"] = []
1267
- rs["last_session_id"] = None
1268
- rs["resume_from_phase"] = None
1269
- reset_continuation_metadata(rs)
1270
- rs["updated_at"] = now_iso()
1271
- save_refactor_status(state_dir, rid, rs)
1272
-
1273
- result = {
1274
- "action": "unskip",
1275
- "reset_count": len(to_reset),
1276
- "refactors": reset_details,
1277
- }
1278
- print(json.dumps(result, indent=2, ensure_ascii=False))
1279
-
1280
-
1281
- # ---------------------------------------------------------------------------
1282
- # Main
1283
- # ---------------------------------------------------------------------------
1284
-
1285
- def main():
1286
- args = parse_args()
1287
-
1288
- if args.action == "update":
1289
- if not args.refactor_id:
1290
- error_out("--refactor-id is required for 'update' action")
1291
- if not args.session_status:
1292
- error_out("--session-status is required for 'update' action")
1293
- if args.action in ("start", "reset", "clean", "complete"):
1294
- if not args.refactor_id:
1295
- error_out("--refactor-id is required for '{}' action".format(args.action))
1296
- if args.action == "clean":
1297
- if not args.project_root:
1298
- error_out("--project-root is required for 'clean' action")
1299
-
1300
- refactor_list_data, err = load_json_file(args.refactor_list)
1301
- if err:
1302
- error_out("Cannot load refactor list: {}".format(err))
1303
-
1304
- if args.action == "get_next":
1305
- action_get_next(refactor_list_data, args.state_dir)
1306
- elif args.action == "update":
1307
- action_update(args, args.refactor_list, args.state_dir)
1308
- elif args.action == "status":
1309
- action_status(refactor_list_data, args.state_dir)
1310
- elif args.action == "reset":
1311
- action_reset(args, args.refactor_list, args.state_dir)
1312
- elif args.action == "clean":
1313
- action_clean(args, args.refactor_list, args.state_dir)
1314
- elif args.action == "start":
1315
- action_start(args, args.refactor_list, args.state_dir)
1316
- elif args.action == "pause":
1317
- action_pause(args.state_dir)
1318
- elif args.action == "unskip":
1319
- action_unskip(args, args.refactor_list, args.state_dir)
1320
- elif args.action == "complete":
1321
- # Shortcut: 'complete' is equivalent to 'update --session-status success'
1322
- args.session_status = "success"
1323
- action_update(args, args.refactor_list, args.state_dir)
1324
-
1325
-
1326
- if __name__ == "__main__":
1327
- main()