prizmkit 1.1.99 → 1.1.101

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (321) hide show
  1. package/bin/create-prizmkit.js +4 -4
  2. package/bundled/VERSION.json +3 -3
  3. package/bundled/dev-pipeline/.env.example +3 -3
  4. package/bundled/dev-pipeline/README.md +110 -90
  5. package/bundled/dev-pipeline/assets/prizm-dev-team-integration.md +1 -1
  6. package/bundled/dev-pipeline/cli.py +27 -0
  7. package/bundled/dev-pipeline/prizmkit_runtime/__init__.py +13 -0
  8. package/bundled/dev-pipeline/prizmkit_runtime/__main__.py +9 -0
  9. package/bundled/dev-pipeline/prizmkit_runtime/cli.py +193 -0
  10. package/bundled/dev-pipeline/prizmkit_runtime/commands.py +313 -0
  11. package/bundled/dev-pipeline/prizmkit_runtime/compat.py +32 -0
  12. package/bundled/dev-pipeline/prizmkit_runtime/config.py +410 -0
  13. package/bundled/dev-pipeline/prizmkit_runtime/daemon.py +478 -0
  14. package/bundled/dev-pipeline/prizmkit_runtime/gitops.py +734 -0
  15. package/bundled/dev-pipeline/prizmkit_runtime/heartbeat.py +256 -0
  16. package/bundled/dev-pipeline/prizmkit_runtime/interoperability.py +109 -0
  17. package/bundled/dev-pipeline/prizmkit_runtime/paths.py +110 -0
  18. package/bundled/dev-pipeline/prizmkit_runtime/processes.py +373 -0
  19. package/bundled/dev-pipeline/prizmkit_runtime/reset.py +389 -0
  20. package/bundled/dev-pipeline/prizmkit_runtime/runner_bookkeeping.py +51 -0
  21. package/bundled/dev-pipeline/prizmkit_runtime/runner_classification.py +179 -0
  22. package/bundled/dev-pipeline/prizmkit_runtime/runner_models.py +345 -0
  23. package/bundled/dev-pipeline/prizmkit_runtime/runner_prompts.py +118 -0
  24. package/bundled/dev-pipeline/prizmkit_runtime/runner_recovery.py +187 -0
  25. package/bundled/dev-pipeline/prizmkit_runtime/runner_status.py +147 -0
  26. package/bundled/dev-pipeline/prizmkit_runtime/runners.py +422 -0
  27. package/bundled/dev-pipeline/prizmkit_runtime/sessions.py +552 -0
  28. package/bundled/dev-pipeline/prizmkit_runtime/status.py +71 -0
  29. package/bundled/dev-pipeline/scripts/check-session-status.py +74 -1
  30. package/bundled/dev-pipeline/scripts/continuation.py +374 -0
  31. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +64 -52
  32. package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +35 -25
  33. package/bundled/dev-pipeline/scripts/generate-recovery-prompt.py +2 -2
  34. package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +15 -20
  35. package/bundled/dev-pipeline/scripts/parse-stream-progress.py +185 -16
  36. package/bundled/dev-pipeline/scripts/update-bug-status.py +214 -6
  37. package/bundled/dev-pipeline/scripts/update-feature-status.py +237 -6
  38. package/bundled/dev-pipeline/scripts/update-refactor-status.py +214 -6
  39. package/bundled/dev-pipeline/templates/agent-prompts/dev-implement.md +8 -2
  40. package/bundled/dev-pipeline/templates/bootstrap-prompt.md +4 -0
  41. package/bundled/dev-pipeline/templates/bootstrap-tier1.md +14 -5
  42. package/bundled/dev-pipeline/templates/bootstrap-tier2.md +16 -6
  43. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +16 -6
  44. package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +1 -1
  45. package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +3 -3
  46. package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +2 -0
  47. package/bundled/dev-pipeline/templates/sections/log-size-awareness.md +13 -69
  48. package/bundled/dev-pipeline/templates/sections/phase-context-snapshot-agent-suffix.md +15 -7
  49. package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +42 -29
  50. package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +41 -39
  51. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-agent.md +4 -0
  52. package/bundled/dev-pipeline/templates/sections/test-failure-recovery-lite.md +4 -0
  53. package/bundled/dev-pipeline/templates/session-status-schema.json +1 -1
  54. package/bundled/dev-pipeline/tests/conftest.py +1 -0
  55. package/bundled/dev-pipeline/tests/test_auto_skip.py +932 -0
  56. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +207 -0
  57. package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +100 -0
  58. package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +43 -0
  59. package/bundled/dev-pipeline/tests/test_python_runner_parity.py +1138 -0
  60. package/bundled/dev-pipeline/tests/test_unified_cli.py +1045 -0
  61. package/bundled/skills/_metadata.json +1 -1
  62. package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +29 -34
  63. package/bundled/skills/bugfix-pipeline-launcher/references/configuration.md +6 -5
  64. package/bundled/skills/feature-pipeline-launcher/SKILL.md +29 -35
  65. package/bundled/skills/feature-pipeline-launcher/references/configuration.md +7 -6
  66. package/bundled/skills/feature-workflow/SKILL.md +3 -6
  67. package/bundled/skills/recovery-workflow/SKILL.md +23 -32
  68. package/bundled/skills/refactor-pipeline-launcher/SKILL.md +29 -35
  69. package/bundled/skills/refactor-pipeline-launcher/references/configuration.md +7 -6
  70. package/bundled/skills/refactor-workflow/SKILL.md +3 -6
  71. package/bundled/templates/hooks/commit-intent.json +2 -2
  72. package/bundled/templates/hooks/diff-prizm-docs.py +226 -0
  73. package/bundled/templates/hooks/prizm-pre-commit.py +45 -0
  74. package/bundled/templates/hooks/validate-prizm-docs.py +240 -0
  75. package/package.json +1 -1
  76. package/src/config.js +33 -12
  77. package/src/index.js +3 -6
  78. package/src/manifest.js +3 -2
  79. package/src/metadata.js +7 -18
  80. package/src/prompts.js +0 -12
  81. package/src/runtimes.js +18 -11
  82. package/src/scaffold.js +133 -116
  83. package/src/upgrade.js +1 -1
  84. package/bundled/dev-pipeline/launch-bugfix-daemon.sh +0 -500
  85. package/bundled/dev-pipeline/launch-feature-daemon.sh +0 -657
  86. package/bundled/dev-pipeline/launch-refactor-daemon.sh +0 -502
  87. package/bundled/dev-pipeline/lib/branch.sh +0 -326
  88. package/bundled/dev-pipeline/lib/common.sh +0 -1257
  89. package/bundled/dev-pipeline/lib/heartbeat.sh +0 -469
  90. package/bundled/dev-pipeline/reset-bug.sh +0 -395
  91. package/bundled/dev-pipeline/reset-feature.sh +0 -406
  92. package/bundled/dev-pipeline/reset-refactor.sh +0 -393
  93. package/bundled/dev-pipeline/run-bugfix.sh +0 -1315
  94. package/bundled/dev-pipeline/run-feature.sh +0 -1602
  95. package/bundled/dev-pipeline/run-recovery.sh +0 -648
  96. package/bundled/dev-pipeline/run-refactor.sh +0 -1348
  97. package/bundled/dev-pipeline/scripts/monitor-log.sh +0 -104
  98. package/bundled/dev-pipeline/tests/test-path-resolution.sh +0 -100
  99. package/bundled/dev-pipeline-windows/.env.example +0 -36
  100. package/bundled/dev-pipeline-windows/README.md +0 -30
  101. package/bundled/dev-pipeline-windows/SCHEMA_ANALYSIS.md +0 -533
  102. package/bundled/dev-pipeline-windows/assets/feature-list-example.json +0 -146
  103. package/bundled/dev-pipeline-windows/assets/prizm-dev-team-integration.md +0 -137
  104. package/bundled/dev-pipeline-windows/launch-bugfix-daemon.ps1 +0 -9
  105. package/bundled/dev-pipeline-windows/launch-feature-daemon.ps1 +0 -9
  106. package/bundled/dev-pipeline-windows/launch-refactor-daemon.ps1 +0 -9
  107. package/bundled/dev-pipeline-windows/lib/branch.ps1 +0 -235
  108. package/bundled/dev-pipeline-windows/lib/common.ps1 +0 -829
  109. package/bundled/dev-pipeline-windows/lib/daemon.ps1 +0 -140
  110. package/bundled/dev-pipeline-windows/lib/pipeline.ps1 +0 -967
  111. package/bundled/dev-pipeline-windows/lib/reset.ps1 +0 -87
  112. package/bundled/dev-pipeline-windows/reset-bug.ps1 +0 -9
  113. package/bundled/dev-pipeline-windows/reset-feature.ps1 +0 -9
  114. package/bundled/dev-pipeline-windows/reset-refactor.ps1 +0 -9
  115. package/bundled/dev-pipeline-windows/run-bugfix.ps1 +0 -9
  116. package/bundled/dev-pipeline-windows/run-feature.ps1 +0 -9
  117. package/bundled/dev-pipeline-windows/run-recovery.ps1 +0 -179
  118. package/bundled/dev-pipeline-windows/run-refactor.ps1 +0 -9
  119. package/bundled/dev-pipeline-windows/scripts/check-session-status.py +0 -228
  120. package/bundled/dev-pipeline-windows/scripts/detect-stuck.py +0 -530
  121. package/bundled/dev-pipeline-windows/scripts/generate-bootstrap-prompt.py +0 -2282
  122. package/bundled/dev-pipeline-windows/scripts/generate-bugfix-prompt.py +0 -767
  123. package/bundled/dev-pipeline-windows/scripts/generate-recovery-prompt.py +0 -805
  124. package/bundled/dev-pipeline-windows/scripts/generate-refactor-prompt.py +0 -845
  125. package/bundled/dev-pipeline-windows/scripts/init-bugfix-pipeline.py +0 -316
  126. package/bundled/dev-pipeline-windows/scripts/init-dev-team.py +0 -134
  127. package/bundled/dev-pipeline-windows/scripts/init-pipeline.py +0 -382
  128. package/bundled/dev-pipeline-windows/scripts/init-refactor-pipeline.py +0 -399
  129. package/bundled/dev-pipeline-windows/scripts/monitor-log.ps1 +0 -102
  130. package/bundled/dev-pipeline-windows/scripts/parse-stream-progress.py +0 -1232
  131. package/bundled/dev-pipeline-windows/scripts/patch-completion-notes.py +0 -191
  132. package/bundled/dev-pipeline-windows/scripts/prizmkit-test-gate.py +0 -446
  133. package/bundled/dev-pipeline-windows/scripts/update-bug-status.py +0 -913
  134. package/bundled/dev-pipeline-windows/scripts/update-checkpoint.py +0 -173
  135. package/bundled/dev-pipeline-windows/scripts/update-feature-status.py +0 -1558
  136. package/bundled/dev-pipeline-windows/scripts/update-refactor-status.py +0 -1119
  137. package/bundled/dev-pipeline-windows/scripts/utils.py +0 -542
  138. package/bundled/dev-pipeline-windows/templates/agent-prompts/critic-plan-challenge.md +0 -7
  139. package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-fix.md +0 -7
  140. package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-implement.md +0 -65
  141. package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-resume.md +0 -5
  142. package/bundled/dev-pipeline-windows/templates/agent-prompts/reviewer-review.md +0 -7
  143. package/bundled/dev-pipeline-windows/templates/bootstrap-prompt.md +0 -73
  144. package/bundled/dev-pipeline-windows/templates/bootstrap-tier1.md +0 -589
  145. package/bundled/dev-pipeline-windows/templates/bootstrap-tier2.md +0 -710
  146. package/bundled/dev-pipeline-windows/templates/bootstrap-tier3.md +0 -791
  147. package/bundled/dev-pipeline-windows/templates/bug-fix-list-schema.json +0 -263
  148. package/bundled/dev-pipeline-windows/templates/bugfix-bootstrap-prompt.md +0 -326
  149. package/bundled/dev-pipeline-windows/templates/feature-list-schema.json +0 -237
  150. package/bundled/dev-pipeline-windows/templates/refactor-bootstrap-prompt.md +0 -340
  151. package/bundled/dev-pipeline-windows/templates/refactor-list-schema.json +0 -270
  152. package/bundled/dev-pipeline-windows/templates/sections/ac-verification-checklist.md +0 -7
  153. package/bundled/dev-pipeline-windows/templates/sections/checkpoint-system.md +0 -91
  154. package/bundled/dev-pipeline-windows/templates/sections/context-budget-rules.md +0 -34
  155. package/bundled/dev-pipeline-windows/templates/sections/critical-paths-agent.md +0 -10
  156. package/bundled/dev-pipeline-windows/templates/sections/critical-paths-full.md +0 -12
  157. package/bundled/dev-pipeline-windows/templates/sections/critical-paths-lite.md +0 -7
  158. package/bundled/dev-pipeline-windows/templates/sections/directory-convention-agent.md +0 -8
  159. package/bundled/dev-pipeline-windows/templates/sections/directory-convention-full.md +0 -9
  160. package/bundled/dev-pipeline-windows/templates/sections/directory-convention-lite.md +0 -6
  161. package/bundled/dev-pipeline-windows/templates/sections/failure-capture.md +0 -21
  162. package/bundled/dev-pipeline-windows/templates/sections/feature-context.md +0 -21
  163. package/bundled/dev-pipeline-windows/templates/sections/log-size-awareness.md +0 -78
  164. package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification-auto.md +0 -283
  165. package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification-opencli.md +0 -112
  166. package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification.md +0 -168
  167. package/bundled/dev-pipeline-windows/templates/sections/phase-commit-full.md +0 -82
  168. package/bundled/dev-pipeline-windows/templates/sections/phase-commit.md +0 -75
  169. package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-agent-suffix.md +0 -23
  170. package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-base.md +0 -14
  171. package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-lite-suffix.md +0 -19
  172. package/bundled/dev-pipeline-windows/templates/sections/phase-critic-plan-full.md +0 -63
  173. package/bundled/dev-pipeline-windows/templates/sections/phase-critic-plan.md +0 -42
  174. package/bundled/dev-pipeline-windows/templates/sections/phase-implement-agent.md +0 -44
  175. package/bundled/dev-pipeline-windows/templates/sections/phase-implement-full.md +0 -59
  176. package/bundled/dev-pipeline-windows/templates/sections/phase-implement-lite.md +0 -39
  177. package/bundled/dev-pipeline-windows/templates/sections/phase-plan-agent.md +0 -27
  178. package/bundled/dev-pipeline-windows/templates/sections/phase-plan-lite.md +0 -27
  179. package/bundled/dev-pipeline-windows/templates/sections/phase-prizmkit-test.md +0 -39
  180. package/bundled/dev-pipeline-windows/templates/sections/phase-review-agent.md +0 -35
  181. package/bundled/dev-pipeline-windows/templates/sections/phase-review-full.md +0 -35
  182. package/bundled/dev-pipeline-windows/templates/sections/phase-specify-plan-full.md +0 -73
  183. package/bundled/dev-pipeline-windows/templates/sections/phase0-init.md +0 -13
  184. package/bundled/dev-pipeline-windows/templates/sections/phase0-test-baseline.md +0 -21
  185. package/bundled/dev-pipeline-windows/templates/sections/session-context.md +0 -5
  186. package/bundled/dev-pipeline-windows/templates/sections/subagent-timeout-recovery.md +0 -6
  187. package/bundled/dev-pipeline-windows/templates/sections/task-contract.md +0 -34
  188. package/bundled/dev-pipeline-windows/templates/sections/test-failure-recovery-agent.md +0 -48
  189. package/bundled/dev-pipeline-windows/templates/sections/test-failure-recovery-lite.md +0 -48
  190. package/bundled/dev-pipeline-windows/templates/session-status-schema.json +0 -83
  191. package/bundled/skills-windows/app-planner/SKILL.md +0 -296
  192. package/bundled/skills-windows/app-planner/assets/app-design-guide.md +0 -101
  193. package/bundled/skills-windows/app-planner/references/architecture-decisions.md +0 -52
  194. package/bundled/skills-windows/app-planner/references/brainstorm-guide.md +0 -101
  195. package/bundled/skills-windows/app-planner/references/frontend-design-guide.md +0 -71
  196. package/bundled/skills-windows/app-planner/references/infrastructure-convention-discovery.md +0 -108
  197. package/bundled/skills-windows/app-planner/references/project-brief-guide.md +0 -82
  198. package/bundled/skills-windows/app-planner/references/project-conventions-discovery.md +0 -59
  199. package/bundled/skills-windows/app-planner/references/project-state-detection.md +0 -90
  200. package/bundled/skills-windows/app-planner/references/red-team-checklist.md +0 -40
  201. package/bundled/skills-windows/app-planner/references/rules/backend/derivation-rules.md +0 -619
  202. package/bundled/skills-windows/app-planner/references/rules/backend/fixed-rules.md +0 -285
  203. package/bundled/skills-windows/app-planner/references/rules/backend/question-bank.md +0 -249
  204. package/bundled/skills-windows/app-planner/references/rules/backend/question-manifest.json +0 -46
  205. package/bundled/skills-windows/app-planner/references/rules/backend/template.md +0 -173
  206. package/bundled/skills-windows/app-planner/references/rules/database/derivation-rules.md +0 -382
  207. package/bundled/skills-windows/app-planner/references/rules/database/fixed-rules.md +0 -211
  208. package/bundled/skills-windows/app-planner/references/rules/database/question-bank.md +0 -184
  209. package/bundled/skills-windows/app-planner/references/rules/database/question-manifest.json +0 -39
  210. package/bundled/skills-windows/app-planner/references/rules/database/template.md +0 -158
  211. package/bundled/skills-windows/app-planner/references/rules/frontend/derivation-rules.md +0 -820
  212. package/bundled/skills-windows/app-planner/references/rules/frontend/fixed-rules.md +0 -188
  213. package/bundled/skills-windows/app-planner/references/rules/frontend/question-bank.md +0 -319
  214. package/bundled/skills-windows/app-planner/references/rules/frontend/question-manifest.json +0 -51
  215. package/bundled/skills-windows/app-planner/references/rules/frontend/template.md +0 -339
  216. package/bundled/skills-windows/app-planner/references/rules/mobile/derivation-rules.md +0 -649
  217. package/bundled/skills-windows/app-planner/references/rules/mobile/fixed-rules.md +0 -290
  218. package/bundled/skills-windows/app-planner/references/rules/mobile/question-bank.md +0 -232
  219. package/bundled/skills-windows/app-planner/references/rules/mobile/question-manifest.json +0 -47
  220. package/bundled/skills-windows/app-planner/references/rules/mobile/template.md +0 -175
  221. package/bundled/skills-windows/app-planner/references/rules-configuration.md +0 -46
  222. package/bundled/skills-windows/bug-fix-workflow/SKILL.md +0 -379
  223. package/bundled/skills-windows/bug-fix-workflow/references/bug-diagnosis.md +0 -41
  224. package/bundled/skills-windows/bug-planner/SKILL.md +0 -402
  225. package/bundled/skills-windows/bug-planner/assets/bug-confirmation-template.md +0 -43
  226. package/bundled/skills-windows/bug-planner/references/critic-and-verification.md +0 -44
  227. package/bundled/skills-windows/bug-planner/references/error-recovery.md +0 -73
  228. package/bundled/skills-windows/bug-planner/references/input-formats.md +0 -53
  229. package/bundled/skills-windows/bug-planner/references/schema-validation.md +0 -25
  230. package/bundled/skills-windows/bug-planner/references/severity-rules.md +0 -16
  231. package/bundled/skills-windows/bug-planner/scripts/validate-bug-list.py +0 -322
  232. package/bundled/skills-windows/bugfix-pipeline-launcher/SKILL.md +0 -304
  233. package/bundled/skills-windows/bugfix-pipeline-launcher/references/configuration.md +0 -84
  234. package/bundled/skills-windows/feature-pipeline-launcher/SKILL.md +0 -381
  235. package/bundled/skills-windows/feature-pipeline-launcher/references/configuration.md +0 -67
  236. package/bundled/skills-windows/feature-pipeline-launcher/scripts/preflight-check.py +0 -462
  237. package/bundled/skills-windows/feature-planner/SKILL.md +0 -397
  238. package/bundled/skills-windows/feature-planner/assets/evaluation-guide.md +0 -64
  239. package/bundled/skills-windows/feature-planner/assets/planning-guide.md +0 -214
  240. package/bundled/skills-windows/feature-planner/references/browser-interaction.md +0 -59
  241. package/bundled/skills-windows/feature-planner/references/completeness-review.md +0 -57
  242. package/bundled/skills-windows/feature-planner/references/decomposition-patterns.md +0 -75
  243. package/bundled/skills-windows/feature-planner/references/error-recovery.md +0 -90
  244. package/bundled/skills-windows/feature-planner/references/incremental-feature-planning.md +0 -112
  245. package/bundled/skills-windows/feature-planner/references/new-project-planning.md +0 -85
  246. package/bundled/skills-windows/feature-planner/scripts/validate-and-generate.py +0 -1020
  247. package/bundled/skills-windows/feature-workflow/SKILL.md +0 -374
  248. package/bundled/skills-windows/feature-workflow/references/brainstorm-guide.md +0 -137
  249. package/bundled/skills-windows/prizm-kit/SKILL.md +0 -93
  250. package/bundled/skills-windows/prizmkit-code-review/SKILL.md +0 -161
  251. package/bundled/skills-windows/prizmkit-code-review/references/dev-agent-prompt.md +0 -30
  252. package/bundled/skills-windows/prizmkit-code-review/references/review-report-template.md +0 -31
  253. package/bundled/skills-windows/prizmkit-code-review/references/reviewer-agent-prompt.md +0 -66
  254. package/bundled/skills-windows/prizmkit-code-review/scripts/check_loop.py +0 -186
  255. package/bundled/skills-windows/prizmkit-committer/SKILL.md +0 -89
  256. package/bundled/skills-windows/prizmkit-deploy/SKILL.md +0 -444
  257. package/bundled/skills-windows/prizmkit-deploy/references/ci-cd-workflows.md +0 -115
  258. package/bundled/skills-windows/prizmkit-deploy/references/cloud-platform-deploy.md +0 -93
  259. package/bundled/skills-windows/prizmkit-deploy/references/data-safety-examples.md +0 -120
  260. package/bundled/skills-windows/prizmkit-deploy/references/database-setup.md +0 -46
  261. package/bundled/skills-windows/prizmkit-deploy/references/deploy-config-schema.md +0 -148
  262. package/bundled/skills-windows/prizmkit-deploy/references/deploy-history-schema.md +0 -62
  263. package/bundled/skills-windows/prizmkit-deploy/references/deployment-modes.md +0 -50
  264. package/bundled/skills-windows/prizmkit-deploy/references/direct-upload.md +0 -26
  265. package/bundled/skills-windows/prizmkit-deploy/references/dns-setup.md +0 -42
  266. package/bundled/skills-windows/prizmkit-deploy/references/docker-deploy.md +0 -31
  267. package/bundled/skills-windows/prizmkit-deploy/references/firewall-setup.md +0 -37
  268. package/bundled/skills-windows/prizmkit-deploy/references/live-validation-notes.md +0 -21
  269. package/bundled/skills-windows/prizmkit-deploy/references/nginx-blue-green.md +0 -59
  270. package/bundled/skills-windows/prizmkit-deploy/references/ssh-bootstrap-flow.md +0 -49
  271. package/bundled/skills-windows/prizmkit-deploy/references/ssh-execution-flow.md +0 -41
  272. package/bundled/skills-windows/prizmkit-deploy/references/ssh-takeover.md +0 -20
  273. package/bundled/skills-windows/prizmkit-deploy/references/ssl-setup.md +0 -56
  274. package/bundled/skills-windows/prizmkit-implement/SKILL.md +0 -71
  275. package/bundled/skills-windows/prizmkit-init/SKILL.md +0 -356
  276. package/bundled/skills-windows/prizmkit-init/assets/project-brief-template.md +0 -82
  277. package/bundled/skills-windows/prizmkit-init/references/config-schema.md +0 -70
  278. package/bundled/skills-windows/prizmkit-init/references/rules/layer-detection.md +0 -41
  279. package/bundled/skills-windows/prizmkit-init/references/tech-stack-catalog.md +0 -13
  280. package/bundled/skills-windows/prizmkit-init/references/update-supplement.md +0 -9
  281. package/bundled/skills-windows/prizmkit-plan/SKILL.md +0 -102
  282. package/bundled/skills-windows/prizmkit-plan/assets/plan-template.md +0 -115
  283. package/bundled/skills-windows/prizmkit-plan/assets/spec-template.md +0 -73
  284. package/bundled/skills-windows/prizmkit-plan/references/clarify-guide.md +0 -67
  285. package/bundled/skills-windows/prizmkit-plan/references/examples.md +0 -85
  286. package/bundled/skills-windows/prizmkit-plan/references/verification-checklist.md +0 -60
  287. package/bundled/skills-windows/prizmkit-prizm-docs/SKILL.md +0 -129
  288. package/bundled/skills-windows/prizmkit-prizm-docs/assets/prizm-docs-format.md +0 -613
  289. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-init.md +0 -45
  290. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-rebuild.md +0 -15
  291. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-status.md +0 -14
  292. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-update.md +0 -19
  293. package/bundled/skills-windows/prizmkit-prizm-docs/references/op-validate.md +0 -17
  294. package/bundled/skills-windows/prizmkit-retrospective/SKILL.md +0 -87
  295. package/bundled/skills-windows/prizmkit-retrospective/references/knowledge-injection-steps.md +0 -50
  296. package/bundled/skills-windows/prizmkit-retrospective/references/structural-sync-steps.md +0 -43
  297. package/bundled/skills-windows/prizmkit-test/SKILL.md +0 -227
  298. package/bundled/skills-windows/prizmkit-test/references/boundary-coverage-protocol.md +0 -220
  299. package/bundled/skills-windows/prizmkit-test/references/examples.md +0 -143
  300. package/bundled/skills-windows/prizmkit-test/references/service-boundary-test-catalog.md +0 -225
  301. package/bundled/skills-windows/prizmkit-test/references/test-generation-steps.md +0 -109
  302. package/bundled/skills-windows/prizmkit-test/references/test-report-template.md +0 -111
  303. package/bundled/skills-windows/prizmkit-test/scripts/validate_boundary_report.py +0 -347
  304. package/bundled/skills-windows/recovery-workflow/SKILL.md +0 -355
  305. package/bundled/skills-windows/recovery-workflow/evals/evals.json +0 -46
  306. package/bundled/skills-windows/recovery-workflow/references/detection.md +0 -58
  307. package/bundled/skills-windows/recovery-workflow/scripts/detect-recovery-state.py +0 -544
  308. package/bundled/skills-windows/refactor-pipeline-launcher/SKILL.md +0 -346
  309. package/bundled/skills-windows/refactor-pipeline-launcher/references/configuration.md +0 -72
  310. package/bundled/skills-windows/refactor-planner/SKILL.md +0 -398
  311. package/bundled/skills-windows/refactor-planner/assets/planning-guide.md +0 -292
  312. package/bundled/skills-windows/refactor-planner/references/behavior-preservation.md +0 -301
  313. package/bundled/skills-windows/refactor-planner/references/fast-path.md +0 -59
  314. package/bundled/skills-windows/refactor-planner/references/planning-phases.md +0 -135
  315. package/bundled/skills-windows/refactor-planner/references/refactor-scoping-guide.md +0 -221
  316. package/bundled/skills-windows/refactor-planner/scripts/validate-and-generate-refactor.py +0 -858
  317. package/bundled/skills-windows/refactor-workflow/SKILL.md +0 -343
  318. package/bundled/skills-windows/refactor-workflow/references/brainstorm-guide.md +0 -116
  319. package/bundled/templates/hooks/diff-prizm-docs.sh +0 -158
  320. package/bundled/templates/hooks/prizm-pre-commit.sh +0 -108
  321. package/bundled/templates/hooks/validate-prizm-docs.sh +0 -139
