prizmkit 1.1.100 → 1.1.101

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (309) hide show
  1. package/bin/create-prizmkit.js +4 -4
  2. package/bundled/VERSION.json +3 -3
  3. package/bundled/dev-pipeline/.env.example +3 -3
  4. package/bundled/dev-pipeline/README.md +110 -90
  5. package/bundled/dev-pipeline/assets/prizm-dev-team-integration.md +1 -1
  6. package/bundled/dev-pipeline/cli.py +27 -0
  7. package/bundled/dev-pipeline/prizmkit_runtime/__init__.py +13 -0
  8. package/bundled/dev-pipeline/prizmkit_runtime/__main__.py +9 -0
  9. package/bundled/dev-pipeline/prizmkit_runtime/cli.py +193 -0
  10. package/bundled/dev-pipeline/prizmkit_runtime/commands.py +313 -0
  11. package/bundled/dev-pipeline/prizmkit_runtime/compat.py +32 -0
  12. package/bundled/dev-pipeline/prizmkit_runtime/config.py +410 -0
  13. package/bundled/dev-pipeline/prizmkit_runtime/daemon.py +478 -0
  14. package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +734 -0
  15. package/bundled/dev-pipeline/prizmkit_runtime/heartbeat.py +256 -0
  16. package/bundled/dev-pipeline/prizmkit_runtime/interoperability.py +109 -0
  17. package/bundled/dev-pipeline/prizmkit_runtime/paths.py +110 -0
  18. package/bundled/dev-pipeline/prizmkit_runtime/processes.py +373 -0
  19. package/bundled/dev-pipeline/prizmkit_runtime/reset.py +389 -0
  20. package/bundled/dev-pipeline/prizmkit_runtime/runner_bookkeeping.py +51 -0
  21. package/bundled/dev-pipeline/prizmkit_runtime/runner_classification.py +179 -0
  22. package/bundled/dev-pipeline/prizmkit_runtime/runner_models.py +345 -0
  23. package/bundled/dev-pipeline/prizmkit_runtime/runner_prompts.py +118 -0
  24. package/bundled/dev-pipeline/prizmkit_runtime/runner_recovery.py +187 -0
  25. package/bundled/dev-pipeline/prizmkit_runtime/runner_status.py +147 -0
  26. package/bundled/dev-pipeline/prizmkit_runtime/runners.py +422 -0
  27. package/bundled/dev-pipeline/prizmkit_runtime/sessions.py +552 -0
  28. package/bundled/dev-pipeline/prizmkit_runtime/status.py +71 -0
  29. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +38 -23
  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 +7 -1
  34. package/bundled/dev-pipeline/templates/bootstrap-prompt.md +4 -0
  35. package/bundled/dev-pipeline/templates/bootstrap-tier1.md +12 -3
  36. package/bundled/dev-pipeline/templates/bootstrap-tier2.md +13 -3
  37. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +13 -3
  38. package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +2 -0
  39. package/bundled/dev-pipeline/templates/sections/log-size-awareness.md +9 -30
  40. package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-agent-suffix.md +15 -7
  41. package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +42 -29
  42. package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +41 -39
  43. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-agent.md +4 -0
  44. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-lite.md +4 -0
  45. package/bundled/dev-pipeline/tests/test_auto_skip.py +436 -14
  46. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +104 -0
  47. package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +40 -0
  48. package/bundled/dev-pipeline/tests/test_python_runner_parity.py +1138 -0
  49. package/bundled/dev-pipeline/tests/test_unified_cli.py +1045 -0
  50. package/bundled/skills/_metadata.json +1 -1
  51. package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +29 -34
  52. package/bundled/skills/bugfix-pipeline-launcher/references/configuration.md +6 -5
  53. package/bundled/skills/feature-pipeline-launcher/SKILL.md +29 -35
  54. package/bundled/skills/feature-pipeline-launcher/references/configuration.md +7 -6
  55. package/bundled/skills/feature-workflow/SKILL.md +3 -6
  56. package/bundled/skills/recovery-workflow/SKILL.md +23 -32
  57. package/bundled/skills/refactor-pipeline-launcher/SKILL.md +29 -35
  58. package/bundled/skills/refactor-pipeline-launcher/references/configuration.md +7 -6
  59. package/bundled/skills/refactor-workflow/SKILL.md +3 -6
  60. package/bundled/templates/hooks/commit-intent.json +2 -2
  61. package/bundled/templates/hooks/diff-prizm-docs.py +226 -0
  62. package/bundled/templates/hooks/prizm-pre-commit.py +45 -0
  63. package/bundled/templates/hooks/validate-prizm-docs.py +240 -0
  64. package/package.json +1 -1
  65. package/src/config.js +33 -12
  66. package/src/index.js +3 -6
  67. package/src/manifest.js +3 -2
  68. package/src/metadata.js +7 -18
  69. package/src/prompts.js +0 -12
  70. package/src/runtimes.js +18 -11
  71. package/src/scaffold.js +133 -116
  72. package/src/upgrade.js +1 -1
  73. package/bundled/dev-pipeline/launch-bugfix-daemon.sh +0 -500
  74. package/bundled/dev-pipeline/launch-feature-daemon.sh +0 -657
  75. package/bundled/dev-pipeline/launch-refactor-daemon.sh +0 -502
  76. package/bundled/dev-pipeline/lib/branch.sh +0 -326
  77. package/bundled/dev-pipeline/lib/common.sh +0 -1476
  78. package/bundled/dev-pipeline/lib/heartbeat.sh +0 -469
  79. package/bundled/dev-pipeline/reset-bug.sh +0 -425
  80. package/bundled/dev-pipeline/reset-feature.sh +0 -436
  81. package/bundled/dev-pipeline/reset-refactor.sh +0 -423
  82. package/bundled/dev-pipeline/run-bugfix.sh +0 -1430
  83. package/bundled/dev-pipeline/run-feature.sh +0 -1718
  84. package/bundled/dev-pipeline/run-recovery.sh +0 -648
  85. package/bundled/dev-pipeline/run-refactor.sh +0 -1463
  86. package/bundled/dev-pipeline/tests/test-path-resolution.sh +0 -100
  87. package/bundled/dev-pipeline-windows/.env.example +0 -36
  88. package/bundled/dev-pipeline-windows/README.md +0 -30
  89. package/bundled/dev-pipeline-windows/SCHEMA_ANALYSIS.md +0 -533
  90. package/bundled/dev-pipeline-windows/assets/feature-list-example.json +0 -146
  91. package/bundled/dev-pipeline-windows/assets/prizm-dev-team-integration.md +0 -137
  92. package/bundled/dev-pipeline-windows/launch-bugfix-daemon.ps1 +0 -9
  93. package/bundled/dev-pipeline-windows/launch-feature-daemon.ps1 +0 -9
  94. package/bundled/dev-pipeline-windows/launch-refactor-daemon.ps1 +0 -9
  95. package/bundled/dev-pipeline-windows/lib/branch.ps1 +0 -235
  96. package/bundled/dev-pipeline-windows/lib/common.ps1 +0 -991
  97. package/bundled/dev-pipeline-windows/lib/daemon.ps1 +0 -140
  98. package/bundled/dev-pipeline-windows/lib/pipeline.ps1 +0 -1051
  99. package/bundled/dev-pipeline-windows/lib/reset.ps1 +0 -121
  100. package/bundled/dev-pipeline-windows/reset-bug.ps1 +0 -10
  101. package/bundled/dev-pipeline-windows/reset-feature.ps1 +0 -10
  102. package/bundled/dev-pipeline-windows/reset-refactor.ps1 +0 -10
  103. package/bundled/dev-pipeline-windows/run-bugfix.ps1 +0 -9
  104. package/bundled/dev-pipeline-windows/run-feature.ps1 +0 -9
  105. package/bundled/dev-pipeline-windows/run-recovery.ps1 +0 -179
  106. package/bundled/dev-pipeline-windows/run-refactor.ps1 +0 -9
  107. package/bundled/dev-pipeline-windows/scripts/check-session-status.py +0 -301
  108. package/bundled/dev-pipeline-windows/scripts/continuation.py +0 -374
  109. package/bundled/dev-pipeline-windows/scripts/detect-stuck.py +0 -530
  110. package/bundled/dev-pipeline-windows/scripts/generate-bootstrap-prompt.py +0 -2279
  111. package/bundled/dev-pipeline-windows/scripts/generate-bugfix-prompt.py +0 -763
  112. package/bundled/dev-pipeline-windows/scripts/generate-recovery-prompt.py +0 -805
  113. package/bundled/dev-pipeline-windows/scripts/generate-refactor-prompt.py +0 -841
  114. package/bundled/dev-pipeline-windows/scripts/init-bugfix-pipeline.py +0 -316
  115. package/bundled/dev-pipeline-windows/scripts/init-dev-team.py +0 -134
  116. package/bundled/dev-pipeline-windows/scripts/init-pipeline.py +0 -382
  117. package/bundled/dev-pipeline-windows/scripts/init-refactor-pipeline.py +0 -399
  118. package/bundled/dev-pipeline-windows/scripts/parse-stream-progress.py +0 -1362
  119. package/bundled/dev-pipeline-windows/scripts/patch-completion-notes.py +0 -191
  120. package/bundled/dev-pipeline-windows/scripts/prizmkit-test-gate.py +0 -446
  121. package/bundled/dev-pipeline-windows/scripts/update-bug-status.py +0 -1121
  122. package/bundled/dev-pipeline-windows/scripts/update-checkpoint.py +0 -173
  123. package/bundled/dev-pipeline-windows/scripts/update-feature-status.py +0 -1789
  124. package/bundled/dev-pipeline-windows/scripts/update-refactor-status.py +0 -1327
  125. package/bundled/dev-pipeline-windows/scripts/utils.py +0 -542
  126. package/bundled/dev-pipeline-windows/templates/agent-prompts/critic-plan-challenge.md +0 -7
  127. package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-fix.md +0 -7
  128. package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-implement.md +0 -65
  129. package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-resume.md +0 -5
  130. package/bundled/dev-pipeline-windows/templates/agent-prompts/reviewer-review.md +0 -7
  131. package/bundled/dev-pipeline-windows/templates/bootstrap-prompt.md +0 -73
  132. package/bundled/dev-pipeline-windows/templates/bootstrap-tier1.md +0 -589
  133. package/bundled/dev-pipeline-windows/templates/bootstrap-tier2.md +0 -710
  134. package/bundled/dev-pipeline-windows/templates/bootstrap-tier3.md +0 -791
  135. package/bundled/dev-pipeline-windows/templates/bug-fix-list-schema.json +0 -263
  136. package/bundled/dev-pipeline-windows/templates/bugfix-bootstrap-prompt.md +0 -326
  137. package/bundled/dev-pipeline-windows/templates/feature-list-schema.json +0 -237
  138. package/bundled/dev-pipeline-windows/templates/refactor-bootstrap-prompt.md +0 -340
  139. package/bundled/dev-pipeline-windows/templates/refactor-list-schema.json +0 -270
  140. package/bundled/dev-pipeline-windows/templates/sections/ac-verification-checklist.md +0 -7
  141. package/bundled/dev-pipeline-windows/templates/sections/checkpoint-system.md +0 -91
  142. package/bundled/dev-pipeline-windows/templates/sections/context-budget-rules.md +0 -34
  143. package/bundled/dev-pipeline-windows/templates/sections/critical-paths-agent.md +0 -10
  144. package/bundled/dev-pipeline-windows/templates/sections/critical-paths-full.md +0 -12
  145. package/bundled/dev-pipeline-windows/templates/sections/critical-paths-lite.md +0 -7
  146. package/bundled/dev-pipeline-windows/templates/sections/directory-convention-agent.md +0 -8
  147. package/bundled/dev-pipeline-windows/templates/sections/directory-convention-full.md +0 -9
  148. package/bundled/dev-pipeline-windows/templates/sections/directory-convention-lite.md +0 -6
  149. package/bundled/dev-pipeline-windows/templates/sections/failure-capture.md +0 -21
  150. package/bundled/dev-pipeline-windows/templates/sections/feature-context.md +0 -21
  151. package/bundled/dev-pipeline-windows/templates/sections/log-size-awareness.md +0 -41
  152. package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification-auto.md +0 -283
  153. package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification-opencli.md +0 -112
  154. package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification.md +0 -168
  155. package/bundled/dev-pipeline-windows/templates/sections/phase-commit-full.md +0 -82
  156. package/bundled/dev-pipeline-windows/templates/sections/phase-commit.md +0 -75
  157. package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-agent-suffix.md +0 -23
  158. package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-base.md +0 -14
  159. package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-lite-suffix.md +0 -19
  160. package/bundled/dev-pipeline-windows/templates/sections/phase-critic-plan-full.md +0 -63
  161. package/bundled/dev-pipeline-windows/templates/sections/phase-critic-plan.md +0 -42
  162. package/bundled/dev-pipeline-windows/templates/sections/phase-implement-agent.md +0 -44
  163. package/bundled/dev-pipeline-windows/templates/sections/phase-implement-full.md +0 -59
  164. package/bundled/dev-pipeline-windows/templates/sections/phase-implement-lite.md +0 -39
  165. package/bundled/dev-pipeline-windows/templates/sections/phase-plan-agent.md +0 -27
  166. package/bundled/dev-pipeline-windows/templates/sections/phase-plan-lite.md +0 -27
  167. package/bundled/dev-pipeline-windows/templates/sections/phase-prizmkit-test.md +0 -39
  168. package/bundled/dev-pipeline-windows/templates/sections/phase-review-agent.md +0 -35
  169. package/bundled/dev-pipeline-windows/templates/sections/phase-review-full.md +0 -35
  170. package/bundled/dev-pipeline-windows/templates/sections/phase-specify-plan-full.md +0 -73
  171. package/bundled/dev-pipeline-windows/templates/sections/phase0-init.md +0 -13
  172. package/bundled/dev-pipeline-windows/templates/sections/phase0-test-baseline.md +0 -21
  173. package/bundled/dev-pipeline-windows/templates/sections/session-context.md +0 -5
  174. package/bundled/dev-pipeline-windows/templates/sections/subagent-timeout-recovery.md +0 -6
  175. package/bundled/dev-pipeline-windows/templates/sections/task-contract.md +0 -34
  176. package/bundled/dev-pipeline-windows/templates/sections/test-failure-recovery-agent.md +0 -48
  177. package/bundled/dev-pipeline-windows/templates/sections/test-failure-recovery-lite.md +0 -48
  178. package/bundled/dev-pipeline-windows/templates/session-status-schema.json +0 -83
  179. package/bundled/skills-windows/app-planner/SKILL.md +0 -296
  180. package/bundled/skills-windows/app-planner/assets/app-design-guide.md +0 -101
  181. package/bundled/skills-windows/app-planner/references/architecture-decisions.md +0 -52
  182. package/bundled/skills-windows/app-planner/references/brainstorm-guide.md +0 -101
  183. package/bundled/skills-windows/app-planner/references/frontend-design-guide.md +0 -71
  184. package/bundled/skills-windows/app-planner/references/infrastructure-convention-discovery.md +0 -108
  185. package/bundled/skills-windows/app-planner/references/project-brief-guide.md +0 -82
  186. package/bundled/skills-windows/app-planner/references/project-conventions-discovery.md +0 -59
  187. package/bundled/skills-windows/app-planner/references/project-state-detection.md +0 -90
  188. package/bundled/skills-windows/app-planner/references/red-team-checklist.md +0 -40
  189. package/bundled/skills-windows/app-planner/references/rules/backend/derivation-rules.md +0 -619
  190. package/bundled/skills-windows/app-planner/references/rules/backend/fixed-rules.md +0 -285
  191. package/bundled/skills-windows/app-planner/references/rules/backend/question-bank.md +0 -249
  192. package/bundled/skills-windows/app-planner/references/rules/backend/question-manifest.json +0 -46
  193. package/bundled/skills-windows/app-planner/references/rules/backend/template.md +0 -173
  194. package/bundled/skills-windows/app-planner/references/rules/database/derivation-rules.md +0 -382
  195. package/bundled/skills-windows/app-planner/references/rules/database/fixed-rules.md +0 -211
  196. package/bundled/skills-windows/app-planner/references/rules/database/question-bank.md +0 -184
  197. package/bundled/skills-windows/app-planner/references/rules/database/question-manifest.json +0 -39
  198. package/bundled/skills-windows/app-planner/references/rules/database/template.md +0 -158
  199. package/bundled/skills-windows/app-planner/references/rules/frontend/derivation-rules.md +0 -820
  200. package/bundled/skills-windows/app-planner/references/rules/frontend/fixed-rules.md +0 -188
  201. package/bundled/skills-windows/app-planner/references/rules/frontend/question-bank.md +0 -319
  202. package/bundled/skills-windows/app-planner/references/rules/frontend/question-manifest.json +0 -51
  203. package/bundled/skills-windows/app-planner/references/rules/frontend/template.md +0 -339
  204. package/bundled/skills-windows/app-planner/references/rules/mobile/derivation-rules.md +0 -649
  205. package/bundled/skills-windows/app-planner/references/rules/mobile/fixed-rules.md +0 -290
  206. package/bundled/skills-windows/app-planner/references/rules/mobile/question-bank.md +0 -232
  207. package/bundled/skills-windows/app-planner/references/rules/mobile/question-manifest.json +0 -47
  208. package/bundled/skills-windows/app-planner/references/rules/mobile/template.md +0 -175
  209. package/bundled/skills-windows/app-planner/references/rules-configuration.md +0 -46
  210. package/bundled/skills-windows/bug-fix-workflow/SKILL.md +0 -379
  211. package/bundled/skills-windows/bug-fix-workflow/references/bug-diagnosis.md +0 -41
  212. package/bundled/skills-windows/bug-planner/SKILL.md +0 -402
  213. package/bundled/skills-windows/bug-planner/assets/bug-confirmation-template.md +0 -43
  214. package/bundled/skills-windows/bug-planner/references/critic-and-verification.md +0 -44
  215. package/bundled/skills-windows/bug-planner/references/error-recovery.md +0 -73
  216. package/bundled/skills-windows/bug-planner/references/input-formats.md +0 -53
  217. package/bundled/skills-windows/bug-planner/references/schema-validation.md +0 -25
  218. package/bundled/skills-windows/bug-planner/references/severity-rules.md +0 -16
  219. package/bundled/skills-windows/bug-planner/scripts/validate-bug-list.py +0 -322
  220. package/bundled/skills-windows/bugfix-pipeline-launcher/SKILL.md +0 -304
  221. package/bundled/skills-windows/bugfix-pipeline-launcher/references/configuration.md +0 -84
  222. package/bundled/skills-windows/feature-pipeline-launcher/SKILL.md +0 -381
  223. package/bundled/skills-windows/feature-pipeline-launcher/references/configuration.md +0 -67
  224. package/bundled/skills-windows/feature-pipeline-launcher/scripts/preflight-check.py +0 -462
  225. package/bundled/skills-windows/feature-planner/SKILL.md +0 -397
  226. package/bundled/skills-windows/feature-planner/assets/evaluation-guide.md +0 -64
  227. package/bundled/skills-windows/feature-planner/assets/planning-guide.md +0 -214
  228. package/bundled/skills-windows/feature-planner/references/browser-interaction.md +0 -59
  229. package/bundled/skills-windows/feature-planner/references/completeness-review.md +0 -57
  230. package/bundled/skills-windows/feature-planner/references/decomposition-patterns.md +0 -75
  231. package/bundled/skills-windows/feature-planner/references/error-recovery.md +0 -90
  232. package/bundled/skills-windows/feature-planner/references/incremental-feature-planning.md +0 -112
  233. package/bundled/skills-windows/feature-planner/references/new-project-planning.md +0 -85
  234. package/bundled/skills-windows/feature-planner/scripts/validate-and-generate.py +0 -1020
  235. package/bundled/skills-windows/feature-workflow/SKILL.md +0 -374
  236. package/bundled/skills-windows/feature-workflow/references/brainstorm-guide.md +0 -137
  237. package/bundled/skills-windows/prizm-kit/SKILL.md +0 -93
  238. package/bundled/skills-windows/prizmkit-code-review/SKILL.md +0 -161
  239. package/bundled/skills-windows/prizmkit-code-review/references/dev-agent-prompt.md +0 -30
  240. package/bundled/skills-windows/prizmkit-code-review/references/review-report-template.md +0 -31
  241. package/bundled/skills-windows/prizmkit-code-review/references/reviewer-agent-prompt.md +0 -66
  242. package/bundled/skills-windows/prizmkit-code-review/scripts/check_loop.py +0 -186
  243. package/bundled/skills-windows/prizmkit-committer/SKILL.md +0 -89
  244. package/bundled/skills-windows/prizmkit-deploy/SKILL.md +0 -444
  245. package/bundled/skills-windows/prizmkit-deploy/references/ci-cd-workflows.md +0 -115
  246. package/bundled/skills-windows/prizmkit-deploy/references/cloud-platform-deploy.md +0 -93
  247. package/bundled/skills-windows/prizmkit-deploy/references/data-safety-examples.md +0 -120
  248. package/bundled/skills-windows/prizmkit-deploy/references/database-setup.md +0 -46
  249. package/bundled/skills-windows/prizmkit-deploy/references/deploy-config-schema.md +0 -148
  250. package/bundled/skills-windows/prizmkit-deploy/references/deploy-history-schema.md +0 -62
  251. package/bundled/skills-windows/prizmkit-deploy/references/deployment-modes.md +0 -50
  252. package/bundled/skills-windows/prizmkit-deploy/references/direct-upload.md +0 -26
  253. package/bundled/skills-windows/prizmkit-deploy/references/dns-setup.md +0 -42
  254. package/bundled/skills-windows/prizmkit-deploy/references/docker-deploy.md +0 -31
  255. package/bundled/skills-windows/prizmkit-deploy/references/firewall-setup.md +0 -37
  256. package/bundled/skills-windows/prizmkit-deploy/references/live-validation-notes.md +0 -21
  257. package/bundled/skills-windows/prizmkit-deploy/references/nginx-blue-green.md +0 -59
  258. package/bundled/skills-windows/prizmkit-deploy/references/ssh-bootstrap-flow.md +0 -49
  259. package/bundled/skills-windows/prizmkit-deploy/references/ssh-execution-flow.md +0 -41
  260. package/bundled/skills-windows/prizmkit-deploy/references/ssh-takeover.md +0 -20
  261. package/bundled/skills-windows/prizmkit-deploy/references/ssl-setup.md +0 -56
  262. package/bundled/skills-windows/prizmkit-implement/SKILL.md +0 -71
  263. package/bundled/skills-windows/prizmkit-init/SKILL.md +0 -356
  264. package/bundled/skills-windows/prizmkit-init/assets/project-brief-template.md +0 -82
  265. package/bundled/skills-windows/prizmkit-init/references/config-schema.md +0 -70
  266. package/bundled/skills-windows/prizmkit-init/references/rules/layer-detection.md +0 -41
  267. package/bundled/skills-windows/prizmkit-init/references/tech-stack-catalog.md +0 -13
  268. package/bundled/skills-windows/prizmkit-init/references/update-supplement.md +0 -9
  269. package/bundled/skills-windows/prizmkit-plan/SKILL.md +0 -102
  270. package/bundled/skills-windows/prizmkit-plan/assets/plan-template.md +0 -115
  271. package/bundled/skills-windows/prizmkit-plan/assets/spec-template.md +0 -73
  272. package/bundled/skills-windows/prizmkit-plan/references/clarify-guide.md +0 -67
  273. package/bundled/skills-windows/prizmkit-plan/references/examples.md +0 -85
  274. package/bundled/skills-windows/prizmkit-plan/references/verification-checklist.md +0 -60
  275. package/bundled/skills-windows/prizmkit-prizm-docs/SKILL.md +0 -129
  276. package/bundled/skills-windows/prizmkit-prizm-docs/assets/prizm-docs-format.md +0 -613
  277. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-init.md +0 -45
  278. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-rebuild.md +0 -15
  279. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-status.md +0 -14
  280. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-update.md +0 -19
  281. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-validate.md +0 -17
  282. package/bundled/skills-windows/prizmkit-retrospective/SKILL.md +0 -87
  283. package/bundled/skills-windows/prizmkit-retrospective/references/knowledge-injection-steps.md +0 -50
  284. package/bundled/skills-windows/prizmkit-retrospective/references/structural-sync-steps.md +0 -43
  285. package/bundled/skills-windows/prizmkit-test/SKILL.md +0 -227
  286. package/bundled/skills-windows/prizmkit-test/references/boundary-coverage-protocol.md +0 -220
  287. package/bundled/skills-windows/prizmkit-test/references/examples.md +0 -143
  288. package/bundled/skills-windows/prizmkit-test/references/service-boundary-test-catalog.md +0 -225
  289. package/bundled/skills-windows/prizmkit-test/references/test-generation-steps.md +0 -109
  290. package/bundled/skills-windows/prizmkit-test/references/test-report-template.md +0 -111
  291. package/bundled/skills-windows/prizmkit-test/scripts/validate_boundary_report.py +0 -347
  292. package/bundled/skills-windows/recovery-workflow/SKILL.md +0 -355
  293. package/bundled/skills-windows/recovery-workflow/evals/evals.json +0 -46
  294. package/bundled/skills-windows/recovery-workflow/references/detection.md +0 -58
  295. package/bundled/skills-windows/recovery-workflow/scripts/detect-recovery-state.py +0 -544
  296. package/bundled/skills-windows/refactor-pipeline-launcher/SKILL.md +0 -346
  297. package/bundled/skills-windows/refactor-pipeline-launcher/references/configuration.md +0 -72
  298. package/bundled/skills-windows/refactor-planner/SKILL.md +0 -398
  299. package/bundled/skills-windows/refactor-planner/assets/planning-guide.md +0 -292
  300. package/bundled/skills-windows/refactor-planner/references/behavior-preservation.md +0 -301
  301. package/bundled/skills-windows/refactor-planner/references/fast-path.md +0 -59
  302. package/bundled/skills-windows/refactor-planner/references/planning-phases.md +0 -135
  303. package/bundled/skills-windows/refactor-planner/references/refactor-scoping-guide.md +0 -221
  304. package/bundled/skills-windows/refactor-planner/scripts/validate-and-generate-refactor.py +0 -858
  305. package/bundled/skills-windows/refactor-workflow/SKILL.md +0 -343
  306. package/bundled/skills-windows/refactor-workflow/references/brainstorm-guide.md +0 -116
  307. package/bundled/templates/hooks/diff-prizm-docs.sh +0 -158
  308. package/bundled/templates/hooks/prizm-pre-commit.sh +0 -108
  309. package/bundled/templates/hooks/validate-prizm-docs.sh +0 -139