@@ -0,0 +1,734 @@
1
+ """Branch and worktree helper primitives."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import re
7
+ import shutil
8
+ import subprocess
9
+ from collections.abc import Sequence
10
+ from dataclasses import dataclass
11
+ from pathlib import Path
12
+
13
+
14
+ HIDDEN_TOOL_WORKTREE_EXCLUDES = (
15
+ ":(top,exclude).prizmkit-worktree",
16
+ ":(top,exclude).skills-lock.json",
17
+ ":(top,exclude).AGENTS.md",
18
+ ":(top,exclude,glob).*/worktree",
19
+ ":(top,exclude,glob).*/worktree/**",
20
+ ":(top,exclude,glob).*/worktrees",
21
+ ":(top,exclude,glob).*/worktrees/**",
22
+ ":(top,exclude).claude",
23
+ ":(top,exclude,glob).claude/**",
24
+ ":(top,exclude).codebuddy",
25
+ ":(top,exclude,glob).codebuddy/**",
26
+ ":(top,exclude).codex",
27
+ ":(top,exclude,glob).codex/**",
28
+ ":(top,exclude).agents",
29
+ ":(top,exclude,glob).agents/**",
30
+ ":(top,exclude).prizmkit/prizm-docs",
31
+ ":(top,exclude,glob).prizmkit/prizm-docs/**",
32
+ ":(top,exclude).prizmkit/config.json",
33
+ ":(top,exclude).prizmkit/manifest.json",
34
+ ":(top,exclude).prizmkit/dev-pipeline/scripts",
35
+ ":(top,exclude,glob).prizmkit/dev-pipeline/scripts/**",
36
+ )
37
+
38
+ WORKTREE_PLATFORM_SUPPORT_DIRS = (".claude", ".codebuddy", ".codex", ".agents")
39
+ WORKTREE_ROOT_SUPPORT_FILES = ("skills-lock.json", "AGENTS.md")
40
+ WORKTREE_PRIZMKIT_SUPPORT_ENTRIES = ("prizm-docs", "config.json", "manifest.json")
41
+ WORKTREE_SUPPORT_IGNORE_NAMES = {"__pycache__", ".DS_Store", "settings.local.json"}
42
+
43
+
44
+ @dataclass(frozen=True)
45
+ class BranchContext:
46
+ """Branch state required by git/worktree helpers."""
47
+
48
+ base_branch: str
49
+ working_branch: str
50
+ project_root: Path
51
+ remote_name: str = "origin"
52
+
53
+
54
+ @dataclass(frozen=True)
55
+ class WorktreePolicy:
56
+ """Worktree creation and cleanup policy for later porting."""
57
+
58
+ use_worktree: bool
59
+ cleanup_on_success: bool
60
+ preserve_on_failure: bool
61
+ worktree_root: Path | None = None
62
+
63
+
64
+
65
+
66
+ @dataclass(frozen=True)
67
+ class WorktreeRuntimeContext:
68
+ """Resolved linked-worktree paths and safety metadata."""
69
+
70
+ context: BranchContext
71
+ policy: WorktreePolicy
72
+ worktree_root: Path
73
+ worktree_path: Path
74
+ sentinel_path: Path
75
+
76
+ def is_cleanup_path_safe(self) -> bool:
77
+ root = self.worktree_root.resolve()
78
+ target = self.worktree_path.resolve()
79
+ try:
80
+ return os.path.commonpath([str(root), str(target)]) == str(root) and target != root
81
+ except ValueError:
82
+ return False
83
+
84
+
85
+
86
+
87
+ @dataclass(frozen=True)
88
+ class WorktreeOperationResult:
89
+ """Executable linked-worktree operation result."""
90
+
91
+ ok: bool
92
+ reason: str = ""
93
+ runtime: WorktreeRuntimeContext | None = None
94
+ results: tuple[GitCommandResult, ...] = ()
95
+
96
+
97
+ @dataclass(frozen=True)
98
+ class WorktreeRemovalResult:
99
+ """Guarded worktree removal result."""
100
+
101
+ ok: bool
102
+ reason: str = ""
103
+ results: tuple[GitCommandResult, ...] = ()
104
+
105
+
106
+ @dataclass(frozen=True)
107
+ class WorktreeSupportAssetsResult:
108
+ """Support assets materialized into an AI-visible linked worktree."""
109
+
110
+ ok: bool
111
+ copied: tuple[Path, ...] = ()
112
+ existing: tuple[Path, ...] = ()
113
+ missing: tuple[str, ...] = ()
114
+ reason: str = ""
115
+
116
+
117
+ def _safe_worktree_name(branch_name: str) -> str:
118
+ safe = re.sub(r"[^A-Za-z0-9._-]+", "-", branch_name.strip())
119
+ safe = safe.strip(".-")
120
+ return safe or "worktree"
121
+
122
+
123
+ def worktree_runtime_context(context: BranchContext, policy: WorktreePolicy) -> WorktreeRuntimeContext:
124
+ """Resolve deterministic per-branch worktree paths under a runner-owned root."""
125
+ root = (policy.worktree_root or context.project_root / ".prizmkit" / "state" / "worktrees").resolve()
126
+ worktree_path = root / _safe_worktree_name(context.working_branch)
127
+ return WorktreeRuntimeContext(
128
+ context=context,
129
+ policy=policy,
130
+ worktree_root=root,
131
+ worktree_path=worktree_path,
132
+ sentinel_path=worktree_path / ".prizmkit-worktree",
133
+ )
134
+
135
+
136
+ def linked_worktree_setup_plan(runtime: WorktreeRuntimeContext) -> GitCommandPlan:
137
+ """Plan linked-worktree branch creation without main-worktree checkout."""
138
+ context = runtime.context
139
+ return GitCommandPlan(
140
+ name="linked_worktree_setup",
141
+ commands=(
142
+ _git("rev-parse", "--verify", context.working_branch, allow_failure=True, description="check existing branch"),
143
+ _git("branch", context.working_branch, context.base_branch, allow_failure=True, description="create branch without checkout"),
144
+ _git("worktree", "list", "--porcelain", allow_failure=True, description="inspect registered worktrees"),
145
+ _git("worktree", "add", "--checkout", str(runtime.worktree_path), context.working_branch, allow_failure=True, description="create or reuse linked worktree"),
146
+ ),
147
+ notes=(
148
+ "Creates the task branch without checking it out in the main working tree.",
149
+ "A deterministic path lets context-overflow continuations reuse the same worktree.",
150
+ ),
151
+ require_one_success=((0, 1),),
152
+ )
153
+
154
+
155
+ def worktree_merge_plan(runtime: WorktreeRuntimeContext, *, auto_push: bool = False) -> GitCommandPlan:
156
+ """Plan rebase-in-worktree then fast-forward merge in the main repository."""
157
+ context = runtime.context
158
+ commands = [
159
+ _git("rebase", context.base_branch, description="rebase worktree branch onto base"),
160
+ _git("merge", "--ff-only", context.working_branch, description="fast-forward base from worktree branch"),
161
+ ]
162
+ if auto_push:
163
+ commands.append(_git("push", allow_failure=True, description="optional auto-push after merge"))
164
+ return GitCommandPlan(
165
+ name="worktree_merge",
166
+ commands=tuple(commands),
167
+ notes=("Run rebase in the linked worktree and merge from the main checkout after checkout-free setup.",),
168
+ )
169
+
170
+
171
+ def worktree_remove_plan(runtime: WorktreeRuntimeContext, *, delete_branch: bool = True) -> GitCommandPlan:
172
+ """Plan guarded linked-worktree removal and optional branch deletion."""
173
+ commands = [
174
+ _git("worktree", "remove", "--force", str(runtime.worktree_path), description="remove linked worktree"),
175
+ ]
176
+ if delete_branch:
177
+ commands.append(_git("branch", "-d", runtime.context.working_branch, allow_failure=True, description="delete merged task branch"))
178
+ return GitCommandPlan(
179
+ name="worktree_remove",
180
+ commands=tuple(commands),
181
+ notes=("Caller must verify cleanup safety and registration before executing.",),
182
+ )
183
+
184
+
185
+ def worktree_registered(runtime: WorktreeRuntimeContext) -> bool:
186
+ """Return whether git worktree metadata contains the resolved path."""
187
+ result = run_git_command(runtime.context.project_root, ("worktree", "list", "--porcelain"))
188
+ if result.return_code != 0:
189
+ return False
190
+ target = str(runtime.worktree_path.resolve())
191
+ candidates: list[str] = []
192
+ for line in result.stdout.splitlines():
193
+ stripped = line.strip()
194
+ if stripped.startswith("worktree "):
195
+ candidates.append(stripped.removeprefix("worktree ").strip())
196
+ elif stripped:
197
+ candidates.append(stripped.split()[0])
198
+ return any(Path(candidate).resolve() == Path(target) for candidate in candidates if candidate)
199
+
200
+
201
+ def mark_worktree_sentinel(runtime: WorktreeRuntimeContext) -> None:
202
+ """Write a small runner-owned sentinel inside a linked worktree."""
203
+ runtime.sentinel_path.parent.mkdir(parents=True, exist_ok=True)
204
+ runtime.sentinel_path.write_text(runtime.context.working_branch + "\n", encoding="utf-8")
205
+
206
+
207
+
208
+ def materialize_worktree_support_assets(runtime: WorktreeRuntimeContext) -> WorktreeSupportAssetsResult:
209
+ """Copy ignored/untracked PrizmKit support assets into the linked worktree.
210
+
211
+ Git worktree checkout materializes only tracked files. Platform agent
212
+ definitions, Prizm docs/config, and installed runtime utility scripts are
213
+ commonly ignored support assets, yet generated prompts reference them from
214
+ the AI-visible project root. Copy only missing support files so continuation
215
+ worktrees keep any task-local artifact changes.
216
+ """
217
+ source_root = runtime.context.project_root
218
+ target_root = runtime.worktree_path
219
+ copied: list[Path] = []
220
+ existing: list[Path] = []
221
+ missing: list[str] = []
222
+
223
+ try:
224
+ for relative in WORKTREE_PLATFORM_SUPPORT_DIRS:
225
+ _materialize_optional_support_entry(source_root, target_root, relative, copied, existing, missing)
226
+ for relative in WORKTREE_ROOT_SUPPORT_FILES:
227
+ _materialize_optional_support_entry(source_root, target_root, relative, copied, existing, missing)
228
+ for relative in WORKTREE_PRIZMKIT_SUPPORT_ENTRIES:
229
+ _materialize_optional_support_entry(
230
+ source_root / ".prizmkit",
231
+ target_root / ".prizmkit",
232
+ relative,
233
+ copied,
234
+ existing,
235
+ missing,
236
+ )
237
+
238
+ runtime_scripts = _runtime_support_scripts_source(source_root)
239
+ if runtime_scripts is None:
240
+ missing.append(".prizmkit/dev-pipeline/scripts")
241
+ else:
242
+ target = target_root / ".prizmkit" / "dev-pipeline" / "scripts"
243
+ changed = _copy_support_entry(runtime_scripts, target)
244
+ (copied if changed else existing).append(target)
245
+ except OSError as exc:
246
+ return WorktreeSupportAssetsResult(False, tuple(copied), tuple(existing), tuple(missing), str(exc))
247
+
248
+ return WorktreeSupportAssetsResult(True, tuple(copied), tuple(existing), tuple(missing))
249
+
250
+
251
+ def _materialize_optional_support_entry(
252
+ source_root: Path,
253
+ target_root: Path,
254
+ relative: str,
255
+ copied: list[Path],
256
+ existing: list[Path],
257
+ missing: list[str],
258
+ ) -> None:
259
+ source = source_root / relative
260
+ target = target_root / relative
261
+ if not source.exists() and not source.is_symlink():
262
+ missing.append(relative)
263
+ return
264
+ changed = _copy_support_entry(source, target)
265
+ (copied if changed else existing).append(target)
266
+
267
+
268
+ def _runtime_support_scripts_source(project_root: Path) -> Path | None:
269
+ candidates = (
270
+ project_root / ".prizmkit" / "dev-pipeline" / "scripts",
271
+ project_root / "dev-pipeline" / "scripts",
272
+ )
273
+ for candidate in candidates:
274
+ if candidate.is_dir():
275
+ return candidate
276
+ return None
277
+
278
+
279
+ def _copy_support_entry(source: Path, target: Path) -> bool:
280
+ if source.is_symlink():
281
+ if target.exists() or target.is_symlink():
282
+ return False
283
+ target.parent.mkdir(parents=True, exist_ok=True)
284
+ os.symlink(os.readlink(source), target)
285
+ return True
286
+ if source.is_file():
287
+ if target.exists():
288
+ return False
289
+ target.parent.mkdir(parents=True, exist_ok=True)
290
+ shutil.copy2(source, target)
291
+ return True
292
+
293
+ changed = False
294
+ if not target.exists():
295
+ target.mkdir(parents=True, exist_ok=True)
296
+ changed = True
297
+ for current_root, dir_names, file_names in os.walk(source):
298
+ dir_names[:] = [name for name in dir_names if not _skip_support_asset_name(name)]
299
+ relative_root = Path(current_root).relative_to(source)
300
+ target_root = target / relative_root
301
+ if not target_root.exists():
302
+ target_root.mkdir(parents=True, exist_ok=True)
303
+ changed = True
304
+ for file_name in file_names:
305
+ if _skip_support_asset_name(file_name):
306
+ continue
307
+ source_file = Path(current_root) / file_name
308
+ target_file = target_root / file_name
309
+ if target_file.exists() or target_file.is_symlink():
310
+ continue
311
+ if source_file.is_symlink():
312
+ os.symlink(os.readlink(source_file), target_file)
313
+ else:
314
+ shutil.copy2(source_file, target_file)
315
+ changed = True
316
+ return changed
317
+
318
+
319
+ def _skip_support_asset_name(name: str) -> bool:
320
+ return name in WORKTREE_SUPPORT_IGNORE_NAMES or name.endswith(".pyc")
321
+
322
+
323
+ def ensure_linked_worktree(runtime: WorktreeRuntimeContext) -> WorktreeOperationResult:
324
+ """Create or reuse a linked worktree for the runtime context."""
325
+ if not runtime.policy.use_worktree:
326
+ return WorktreeOperationResult(False, "worktree_disabled", runtime)
327
+ if not runtime.is_cleanup_path_safe():
328
+ return WorktreeOperationResult(False, "unsafe_worktree_path", runtime)
329
+
330
+ runtime.worktree_root.mkdir(parents=True, exist_ok=True)
331
+ results: list[GitCommandResult] = []
332
+
333
+ branch_check = run_git_command(runtime.context.project_root, ("rev-parse", "--verify", runtime.context.working_branch))
334
+ results.append(branch_check)
335
+ if branch_check.return_code != 0:
336
+ branch_create = run_git_command(
337
+ runtime.context.project_root,
338
+ ("branch", runtime.context.working_branch, runtime.context.base_branch),
339
+ )
340
+ results.append(branch_create)
341
+ if branch_create.return_code != 0:
342
+ return WorktreeOperationResult(False, "branch_create_failed", runtime, tuple(results))
343
+
344
+ if worktree_registered(runtime):
345
+ mark_worktree_sentinel(runtime)
346
+ return WorktreeOperationResult(True, runtime=runtime, results=tuple(results))
347
+
348
+ if runtime.worktree_path.exists() and any(runtime.worktree_path.iterdir()):
349
+ return WorktreeOperationResult(False, "worktree_path_exists_unregistered", runtime, tuple(results))
350
+
351
+ add = run_git_command(
352
+ runtime.context.project_root,
353
+ ("worktree", "add", "--checkout", str(runtime.worktree_path), runtime.context.working_branch),
354
+ )
355
+ results.append(add)
356
+ if add.return_code != 0:
357
+ if worktree_registered(runtime):
358
+ mark_worktree_sentinel(runtime)
359
+ return WorktreeOperationResult(True, runtime=runtime, results=tuple(results))
360
+ return WorktreeOperationResult(False, "worktree_add_failed", runtime, tuple(results))
361
+
362
+ mark_worktree_sentinel(runtime)
363
+ return WorktreeOperationResult(True, runtime=runtime, results=tuple(results))
364
+
365
+
366
+ def merge_linked_worktree(runtime: WorktreeRuntimeContext, *, auto_push: bool = False) -> WorktreeOperationResult:
367
+ """Rebase the linked worktree branch and fast-forward merge it into base."""
368
+ results: list[GitCommandResult] = []
369
+ rebase = run_git_command(runtime.worktree_path, ("rebase", runtime.context.base_branch))
370
+ results.append(rebase)
371
+ if rebase.return_code != 0:
372
+ results.append(run_git_command(runtime.worktree_path, ("rebase", "--abort")))
373
+ return WorktreeOperationResult(False, "merge_conflict", runtime, tuple(results))
374
+
375
+ checkout = run_git_command(runtime.context.project_root, ("checkout", runtime.context.base_branch))
376
+ results.append(checkout)
377
+ if checkout.return_code != 0:
378
+ return WorktreeOperationResult(False, "base_checkout_failed", runtime, tuple(results))
379
+
380
+ merge = run_git_command(runtime.context.project_root, ("merge", "--ff-only", runtime.context.working_branch))
381
+ results.append(merge)
382
+ if merge.return_code != 0:
383
+ results.append(run_git_command(runtime.context.project_root, ("merge", "--abort")))
384
+ return WorktreeOperationResult(False, "merge_conflict", runtime, tuple(results))
385
+
386
+ if auto_push:
387
+ results.append(run_git_command(runtime.context.project_root, ("push",)))
388
+
389
+ return WorktreeOperationResult(True, runtime=runtime, results=tuple(results))
390
+
391
+ def guarded_worktree_remove(runtime: WorktreeRuntimeContext, *, delete_branch: bool = True) -> WorktreeRemovalResult:
392
+ """Remove a worktree only when path, sentinel, and git metadata are safe."""
393
+ if not runtime.is_cleanup_path_safe():
394
+ return WorktreeRemovalResult(False, "unsafe_worktree_path")
395
+ if not runtime.sentinel_path.is_file():
396
+ return WorktreeRemovalResult(False, "missing_worktree_sentinel")
397
+ if not worktree_registered(runtime):
398
+ return WorktreeRemovalResult(False, "worktree_not_registered")
399
+ results: list[GitCommandResult] = []
400
+ for command in worktree_remove_plan(runtime, delete_branch=delete_branch).commands:
401
+ result = run_git_command(runtime.context.project_root, command.args)
402
+ results.append(result)
403
+ if result.return_code != 0 and not command.allow_failure:
404
+ return WorktreeRemovalResult(False, command.description or "worktree_remove_failed", tuple(results))
405
+ return WorktreeRemovalResult(True, results=tuple(results))
406
+
407
+
408
+ @dataclass(frozen=True)
409
+ class GitCommand:
410
+ """One planned git command."""
411
+
412
+ args: tuple[str, ...]
413
+ allow_failure: bool = False
414
+ description: str = ""
415
+
416
+
417
+ @dataclass(frozen=True)
418
+ class GitCommandPlan:
419
+ """A deterministic branch/worktree command plan."""
420
+
421
+ name: str
422
+ commands: tuple[GitCommand, ...]
423
+ never_fails: bool = False
424
+ notes: tuple[str, ...] = ()
425
+ require_one_success: tuple[tuple[int, ...], ...] = ()
426
+
427
+
428
+ @dataclass(frozen=True)
429
+ class GitCommandResult:
430
+ """Result from running one git command."""
431
+
432
+ args: tuple[str, ...]
433
+ return_code: int
434
+ stdout: str
435
+ stderr: str
436
+
437
+
438
+ @dataclass(frozen=True)
439
+ class GitPlanResult:
440
+ """Result from running a command plan."""
441
+
442
+ plan: GitCommandPlan
443
+ results: tuple[GitCommandResult, ...]
444
+
445
+ @property
446
+ def ok(self) -> bool:
447
+ if self.plan.never_fails:
448
+ return True
449
+ for command, result in zip(self.plan.commands, self.results):
450
+ if result.return_code != 0 and not command.allow_failure:
451
+ return False
452
+ for success_group in self.plan.require_one_success:
453
+ if not any(
454
+ index < len(self.results) and self.results[index].return_code == 0
455
+ for index in success_group
456
+ ):
457
+ return False
458
+ return True
459
+
460
+
461
+ def _git(*args: str, allow_failure: bool = False, description: str = "") -> GitCommand:
462
+ return GitCommand(args=args, allow_failure=allow_failure, description=description)
463
+
464
+
465
+ def branch_create_plan(context: BranchContext) -> GitCommandPlan:
466
+ """Plan shell-equivalent branch_create intent."""
467
+ return GitCommandPlan(
468
+ name="branch_create",
469
+ commands=(
470
+ _git("rev-parse", "--verify", context.working_branch, allow_failure=True, description="check existing branch"),
471
+ _git("checkout", "-b", context.working_branch, context.base_branch, allow_failure=True, description="create branch if absent"),
472
+ _git("checkout", context.working_branch, allow_failure=True, description="checkout existing branch fallback"),
473
+ ),
474
+ notes=("Create and checkout branch from source, or checkout if it already exists.",),
475
+ require_one_success=((1, 2),),
476
+ )
477
+
478
+
479
+ def branch_return_plan(context: BranchContext) -> GitCommandPlan:
480
+ """Plan shell-equivalent branch_return intent."""
481
+ return GitCommandPlan(
482
+ name="branch_return",
483
+ commands=(
484
+ _git("rev-parse", "--abbrev-ref", "HEAD", description="detect current branch"),
485
+ _git("checkout", context.base_branch, allow_failure=True, description="checkout original branch if needed"),
486
+ ),
487
+ notes=("Safe when already on the original branch.",),
488
+ )
489
+
490
+
491
+ def branch_merge_plan(context: BranchContext, *, auto_push: bool = False) -> GitCommandPlan:
492
+ """Plan shell-equivalent branch_merge safety invariants."""
493
+ commands = [
494
+ _git("diff", "--name-only", allow_failure=True, description="detect tracked dirty files"),
495
+ _git("diff", "--cached", "--name-only", allow_failure=True, description="detect staged dirty files"),
496
+ _git("stash", "push", "-m", "pipeline-merge-stash", allow_failure=True, description="stash tracked dirty files only"),
497
+ _git("rebase", context.base_branch, context.working_branch, description="rebase dev onto original"),
498
+ _git("checkout", context.base_branch, description="checkout original for fast-forward"),
499
+ _git("merge", "--ff-only", context.working_branch, description="fast-forward original"),
500
+ ]
501
+ if auto_push:
502
+ commands.append(_git("push", allow_failure=True, description="optional auto-push"))
503
+ commands.extend(
504
+ [
505
+ _git("branch", "-d", context.working_branch, allow_failure=True, description="delete merged dev branch"),
506
+ _git("stash", "pop", allow_failure=True, description="restore stashed tracked files"),
507
+ ]
508
+ )
509
+ return GitCommandPlan(
510
+ name="branch_merge",
511
+ commands=tuple(commands),
512
+ notes=(
513
+ "Tracked-only stash avoids capturing ignored state artifacts.",
514
+ "Rebase then fast-forward preserves merge invariant.",
515
+ ),
516
+ )
517
+
518
+
519
+ def branch_save_wip_plan(context: BranchContext) -> GitCommandPlan:
520
+ """Plan shell-equivalent never-fail WIP preservation."""
521
+ return GitCommandPlan(
522
+ name="branch_save_wip",
523
+ commands=(
524
+ _git("rev-parse", "--abbrev-ref", "HEAD", allow_failure=True, description="verify current branch"),
525
+ _git("status", "--porcelain", allow_failure=True, description="detect uncommitted work"),
526
+ _git("add", "-A", "--", ".", *HIDDEN_TOOL_WORKTREE_EXCLUDES, allow_failure=True, description="stage non-ignored work excluding hidden tool worktrees"),
527
+ _git(
528
+ "commit",
529
+ "--no-verify",
530
+ "-m",
531
+ f"wip({context.working_branch}): interrupted — uncommitted work saved",
532
+ "-m",
533
+ "Pipeline was interrupted by signal. This commit preserves work-in-progress.",
534
+ "-m",
535
+ f"To resume: git checkout {context.working_branch}",
536
+ allow_failure=True,
537
+ description="create WIP commit",
538
+ ),
539
+ ),
540
+ never_fails=True,
541
+ notes=("Never-fail cleanup helper; errors are diagnostics only.",),
542
+ )
543
+
544
+
545
+ def branch_ensure_return_plan(context: BranchContext) -> GitCommandPlan:
546
+ """Plan shell-equivalent guaranteed return cleanup."""
547
+ return GitCommandPlan(
548
+ name="branch_ensure_return",
549
+ commands=(
550
+ _git("rebase", "--abort", allow_failure=True, description="abort in-progress rebase"),
551
+ _git("rev-parse", "--abbrev-ref", "HEAD", allow_failure=True, description="detect current branch"),
552
+ _git("status", "--porcelain", "--", ".", *HIDDEN_TOOL_WORKTREE_EXCLUDES, allow_failure=True, description="detect WIP before checkout"),
553
+ _git("add", "-A", "--", ".", *HIDDEN_TOOL_WORKTREE_EXCLUDES, allow_failure=True, description="stage WIP before checkout"),
554
+ _git(
555
+ "commit",
556
+ "--no-verify",
557
+ "-m",
558
+ f"wip({context.working_branch}): interrupted — uncommitted work saved",
559
+ "-m",
560
+ "Pipeline was interrupted by signal. This commit preserves work-in-progress.",
561
+ "-m",
562
+ f"To resume: git checkout {context.working_branch}",
563
+ allow_failure=True,
564
+ description="save WIP before return when on dev branch",
565
+ ),
566
+ _git("stash", "push", "-m", "pipeline-ensure-return-stash", allow_failure=True, description="stash checkout blockers"),
567
+ _git("checkout", context.base_branch, allow_failure=True, description="return to original branch"),
568
+ _git("stash", "pop", allow_failure=True, description="restore stashed checkout blockers"),
569
+ ),
570
+ never_fails=True,
571
+ notes=("Always returns success to support trap/finally cleanup paths.",),
572
+ )
573
+
574
+
575
+ def worktree_add_plan(context: BranchContext, policy: WorktreePolicy) -> GitCommandPlan:
576
+ """Plan worktree creation without recreating retired Windows runtime sources."""
577
+ root = policy.worktree_root or context.project_root.parent / f"{context.working_branch.replace('/', '-')}-worktree"
578
+ return GitCommandPlan(
579
+ name="worktree_add",
580
+ commands=(
581
+ _git("worktree", "add", str(root), context.working_branch, description="create git worktree"),
582
+ ),
583
+ notes=("Generic git worktree helper; no retired platform source trees are created.",),
584
+ )
585
+
586
+
587
+ def current_branch(project_root: Path) -> str:
588
+ """Return current git branch name, or an empty string outside git."""
589
+ result = run_git_command(project_root, ("rev-parse", "--abbrev-ref", "HEAD"))
590
+ return result.stdout.strip() if result.return_code == 0 else ""
591
+
592
+
593
+ def git_status_safe(project_root: Path) -> str:
594
+ """Return status while excluding hidden AI tool worktree directories."""
595
+ result = run_git_command(project_root, ("status", "--porcelain", "--", ".", *HIDDEN_TOOL_WORKTREE_EXCLUDES))
596
+ return result.stdout if result.return_code == 0 else ""
597
+
598
+
599
+ def branch_save_wip(project_root: Path, working_branch: str) -> GitPlanResult:
600
+ """Execute shell-compatible WIP save only when currently on working_branch."""
601
+ context = BranchContext(base_branch="", working_branch=working_branch, project_root=project_root)
602
+ plan = branch_save_wip_plan(context)
603
+ if not working_branch or current_branch(project_root) != working_branch or not git_status_safe(project_root).strip():
604
+ return GitPlanResult(plan=plan, results=())
605
+ return run_git_plan(project_root, plan)
606
+
607
+
608
+ def worktree_save_wip(runtime: WorktreeRuntimeContext) -> GitPlanResult:
609
+ """Preserve dirty linked-worktree changes on the task branch before removal."""
610
+ return branch_save_wip(runtime.worktree_path, runtime.context.working_branch)
611
+
612
+
613
+ def branch_ensure_return(project_root: Path, base_branch: str, working_branch: str = "") -> GitPlanResult:
614
+ """Best-effort shell-compatible ensure-return helper that never reports failure."""
615
+ active = current_branch(project_root)
616
+ if working_branch and active == working_branch:
617
+ branch_save_wip(project_root, working_branch)
618
+ context = BranchContext(base_branch=base_branch, working_branch=working_branch or active, project_root=project_root)
619
+ return run_git_plan(project_root, branch_ensure_return_plan(context))
620
+
621
+ def run_git_command(project_root: Path, args: Sequence[str]) -> GitCommandResult:
622
+ """Run one git command in a project root and capture output."""
623
+ completed = subprocess.run(
624
+ ["git", "-C", str(project_root), *map(str, args)],
625
+ stdout=subprocess.PIPE,
626
+ stderr=subprocess.PIPE,
627
+ text=True,
628
+ check=False,
629
+ )
630
+ return GitCommandResult(
631
+ args=tuple(map(str, args)),
632
+ return_code=completed.returncode,
633
+ stdout=completed.stdout,
634
+ stderr=completed.stderr,
635
+ )
636
+
637
+
638
+ def run_git_plan(project_root: Path, plan: GitCommandPlan) -> GitPlanResult:
639
+ """Run a plan sequentially, stopping on non-allowed failures."""
640
+ results: list[GitCommandResult] = []
641
+ for command in plan.commands:
642
+ result = run_git_command(project_root, command.args)
643
+ results.append(result)
644
+ if result.return_code != 0 and not (command.allow_failure or plan.never_fails):
645
+ break
646
+ return GitPlanResult(plan=plan, results=tuple(results))
647
+
648
+
649
+ @dataclass(frozen=True)
650
+ class ResetBranchCleanupResult:
651
+ """Observed result for reset-time branch cleanup."""
652
+
653
+ branch: str
654
+ cleaned: bool
655
+ deleted: bool
656
+ returned_to: str
657
+ warnings: tuple[str, ...] = ()
658
+
659
+
660
+ def default_branch(project_root: Path) -> str:
661
+ """Resolve the same main/master/default-branch fallback used by reset scripts."""
662
+ origin = run_git_command(project_root, ("symbolic-ref", "refs/remotes/origin/HEAD"))
663
+ if origin.return_code == 0 and origin.stdout.strip():
664
+ return origin.stdout.strip().removeprefix("refs/remotes/origin/")
665
+ if run_git_command(project_root, ("rev-parse", "--verify", "main")).return_code == 0:
666
+ return "main"
667
+ if run_git_command(project_root, ("rev-parse", "--verify", "master")).return_code == 0:
668
+ return "master"
669
+ return current_branch(project_root) or "main"
670
+
671
+
672
+ def reset_branch_pattern(prefix: str, item_id: str) -> str:
673
+ """Return the reset helper branch glob for one item."""
674
+ return f"{prefix}/{item_id}-*"
675
+
676
+
677
+ def list_reset_branches(project_root: Path, prefix: str, item_id: str) -> tuple[str, ...]:
678
+ """List dev branches that shell reset helpers would clean for an item."""
679
+ result = run_git_command(project_root, ("branch", "--list", reset_branch_pattern(prefix, item_id)))
680
+ if result.return_code != 0:
681
+ return ()
682
+ branches = []
683
+ for line in result.stdout.splitlines():
684
+ branch = line.strip().lstrip("* ").strip()
685
+ if branch:
686
+ branches.append(branch)
687
+ return tuple(branches)
688
+
689
+
690
+ def reset_cleanup_branch(project_root: Path, branch: str, *, return_branch: str, delete: bool) -> ResetBranchCleanupResult:
691
+ """Discard uncommitted branch changes and optionally delete the branch.
692
+
693
+ This is intentionally reset-specific: unlike interrupted runner cleanup, manual
694
+ reset abandons uncommitted work on matching dev branches to recreate the
695
+ shell helper contract.
696
+ """
697
+ warnings: list[str] = []
698
+ active = current_branch(project_root)
699
+ restored = active
700
+ stashed = False
701
+
702
+ if active == branch:
703
+ run_git_command(project_root, ("reset", "HEAD"))
704
+ run_git_command(project_root, ("checkout", "--", "."))
705
+ run_git_command(project_root, ("clean", "-fd"))
706
+ checkout = run_git_command(project_root, ("checkout", return_branch))
707
+ if checkout.return_code != 0:
708
+ warnings.append(f"failed to checkout {return_branch}")
709
+ restored = branch
710
+ else:
711
+ restored = return_branch
712
+ else:
713
+ dirty = run_git_command(project_root, ("status", "--porcelain"))
714
+ if dirty.stdout.strip():
715
+ stash = run_git_command(project_root, ("stash", "push", "--include-untracked", "-m", "reset-pipeline-temp"))
716
+ stashed = stash.return_code == 0
717
+ checkout = run_git_command(project_root, ("checkout", branch))
718
+ if checkout.return_code == 0:
719
+ run_git_command(project_root, ("reset", "HEAD"))
720
+ run_git_command(project_root, ("checkout", "--", "."))
721
+ run_git_command(project_root, ("clean", "-fd"))
722
+ run_git_command(project_root, ("checkout", active or return_branch))
723
+ restored = active or return_branch
724
+ else:
725
+ warnings.append(f"could not checkout {branch} to discard changes")
726
+ if stashed:
727
+ run_git_command(project_root, ("stash", "pop"))
728
+
729
+ deleted = False
730
+ if delete:
731
+ deleted = run_git_command(project_root, ("branch", "-D", branch)).return_code == 0
732
+ if not deleted:
733
+ warnings.append(f"failed to delete branch {branch}")
734
+ return ResetBranchCleanupResult(branch=branch, cleaned=True, deleted=deleted, returned_to=restored, warnings=tuple(warnings))