@@ -0,0 +1,389 @@
1
+ """Manual reset commands for the unified Python runtime."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import re
7
+ import subprocess
8
+ import sys
9
+ from collections.abc import Sequence
10
+ from dataclasses import dataclass
11
+ from pathlib import Path
12
+
13
+ from .commands import CommandResult # type: ignore # runtime boundary import
14
+ from .gitops import default_branch, list_reset_branches, reset_cleanup_branch
15
+ from .runner_models import RunnerFamily, family_for
16
+
17
+
18
+ @dataclass(frozen=True)
19
+ class ResetOptions:
20
+ """Parsed legacy reset arguments for one family."""
21
+
22
+ list_path: Path
23
+ item_id: str = ""
24
+ item_range: tuple[str, str] | None = None
25
+ filter_mode: str = ""
26
+ clean: bool = False
27
+ run_after: bool = False
28
+ help_requested: bool = False
29
+ unknown_args: tuple[str, ...] = ()
30
+
31
+
32
+ @dataclass(frozen=True)
33
+ class ResetItem:
34
+ """Resolved reset target from the plan list."""
35
+
36
+ item_id: str
37
+ title: str
38
+ slug: str
39
+ status: str
40
+
41
+
42
+ FAMILY_LABELS = {
43
+ "feature": "feature",
44
+ "bugfix": "bug",
45
+ "refactor": "refactor",
46
+ }
47
+
48
+ FILTER_FLAGS = {
49
+ "--auto-skipped": "auto_skipped",
50
+ "--failed": "failed",
51
+ "--stalled": "stalled",
52
+ }
53
+
54
+
55
+ ID_FIELD_BY_KIND = {
56
+ "feature": "id",
57
+ "bugfix": "id",
58
+ "refactor": "id",
59
+ }
60
+
61
+
62
+ TITLE_FIELD_BY_KIND = {
63
+ "feature": "title",
64
+ "bugfix": "title",
65
+ "refactor": "title",
66
+ }
67
+
68
+
69
+ BRANCH_PREFIX_BY_KIND = {
70
+ "feature": "dev",
71
+ "bugfix": "bugfix",
72
+ "refactor": "refactor",
73
+ }
74
+
75
+ STALLED_FILTER_STATUSES = {
76
+ "failed",
77
+ "auto_skipped",
78
+ "needs_info",
79
+ "stalled",
80
+ "stalled_context_continuation",
81
+ }
82
+
83
+
84
+ def run_reset_command(kind: str, legacy_args: tuple[str, ...], paths) -> CommandResult:
85
+ """Run a manual reset command for feature, bugfix, or refactor."""
86
+ family = family_for(kind, paths)
87
+ options = _parse_reset_args(family, legacy_args)
88
+ if options.help_requested:
89
+ return CommandResult(0, f"Python {kind} reset", _help_text(family), stdout=_help_text(family))
90
+
91
+ list_path = _resolve_list_path(options.list_path, paths.project_root)
92
+ if not list_path.is_file():
93
+ return CommandResult(1, f"Python {kind} reset", f"{kind} list not found: {list_path}")
94
+ if not (family.state_dir / "pipeline.json").is_file():
95
+ return CommandResult(1, f"Python {kind} reset", f"No pipeline state found. Run the {kind} pipeline first to initialize.")
96
+
97
+ options = ResetOptions(
98
+ list_path=list_path,
99
+ item_id=options.item_id,
100
+ item_range=options.item_range,
101
+ filter_mode=options.filter_mode,
102
+ clean=options.clean,
103
+ run_after=options.run_after,
104
+ help_requested=options.help_requested,
105
+ unknown_args=options.unknown_args,
106
+ )
107
+ try:
108
+ items = _resolve_items(family, options)
109
+ except ValueError as exc:
110
+ return CommandResult(1, f"Python {kind} reset", str(exc))
111
+ if not items:
112
+ return CommandResult(0, f"Python {kind} reset", f"No {FAMILY_LABELS[kind]}s found with status: {options.filter_mode}")
113
+
114
+ if options.run_after and len(items) > 1:
115
+ options = ResetOptions(
116
+ list_path=options.list_path,
117
+ item_id=options.item_id,
118
+ item_range=options.item_range,
119
+ filter_mode=options.filter_mode,
120
+ clean=options.clean,
121
+ run_after=False,
122
+ help_requested=False,
123
+ unknown_args=options.unknown_args,
124
+ )
125
+
126
+ lines: list[str] = []
127
+ success = 0
128
+ failed = 0
129
+ return_branch = default_branch(paths.project_root)
130
+ for item in items:
131
+ ok = _reset_one(family, item, options, paths.project_root, return_branch, lines)
132
+ if ok:
133
+ success += 1
134
+ else:
135
+ failed += 1
136
+
137
+ lines.append(f"Reset complete: {success} succeeded, {failed} failed")
138
+ if options.run_after and len(items) == 1 and failed == 0:
139
+ from .runners import run_pipeline_command
140
+
141
+ lines.append(f"Auto-retrying {items[0].item_id} via Python foreground runner...")
142
+ retry_result = run_pipeline_command(kind, "run", (items[0].item_id, str(options.list_path)), paths)
143
+ lines.append(retry_result.render())
144
+ return CommandResult(retry_result.exit_code, f"Python {kind} reset", "\n".join(lines), stdout="\n".join(lines))
145
+
146
+ return CommandResult(0 if failed == 0 else 1, f"Python {kind} reset", "\n".join(lines), stdout="\n".join(lines))
147
+
148
+
149
+ def _parse_reset_args(family: RunnerFamily, legacy_args: Sequence[str]) -> ResetOptions:
150
+ args = tuple(str(arg) for arg in legacy_args)
151
+ list_path = family.plan_path
152
+ item_id = ""
153
+ item_range: tuple[str, str] | None = None
154
+ filter_mode = ""
155
+ clean = False
156
+ run_after = False
157
+ help_requested = False
158
+ unknown: list[str] = []
159
+ positional: list[str] = []
160
+
161
+ index = 0
162
+ while index < len(args):
163
+ arg = args[index]
164
+ if arg in {"--help", "-h", "help"}:
165
+ help_requested = True
166
+ elif arg == "--clean":
167
+ clean = True
168
+ elif arg == "--run":
169
+ run_after = True
170
+ elif arg in FILTER_FLAGS:
171
+ filter_mode = FILTER_FLAGS[arg]
172
+ elif arg.startswith("-"):
173
+ unknown.append(arg)
174
+ else:
175
+ positional.append(arg)
176
+ index += 1
177
+
178
+ for value in positional:
179
+ if _looks_like_range(value, family.id_prefix):
180
+ item_range = _normalize_range(value, family.id_prefix)
181
+ elif _looks_like_item_id(value, family.id_prefix) and not item_id:
182
+ item_id = _normalize_item_id(value, family.id_prefix)
183
+ elif list_path == family.plan_path:
184
+ list_path = Path(value).expanduser()
185
+ else:
186
+ unknown.append(value)
187
+
188
+ return ResetOptions(
189
+ list_path=list_path,
190
+ item_id=item_id,
191
+ item_range=item_range,
192
+ filter_mode=filter_mode,
193
+ clean=clean,
194
+ run_after=run_after,
195
+ help_requested=help_requested,
196
+ unknown_args=tuple(unknown),
197
+ )
198
+
199
+
200
+ def _resolve_list_path(path: Path, project_root: Path) -> Path:
201
+ return path.resolve() if path.is_absolute() else (project_root / path).resolve()
202
+
203
+
204
+ def _resolve_items(family: RunnerFamily, options: ResetOptions) -> tuple[ResetItem, ...]:
205
+ data = json.loads(options.list_path.read_text(encoding="utf-8"))
206
+ raw_items = data.get(family.list_key, [])
207
+ if not isinstance(raw_items, list):
208
+ raw_items = []
209
+ by_id = {_item_id(family, item): item for item in raw_items if isinstance(item, dict) and _item_id(family, item)}
210
+
211
+ ids: list[str]
212
+ if options.filter_mode:
213
+ ids = []
214
+ for item in raw_items:
215
+ if not isinstance(item, dict):
216
+ continue
217
+ status = str(item.get("status") or "")
218
+ if options.filter_mode == "auto_skipped" and status == "auto_skipped":
219
+ ids.append(_item_id(family, item))
220
+ elif options.filter_mode == "failed" and status == "failed":
221
+ ids.append(_item_id(family, item))
222
+ elif options.filter_mode == "stalled" and status in STALLED_FILTER_STATUSES:
223
+ ids.append(_item_id(family, item))
224
+ elif options.item_range:
225
+ start, end = options.item_range
226
+ start_num = _numeric_suffix(start, family.id_prefix)
227
+ end_num = _numeric_suffix(end, family.id_prefix)
228
+ if start_num <= 0 or end_num <= 0 or start_num > end_num:
229
+ raise ValueError(f"Invalid range: {start}:{end} (start must be <= end)")
230
+ ids = [f"{family.id_prefix}{number:03d}" for number in range(start_num, end_num + 1)]
231
+ elif options.item_id:
232
+ ids = [options.item_id]
233
+ else:
234
+ raise ValueError(_help_text(family))
235
+
236
+ resolved: list[ResetItem] = []
237
+ for item_id in ids:
238
+ item = by_id.get(item_id)
239
+ if not isinstance(item, dict):
240
+ continue
241
+ title = str(item.get(TITLE_FIELD_BY_KIND[family.kind]) or "")
242
+ resolved.append(ResetItem(item_id=item_id, title=title, slug=_slug_for_item(family, item_id, title), status=str(item.get("status") or "unknown")))
243
+ return tuple(resolved)
244
+
245
+
246
+ def _reset_one(family: RunnerFamily, item: ResetItem, options: ResetOptions, project_root: Path, return_branch: str, lines: list[str]) -> bool:
247
+ label = FAMILY_LABELS[family.kind]
248
+ status_file = family.state_dir / item.item_id / "status.json"
249
+ lines.append(f"Reset: {item.item_id} — {item.title}")
250
+ status_data = _load_status(status_file)
251
+ if status_data:
252
+ lines.append(f"Current status: {item.status} (retry {status_data.get('retry_count', 0)}, {len(status_data.get('sessions') or [])} sessions)")
253
+ _append_continuation_warning(lines, status_data, item.item_id, label)
254
+ else:
255
+ lines.append(f"Current status: {item.status} (no runtime state file)")
256
+
257
+ for branch in list_reset_branches(project_root, BRANCH_PREFIX_BY_KIND[family.kind], item.item_id):
258
+ cleanup = reset_cleanup_branch(project_root, branch, return_branch=return_branch, delete=options.clean)
259
+ lines.append(f"Discarded uncommitted changes on dev branch: {cleanup.branch}")
260
+ if cleanup.deleted:
261
+ lines.append(f"Deleted dev branch: {cleanup.branch}")
262
+ elif not options.clean:
263
+ lines.append(f"Dev branch preserved for debugging: {cleanup.branch}")
264
+ lines.extend(f"WARN: {warning}" for warning in cleanup.warnings)
265
+
266
+ action = "clean" if options.clean else "reset"
267
+ lines.append(f"{'Cleaning' if options.clean else 'Resetting'} {item.item_id} status...")
268
+ result = _run_updater(family, action, options, item, project_root)
269
+ if result.returncode == 0 and _json_without_error(result.stdout):
270
+ lines.append(f"{item.item_id} {action} complete: status -> pending, retry count -> 0")
271
+ return True
272
+ error = _error_text(result.stdout) or result.stderr.strip() or "unknown"
273
+ lines.append(f"ERROR: Reset {item.item_id} failed: {error}")
274
+ return False
275
+
276
+
277
+ def _run_updater(family: RunnerFamily, action: str, options: ResetOptions, item: ResetItem, project_root: Path) -> subprocess.CompletedProcess[str]:
278
+ command = [
279
+ sys.executable,
280
+ str(family.updater_script),
281
+ family.list_arg,
282
+ str(options.list_path),
283
+ "--state-dir",
284
+ str(family.state_dir),
285
+ family.item_id_arg,
286
+ item.item_id,
287
+ "--action",
288
+ action,
289
+ "--max-retries",
290
+ "3",
291
+ "--max-infra-retries",
292
+ "3",
293
+ ]
294
+ if action == "clean":
295
+ command.extend(["--project-root", str(project_root)])
296
+ if family.kind == "feature":
297
+ command.extend(["--feature-slug", item.slug])
298
+ return subprocess.run(command, cwd=str(project_root), stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False)
299
+
300
+
301
+ def _append_continuation_warning(lines: list[str], status_data: dict[str, object], item_id: str, item_label: str) -> None:
302
+ if status_data.get("continuation_pending") is True:
303
+ reason = str(status_data.get("continuation_reason") or "context_overflow")
304
+ lines.append(
305
+ f"WARN: Continuation pending for {item_label} {item_id} ({reason}). Manual reset will abandon automatic continuation progress."
306
+ )
307
+ branch = str(status_data.get("active_dev_branch") or "")
308
+ if branch:
309
+ lines.append(f"WARN: Pending continuation branch: {branch}")
310
+
311
+
312
+ def _load_status(path: Path) -> dict[str, object]:
313
+ if not path.is_file():
314
+ return {}
315
+ try:
316
+ data = json.loads(path.read_text(encoding="utf-8"))
317
+ except (OSError, json.JSONDecodeError):
318
+ return {}
319
+ return data if isinstance(data, dict) else {}
320
+
321
+
322
+ def _json_without_error(text: str) -> bool:
323
+ try:
324
+ data = json.loads(text or "{}")
325
+ except json.JSONDecodeError:
326
+ return False
327
+ return isinstance(data, dict) and "error" not in data
328
+
329
+
330
+ def _error_text(text: str) -> str:
331
+ try:
332
+ data = json.loads(text or "{}")
333
+ except json.JSONDecodeError:
334
+ return text.strip()
335
+ return str(data.get("error") or "") if isinstance(data, dict) else ""
336
+
337
+
338
+ def _item_id(family: RunnerFamily, item: dict[str, object]) -> str:
339
+ return _normalize_item_id(str(item.get(ID_FIELD_BY_KIND[family.kind]) or ""), family.id_prefix)
340
+
341
+
342
+ def _slug_for_item(family: RunnerFamily, item_id: str, title: str) -> str:
343
+ if family.kind != "feature":
344
+ return item_id
345
+ numeric = item_id.replace("F-", "").replace("f-", "").zfill(3)
346
+ slug = re.sub(r"[^a-z0-9\s-]", "", title.lower())
347
+ slug = re.sub(r"[\s]+", "-", slug.strip())
348
+ slug = re.sub(r"-+", "-", slug).strip("-") or "feature"
349
+ return f"{numeric}-{slug}"
350
+
351
+
352
+ def _looks_like_item_id(value: str, prefix: str) -> bool:
353
+ return value.upper().startswith(prefix.upper())
354
+
355
+
356
+ def _looks_like_range(value: str, prefix: str) -> bool:
357
+ if ":" not in value:
358
+ return False
359
+ left, right = value.split(":", 1)
360
+ return _looks_like_item_id(left, prefix) and _looks_like_item_id(right, prefix)
361
+
362
+
363
+ def _normalize_range(value: str, prefix: str) -> tuple[str, str]:
364
+ left, right = value.split(":", 1)
365
+ return _normalize_item_id(left, prefix), _normalize_item_id(right, prefix)
366
+
367
+
368
+ def _normalize_item_id(value: str, prefix: str) -> str:
369
+ upper = value.upper()
370
+ if upper.startswith(prefix.upper()):
371
+ suffix = upper[len(prefix) :]
372
+ if suffix.isdigit():
373
+ return f"{prefix}{int(suffix):03d}"
374
+ return upper
375
+
376
+
377
+ def _numeric_suffix(value: str, prefix: str) -> int:
378
+ normalized = _normalize_item_id(value, prefix)
379
+ suffix = normalized[len(prefix) :]
380
+ return int(suffix) if suffix.isdigit() else 0
381
+
382
+
383
+ def _help_text(family: RunnerFamily) -> str:
384
+ label = FAMILY_LABELS[family.kind]
385
+ return (
386
+ f"Usage: prizmkit-runtime reset {family.kind} <{label}-id|range> [--clean] [--run] "
387
+ "[--auto-skipped|--failed|--stalled] [list-path]\n"
388
+ "Reset is a destructive manual operation and is not used for automatic context continuation."
389
+ )
@@ -0,0 +1,51 @@
1
+ """Bookkeeping git helpers for Python foreground runners.
2
+
3
+ These helpers model the shell runner bookkeeping boundaries without hiding git
4
+ failures. They are intentionally small wrappers so task runners can preserve the
5
+ legacy ordering around branch creation and final status updates.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass
11
+ from pathlib import Path
12
+
13
+ from .gitops import GitCommandResult, git_status_safe, run_git_command
14
+ from .runner_models import RunnerFamily
15
+
16
+
17
+ @dataclass(frozen=True)
18
+ class BookkeepingResult:
19
+ """Result from an optional bookkeeping commit boundary."""
20
+
21
+ attempted: bool
22
+ committed: bool
23
+ result: GitCommandResult | None = None
24
+
25
+ @property
26
+ def ok(self) -> bool:
27
+ return self.result is None or self.result.return_code == 0
28
+
29
+
30
+ def has_workspace_changes(project_root: Path) -> bool:
31
+ """Return true when git status has non-hidden-tool worktree changes."""
32
+ return bool(git_status_safe(project_root).strip())
33
+
34
+
35
+ def commit_all_changes(project_root: Path, message: str) -> BookkeepingResult:
36
+ """Stage and commit current workspace changes when present."""
37
+ if not has_workspace_changes(project_root):
38
+ return BookkeepingResult(attempted=False, committed=False)
39
+ run_git_command(project_root, ("add", "-A", "--", "."))
40
+ result = run_git_command(project_root, ("commit", "--no-verify", "-m", message))
41
+ return BookkeepingResult(attempted=True, committed=result.return_code == 0, result=result)
42
+
43
+
44
+ def commit_pre_branch_bookkeeping(project_root: Path, family: RunnerFamily, item_id: str) -> BookkeepingResult:
45
+ """Commit status/list changes before creating the item dev branch."""
46
+ return commit_all_changes(project_root, f"chore({item_id}): mark in_progress")
47
+
48
+
49
+ def commit_final_bookkeeping(project_root: Path, family: RunnerFamily, item_id: str, status: str) -> BookkeepingResult:
50
+ """Commit final list/state changes after returning to the base branch."""
51
+ return commit_all_changes(project_root, f"chore({item_id}): update {family.kind} status {status}")
@@ -0,0 +1,179 @@
1
+ """Session classification and continuation helpers for Python runners."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import json
7
+ import subprocess
8
+ from pathlib import Path
9
+
10
+ from .gitops import HIDDEN_TOOL_WORKTREE_EXCLUDES, git_status_safe, run_git_command
11
+ from .runner_models import PromptGenerationResult, SessionClassification
12
+ from .sessions import AISessionResult
13
+
14
+ CONTEXT_OVERFLOW = "context_overflow"
15
+ STALL_REASON = "context_overflow_without_git_checkpoint_or_artifact_progress"
16
+ CONTEXT_MARKERS = (
17
+ "context_overflow",
18
+ "input exceeds the context window",
19
+ "context_length_exceeded",
20
+ "maximum context length exceeded",
21
+ "prompt is too long",
22
+ "too many tokens",
23
+ "input token count exceeds",
24
+ )
25
+ INFRA_MARKERS = (
26
+ "rate limit",
27
+ "overloaded",
28
+ "gateway",
29
+ "authentication",
30
+ "unauthorized",
31
+ "api error",
32
+ )
33
+
34
+
35
+ def classify_session(
36
+ result: AISessionResult,
37
+ *,
38
+ project_root: Path,
39
+ base_head: str,
40
+ prompt: PromptGenerationResult | None = None,
41
+ previous_fingerprint: object | None = None,
42
+ previous_no_progress_count: int = 0,
43
+ ) -> SessionClassification:
44
+ """Classify raw AI session signals with durable success precedence."""
45
+ fingerprint = progress_fingerprint(project_root, prompt)
46
+ if _has_commit_since(project_root, base_head):
47
+ return SessionClassification("success", reason="commit_since_base", progress_fingerprint=fingerprint)
48
+
49
+ if _is_context_overflow(result):
50
+ no_progress_count = _next_no_progress_count(previous_fingerprint, fingerprint, previous_no_progress_count)
51
+ if no_progress_count >= 2:
52
+ return SessionClassification(
53
+ "stalled_context_continuation",
54
+ reason=STALL_REASON,
55
+ fatal_error_code=result.fatal_error_code or CONTEXT_OVERFLOW,
56
+ progress_fingerprint=fingerprint,
57
+ no_progress_count=no_progress_count,
58
+ )
59
+ return SessionClassification(
60
+ CONTEXT_OVERFLOW,
61
+ reason=CONTEXT_OVERFLOW,
62
+ fatal_error_code=result.fatal_error_code or CONTEXT_OVERFLOW,
63
+ progress_fingerprint=fingerprint,
64
+ no_progress_count=no_progress_count,
65
+ )
66
+
67
+ if _is_infra_error(result):
68
+ return SessionClassification("infra_error", reason="ai_runtime_or_provider_error", progress_fingerprint=fingerprint)
69
+ if result.termination_reason == "stale_session":
70
+ return SessionClassification("crashed", reason="stale_session", progress_fingerprint=fingerprint)
71
+ if result.timed_out or result.termination_reason == "timeout":
72
+ return SessionClassification("timed_out", reason="timeout", progress_fingerprint=fingerprint)
73
+ if result.exit_code not in (0, None):
74
+ return SessionClassification("crashed", reason=f"exit_code={result.exit_code}", progress_fingerprint=fingerprint)
75
+ if _has_workspace_changes(project_root):
76
+ _auto_commit_workspace(project_root)
77
+ return SessionClassification("success", reason="auto_commit_uncommitted_changes", progress_fingerprint=fingerprint)
78
+ return SessionClassification("crashed", reason="no_durable_success", progress_fingerprint=fingerprint)
79
+
80
+
81
+ def progress_fingerprint(project_root: Path, prompt: PromptGenerationResult | None = None) -> dict[str, object]:
82
+ """Build the no-progress continuation fingerprint used by runner status metadata."""
83
+ status_text = git_status_safe(project_root)
84
+ head = run_git_command(project_root, ("rev-parse", "HEAD")).stdout.strip()
85
+ artifact_hash = ""
86
+ checkpoint_cursor = ""
87
+ if prompt and prompt.artifact_path and prompt.artifact_path.exists():
88
+ artifact_hash = _hash_tree(prompt.artifact_path)
89
+ if prompt and prompt.checkpoint_path and prompt.checkpoint_path.is_file():
90
+ try:
91
+ data = json.loads(prompt.checkpoint_path.read_text(encoding="utf-8"))
92
+ checkpoint_cursor = _checkpoint_cursor(data)
93
+ except (OSError, json.JSONDecodeError):
94
+ checkpoint_cursor = "unreadable"
95
+ return {
96
+ "git_diff_fingerprint": hashlib.sha256(status_text.encode()).hexdigest(),
97
+ "checkpoint_cursor": checkpoint_cursor,
98
+ "artifact_fingerprint": artifact_hash,
99
+ "head_commit": head,
100
+ }
101
+
102
+
103
+ def _next_no_progress_count(previous: object | None, current: object, count: int) -> int:
104
+ if previous and previous == current:
105
+ return max(0, count) + 1
106
+ return 0
107
+
108
+
109
+ def _is_context_overflow(result: AISessionResult) -> bool:
110
+ if (result.fatal_error_code or "").lower() == CONTEXT_OVERFLOW:
111
+ return True
112
+ text = "\n".join(
113
+ [
114
+ result.progress_summary.fatal_error_code,
115
+ result.progress_summary.terminal_result_text,
116
+ *result.progress_summary.errors,
117
+ _tail(result.session_log),
118
+ ]
119
+ ).lower()
120
+ return any(marker in text for marker in CONTEXT_MARKERS)
121
+
122
+
123
+ def _is_infra_error(result: AISessionResult) -> bool:
124
+ text = "\n".join([result.progress_summary.terminal_result_text, *result.progress_summary.errors, _tail(result.session_log)]).lower()
125
+ return bool(result.fatal_error_code and result.fatal_error_code != CONTEXT_OVERFLOW) or any(marker in text for marker in INFRA_MARKERS)
126
+
127
+
128
+ def _has_commit_since(project_root: Path, base_head: str) -> bool:
129
+ if not base_head:
130
+ return False
131
+ current = run_git_command(project_root, ("rev-parse", "HEAD")).stdout.strip()
132
+ return bool(current and current != base_head)
133
+
134
+
135
+ def _has_workspace_changes(project_root: Path) -> bool:
136
+ return bool(git_status_safe(project_root).strip())
137
+
138
+
139
+ def _auto_commit_workspace(project_root: Path) -> None:
140
+ run_git_command(project_root, ("add", "-A", "--", ".", *HIDDEN_TOOL_WORKTREE_EXCLUDES))
141
+ run_git_command(project_root, ("commit", "--no-verify", "-m", "chore: save runner session changes"))
142
+
143
+
144
+ def _tail(path: Path, max_bytes: int = 8192) -> str:
145
+ try:
146
+ data = path.read_bytes()
147
+ except OSError:
148
+ return ""
149
+ return data[-max_bytes:].decode("utf-8", errors="ignore")
150
+
151
+
152
+ def _hash_tree(path: Path) -> str:
153
+ digest = hashlib.sha256()
154
+ if path.is_file():
155
+ digest.update(path.name.encode())
156
+ digest.update(path.read_bytes())
157
+ return digest.hexdigest()
158
+ for child in sorted(path.rglob("*")):
159
+ if child.is_file():
160
+ try:
161
+ rel = child.relative_to(path).as_posix()
162
+ digest.update(rel.encode())
163
+ digest.update(child.read_bytes())
164
+ except OSError:
165
+ continue
166
+ return digest.hexdigest()
167
+
168
+
169
+ def _checkpoint_cursor(data: dict[str, object]) -> str:
170
+ steps = data.get("steps")
171
+ if not isinstance(steps, list):
172
+ return ""
173
+ for step in steps:
174
+ if not isinstance(step, dict):
175
+ continue
176
+ status = step.get("status", "pending")
177
+ if status not in {"completed", "skipped"}:
178
+ return f"{step.get('id', '?')}:{step.get('skill', 'unknown')}:{status}"
179
+ return "complete"