prizmkit 1.1.57 → 1.1.60

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 (188) hide show
  1. package/bin/create-prizmkit.js +8 -6
  2. package/bundled/VERSION.json +3 -3
  3. package/bundled/adapters/codex/agent-adapter.js +38 -0
  4. package/bundled/adapters/codex/paths.js +27 -0
  5. package/bundled/adapters/codex/rules-adapter.js +30 -0
  6. package/bundled/adapters/codex/settings-adapter.js +27 -0
  7. package/bundled/adapters/codex/skill-adapter.js +65 -0
  8. package/bundled/adapters/codex/team-adapter.js +37 -0
  9. package/bundled/dev-pipeline/.env.example +2 -1
  10. package/bundled/dev-pipeline/README.md +10 -7
  11. package/bundled/dev-pipeline/lib/common.sh +278 -37
  12. package/bundled/dev-pipeline/run-bugfix.sh +10 -61
  13. package/bundled/dev-pipeline/run-feature.sh +10 -78
  14. package/bundled/dev-pipeline/run-recovery.sh +10 -46
  15. package/bundled/dev-pipeline/run-refactor.sh +10 -61
  16. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +17 -7
  17. package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +9 -3
  18. package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +9 -3
  19. package/bundled/dev-pipeline/scripts/utils.py +6 -4
  20. package/bundled/dev-pipeline-windows/.env.example +28 -0
  21. package/bundled/dev-pipeline-windows/README.md +30 -0
  22. package/bundled/dev-pipeline-windows/SCHEMA_ANALYSIS.md +525 -0
  23. package/bundled/dev-pipeline-windows/assets/feature-list-example.json +146 -0
  24. package/bundled/dev-pipeline-windows/assets/prizm-dev-team-integration.md +138 -0
  25. package/bundled/dev-pipeline-windows/launch-bugfix-daemon.ps1 +9 -0
  26. package/bundled/dev-pipeline-windows/launch-feature-daemon.ps1 +9 -0
  27. package/bundled/dev-pipeline-windows/launch-refactor-daemon.ps1 +9 -0
  28. package/bundled/dev-pipeline-windows/lib/common.ps1 +432 -0
  29. package/bundled/dev-pipeline-windows/lib/daemon.ps1 +140 -0
  30. package/bundled/dev-pipeline-windows/lib/pipeline.ps1 +446 -0
  31. package/bundled/dev-pipeline-windows/lib/reset.ps1 +87 -0
  32. package/bundled/dev-pipeline-windows/reset-bug.ps1 +9 -0
  33. package/bundled/dev-pipeline-windows/reset-feature.ps1 +9 -0
  34. package/bundled/dev-pipeline-windows/reset-refactor.ps1 +9 -0
  35. package/bundled/dev-pipeline-windows/run-bugfix.ps1 +9 -0
  36. package/bundled/dev-pipeline-windows/run-feature.ps1 +9 -0
  37. package/bundled/dev-pipeline-windows/run-recovery.ps1 +76 -0
  38. package/bundled/dev-pipeline-windows/run-refactor.ps1 +9 -0
  39. package/bundled/dev-pipeline-windows/scripts/check-session-status.py +228 -0
  40. package/bundled/dev-pipeline-windows/scripts/cleanup-logs.py +192 -0
  41. package/bundled/dev-pipeline-windows/scripts/detect-stuck.py +530 -0
  42. package/bundled/dev-pipeline-windows/scripts/generate-bootstrap-prompt.py +1737 -0
  43. package/bundled/dev-pipeline-windows/scripts/generate-bugfix-prompt.py +685 -0
  44. package/bundled/dev-pipeline-windows/scripts/generate-recovery-prompt.py +805 -0
  45. package/bundled/dev-pipeline-windows/scripts/generate-refactor-prompt.py +763 -0
  46. package/bundled/dev-pipeline-windows/scripts/init-bugfix-pipeline.py +316 -0
  47. package/bundled/dev-pipeline-windows/scripts/init-dev-team.py +134 -0
  48. package/bundled/dev-pipeline-windows/scripts/init-pipeline.py +380 -0
  49. package/bundled/dev-pipeline-windows/scripts/init-refactor-pipeline.py +399 -0
  50. package/bundled/dev-pipeline-windows/scripts/parse-stream-progress.py +388 -0
  51. package/bundled/dev-pipeline-windows/scripts/patch-completion-notes.py +191 -0
  52. package/bundled/dev-pipeline-windows/scripts/update-bug-status.py +864 -0
  53. package/bundled/dev-pipeline-windows/scripts/update-checkpoint.py +173 -0
  54. package/bundled/dev-pipeline-windows/scripts/update-feature-status.py +1501 -0
  55. package/bundled/dev-pipeline-windows/scripts/update-refactor-status.py +1073 -0
  56. package/bundled/dev-pipeline-windows/scripts/utils.py +542 -0
  57. package/bundled/dev-pipeline-windows/templates/agent-prompts/critic-plan-challenge.md +7 -0
  58. package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-fix.md +7 -0
  59. package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-implement.md +30 -0
  60. package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-resume.md +5 -0
  61. package/bundled/dev-pipeline-windows/templates/agent-prompts/reviewer-review.md +7 -0
  62. package/bundled/dev-pipeline-windows/templates/bootstrap-prompt.md +46 -0
  63. package/bundled/dev-pipeline-windows/templates/bootstrap-tier1.md +43 -0
  64. package/bundled/dev-pipeline-windows/templates/bootstrap-tier2.md +43 -0
  65. package/bundled/dev-pipeline-windows/templates/bootstrap-tier3.md +43 -0
  66. package/bundled/dev-pipeline-windows/templates/bug-fix-list-schema.json +263 -0
  67. package/bundled/dev-pipeline-windows/templates/bugfix-bootstrap-prompt.md +320 -0
  68. package/bundled/dev-pipeline-windows/templates/feature-list-schema.json +237 -0
  69. package/bundled/dev-pipeline-windows/templates/refactor-bootstrap-prompt.md +331 -0
  70. package/bundled/dev-pipeline-windows/templates/refactor-list-schema.json +270 -0
  71. package/bundled/dev-pipeline-windows/templates/sections/ac-verification-checklist.md +13 -0
  72. package/bundled/dev-pipeline-windows/templates/sections/checkpoint-system.md +91 -0
  73. package/bundled/dev-pipeline-windows/templates/sections/context-budget-rules.md +33 -0
  74. package/bundled/dev-pipeline-windows/templates/sections/critical-paths-agent.md +10 -0
  75. package/bundled/dev-pipeline-windows/templates/sections/critical-paths-full.md +12 -0
  76. package/bundled/dev-pipeline-windows/templates/sections/critical-paths-lite.md +7 -0
  77. package/bundled/dev-pipeline-windows/templates/sections/directory-convention-agent.md +8 -0
  78. package/bundled/dev-pipeline-windows/templates/sections/directory-convention-full.md +9 -0
  79. package/bundled/dev-pipeline-windows/templates/sections/directory-convention-lite.md +6 -0
  80. package/bundled/dev-pipeline-windows/templates/sections/failure-capture.md +21 -0
  81. package/bundled/dev-pipeline-windows/templates/sections/feature-context.md +31 -0
  82. package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification-auto.md +72 -0
  83. package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification-opencli.md +63 -0
  84. package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification.md +62 -0
  85. package/bundled/dev-pipeline-windows/templates/sections/phase-commit-full.md +71 -0
  86. package/bundled/dev-pipeline-windows/templates/sections/phase-commit.md +64 -0
  87. package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-agent-suffix.md +23 -0
  88. package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-base.md +24 -0
  89. package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-lite-suffix.md +12 -0
  90. package/bundled/dev-pipeline-windows/templates/sections/phase-critic-plan-full.md +53 -0
  91. package/bundled/dev-pipeline-windows/templates/sections/phase-critic-plan.md +32 -0
  92. package/bundled/dev-pipeline-windows/templates/sections/phase-implement-agent.md +37 -0
  93. package/bundled/dev-pipeline-windows/templates/sections/phase-implement-full.md +50 -0
  94. package/bundled/dev-pipeline-windows/templates/sections/phase-implement-lite.md +52 -0
  95. package/bundled/dev-pipeline-windows/templates/sections/phase-plan-agent.md +27 -0
  96. package/bundled/dev-pipeline-windows/templates/sections/phase-plan-lite.md +27 -0
  97. package/bundled/dev-pipeline-windows/templates/sections/phase-review-agent.md +27 -0
  98. package/bundled/dev-pipeline-windows/templates/sections/phase-review-full.md +29 -0
  99. package/bundled/dev-pipeline-windows/templates/sections/phase-specify-plan-full.md +77 -0
  100. package/bundled/dev-pipeline-windows/templates/sections/phase0-init.md +13 -0
  101. package/bundled/dev-pipeline-windows/templates/sections/phase0-test-baseline.md +23 -0
  102. package/bundled/dev-pipeline-windows/templates/sections/session-context.md +5 -0
  103. package/bundled/dev-pipeline-windows/templates/sections/subagent-timeout-recovery.md +6 -0
  104. package/bundled/dev-pipeline-windows/templates/sections/test-failure-recovery-agent.md +67 -0
  105. package/bundled/dev-pipeline-windows/templates/sections/test-failure-recovery-lite.md +58 -0
  106. package/bundled/dev-pipeline-windows/templates/session-status-schema.json +83 -0
  107. package/bundled/skills/_metadata.json +1 -1
  108. package/bundled/skills/app-planner/SKILL.md +26 -18
  109. package/bundled/skills/app-planner/references/architecture-decisions.md +9 -5
  110. package/bundled/skills/app-planner/references/frontend-design-guide.md +1 -1
  111. package/bundled/skills/feature-planner/SKILL.md +9 -2
  112. package/bundled/skills/prizmkit-init/SKILL.md +7 -6
  113. package/bundled/skills/recovery-workflow/scripts/detect-recovery-state.py +2 -0
  114. package/bundled/skills-windows/app-planner/SKILL.md +639 -0
  115. package/bundled/skills-windows/app-planner/assets/app-design-guide.md +101 -0
  116. package/bundled/skills-windows/app-planner/references/architecture-decisions.md +52 -0
  117. package/bundled/skills-windows/app-planner/references/brainstorm-guide.md +101 -0
  118. package/bundled/skills-windows/app-planner/references/frontend-design-guide.md +71 -0
  119. package/bundled/skills-windows/app-planner/references/project-brief-guide.md +82 -0
  120. package/bundled/skills-windows/app-planner/references/red-team-checklist.md +40 -0
  121. package/bundled/skills-windows/app-planner/references/rules/backend/derivation-rules.md +609 -0
  122. package/bundled/skills-windows/app-planner/references/rules/backend/fixed-rules.md +285 -0
  123. package/bundled/skills-windows/app-planner/references/rules/backend/question-bank.md +249 -0
  124. package/bundled/skills-windows/app-planner/references/rules/backend/template.md +173 -0
  125. package/bundled/skills-windows/app-planner/references/rules/database/derivation-rules.md +373 -0
  126. package/bundled/skills-windows/app-planner/references/rules/database/fixed-rules.md +211 -0
  127. package/bundled/skills-windows/app-planner/references/rules/database/question-bank.md +184 -0
  128. package/bundled/skills-windows/app-planner/references/rules/database/template.md +158 -0
  129. package/bundled/skills-windows/app-planner/references/rules/frontend/derivation-rules.md +810 -0
  130. package/bundled/skills-windows/app-planner/references/rules/frontend/fixed-rules.md +188 -0
  131. package/bundled/skills-windows/app-planner/references/rules/frontend/question-bank.md +302 -0
  132. package/bundled/skills-windows/app-planner/references/rules/frontend/template.md +320 -0
  133. package/bundled/skills-windows/app-planner/references/rules/mobile/derivation-rules.md +639 -0
  134. package/bundled/skills-windows/app-planner/references/rules/mobile/fixed-rules.md +290 -0
  135. package/bundled/skills-windows/app-planner/references/rules/mobile/question-bank.md +232 -0
  136. package/bundled/skills-windows/app-planner/references/rules/mobile/template.md +175 -0
  137. package/bundled/skills-windows/bug-fix-workflow/SKILL.md +415 -0
  138. package/bundled/skills-windows/bug-planner/SKILL.md +395 -0
  139. package/bundled/skills-windows/bug-planner/assets/bug-confirmation-template.md +43 -0
  140. package/bundled/skills-windows/bug-planner/references/critic-and-verification.md +44 -0
  141. package/bundled/skills-windows/bug-planner/references/error-recovery.md +73 -0
  142. package/bundled/skills-windows/bug-planner/references/input-formats.md +53 -0
  143. package/bundled/skills-windows/bug-planner/references/schema-validation.md +25 -0
  144. package/bundled/skills-windows/bug-planner/references/severity-rules.md +16 -0
  145. package/bundled/skills-windows/bug-planner/scripts/validate-bug-list.py +322 -0
  146. package/bundled/skills-windows/bugfix-pipeline-launcher/SKILL.md +380 -0
  147. package/bundled/skills-windows/feature-pipeline-launcher/SKILL.md +441 -0
  148. package/bundled/skills-windows/feature-pipeline-launcher/scripts/preflight-check.py +462 -0
  149. package/bundled/skills-windows/feature-planner/SKILL.md +401 -0
  150. package/bundled/skills-windows/feature-planner/assets/evaluation-guide.md +64 -0
  151. package/bundled/skills-windows/feature-planner/assets/planning-guide.md +214 -0
  152. package/bundled/skills-windows/feature-planner/references/browser-interaction.md +59 -0
  153. package/bundled/skills-windows/feature-planner/references/completeness-review.md +57 -0
  154. package/bundled/skills-windows/feature-planner/references/decomposition-patterns.md +75 -0
  155. package/bundled/skills-windows/feature-planner/references/error-recovery.md +90 -0
  156. package/bundled/skills-windows/feature-planner/references/incremental-feature-planning.md +112 -0
  157. package/bundled/skills-windows/feature-planner/references/new-project-planning.md +85 -0
  158. package/bundled/skills-windows/feature-planner/scripts/validate-and-generate.py +1029 -0
  159. package/bundled/skills-windows/feature-workflow/SKILL.md +531 -0
  160. package/bundled/skills-windows/prizmkit-init/SKILL.md +356 -0
  161. package/bundled/skills-windows/prizmkit-init/assets/project-brief-template.md +82 -0
  162. package/bundled/skills-windows/prizmkit-init/references/config-schema.md +68 -0
  163. package/bundled/skills-windows/prizmkit-init/references/rules/layer-detection.md +41 -0
  164. package/bundled/skills-windows/prizmkit-init/references/tech-stack-catalog.md +13 -0
  165. package/bundled/skills-windows/prizmkit-init/references/update-supplement.md +9 -0
  166. package/bundled/skills-windows/recovery-workflow/SKILL.md +456 -0
  167. package/bundled/skills-windows/recovery-workflow/evals/evals.json +46 -0
  168. package/bundled/skills-windows/recovery-workflow/scripts/detect-recovery-state.py +544 -0
  169. package/bundled/skills-windows/refactor-pipeline-launcher/SKILL.md +406 -0
  170. package/bundled/skills-windows/refactor-planner/SKILL.md +540 -0
  171. package/bundled/skills-windows/refactor-planner/assets/planning-guide.md +292 -0
  172. package/bundled/skills-windows/refactor-planner/references/behavior-preservation.md +301 -0
  173. package/bundled/skills-windows/refactor-planner/references/refactor-scoping-guide.md +221 -0
  174. package/bundled/skills-windows/refactor-planner/scripts/validate-and-generate-refactor.py +858 -0
  175. package/bundled/skills-windows/refactor-workflow/SKILL.md +503 -0
  176. package/package.json +3 -2
  177. package/src/clean.js +73 -2
  178. package/src/config.js +159 -50
  179. package/src/detect-platform.js +16 -8
  180. package/src/external-skills.js +26 -19
  181. package/src/index.js +31 -9
  182. package/src/manifest.js +6 -2
  183. package/src/metadata.js +43 -5
  184. package/src/platforms.js +36 -0
  185. package/src/prompts.js +31 -6
  186. package/src/runtimes.js +20 -0
  187. package/src/scaffold.js +314 -110
  188. package/src/upgrade.js +81 -41
@@ -0,0 +1,805 @@
1
+ #!/usr/bin/env python3
2
+ """Generate a recovery bootstrap prompt from detection output.
3
+
4
+ Reads the JSON output of detect-recovery-state.py, determines which workflow
5
+ was interrupted and at which phase, then assembles a comprehensive bootstrap
6
+ prompt that explicitly enumerates every remaining phase with full instructions.
7
+
8
+ Unlike the feature/bugfix prompt generators that use template files, this script
9
+ builds the prompt programmatically because recovery prompts vary dramatically
10
+ by workflow type and phase.
11
+
12
+ Usage:
13
+ python3 generate-recovery-prompt.py \
14
+ --detection-json <path> \
15
+ --output <path> \
16
+ [--project-root <path>] \
17
+ [--session-id <id>]
18
+ """
19
+
20
+ import argparse
21
+ import json
22
+ import os
23
+ import subprocess
24
+ import sys
25
+
26
+ from utils import load_json_file, setup_logging
27
+
28
+
29
+ LOGGER = setup_logging("generate-recovery-prompt")
30
+
31
+
32
+ # ============================================================
33
+ # Phase instruction maps — one per workflow type
34
+ #
35
+ # Each phase maps to (name, instructions) where instructions are
36
+ # adapted for autonomous (non-interactive) recovery mode.
37
+ # These must be kept in sync with the corresponding SKILL.md files.
38
+ # ============================================================
39
+
40
+ BUGFIX_PHASES = {
41
+ 0: (
42
+ "Branch Setup",
43
+ """\
44
+ Check current branch. You should already be on a fix/* branch from the
45
+ interrupted session. If so, continue on it. If somehow on main, create
46
+ a new fix branch:
47
+ ```powershell
48
+ git checkout -b fix/{bug_id}-recovery
49
+ ```""",
50
+ ),
51
+ 1: (
52
+ "Deep Bug Diagnosis",
53
+ """\
54
+ Read the bug description and all available artifacts to understand the bug.
55
+ Since this is an autonomous recovery session, skip interactive Q&A.
56
+ Use whatever information is available:
57
+ - Read bug entry from `.prizmkit/plans/bug-fix-list.json` if bug ID is known
58
+ - Read any existing artifacts in `.prizmkit/bugfix/{bug_id}/`
59
+ - Read relevant source code and test files
60
+ - Read `.prizmkit/prizm-docs/` for affected modules
61
+
62
+ Produce a bug summary with: symptom, reproduction steps, expected behavior,
63
+ affected files, and root cause hypothesis.""",
64
+ ),
65
+ 2: (
66
+ "Triage",
67
+ """\
68
+ Locate affected code and identify root cause:
69
+ 1. Read `.prizmkit/prizm-docs/root.prizm` then relevant L1/L2 docs for affected modules
70
+ 2. Read files mentioned in the bug description or error/stack trace
71
+ 3. Check `.prizmkit/prizm-docs/` TRAPS for known patterns
72
+ 4. Classify: root cause (confirmed/suspected), blast radius, fix complexity
73
+ 5. Log your diagnosis (no need to ask for user confirmation in autonomous mode)""",
74
+ ),
75
+ 3: (
76
+ "Reproduce",
77
+ """\
78
+ Create a failing test that proves the bug exists:
79
+ 1. Write a reproduction test: `<module>.test.ts` with test case `should handle <bug scenario>`
80
+ 2. Run the test — confirm it FAILS (red)
81
+ 3. If the bug is hard to reproduce automatically, write a best-effort test
82
+ and proceed""",
83
+ ),
84
+ 4: (
85
+ "Fix",
86
+ """\
87
+ Implement the minimal fix (red → green):
88
+ 1. Read fix-plan.md if it exists for the planned approach
89
+ 2. Change the minimum code to fix the root cause — do NOT refactor
90
+ 3. Run the reproduction test — must PASS (green)
91
+ 4. Run the full module test suite — must pass (no regressions)
92
+ 5. If regressions occur, fix them (max 3 attempts)""",
93
+ ),
94
+ 5: (
95
+ "Review",
96
+ """\
97
+ Verify fix quality:
98
+ 1. Self-review: does the fix address root cause (not just symptom)?
99
+ Edge cases covered? Follows project conventions?
100
+ 2. Run full test suite one final time
101
+ 3. If any issues found, fix and re-review (max 3 rounds)""",
102
+ ),
103
+ 6: (
104
+ "User Verification",
105
+ """\
106
+ Since this is an autonomous recovery session, substitute automated verification
107
+ for manual user testing:
108
+ 1. Run the full test suite
109
+ 2. Verify ALL tests pass
110
+ 3. If tests fail, fix and retry (max 3 attempts)
111
+ 4. Proceed to next phase once all tests are green""",
112
+ ),
113
+ 7: (
114
+ "Commit & Merge",
115
+ """\
116
+ Commit the fix and finalize:
117
+ 1. Run `/prizmkit-retrospective` (structural sync only — update file counts,
118
+ interfaces, dependencies in .prizmkit/prizm-docs/)
119
+ 2. Stage all changed files explicitly (NEVER use `git add -A` or `git add .`)
120
+ 3. Run `/prizmkit-committer --headless` with commit prefix `fix(<scope>): <description>`
121
+ 4. Verify working tree is clean: `git status --short`
122
+ 5. Write `fix-report.md` to `.prizmkit/bugfix/{bug_id}/fix-report.md` with:
123
+ - Root cause summary
124
+ - Fix description
125
+ - Files changed
126
+ - Test results""",
127
+ ),
128
+ }
129
+
130
+ FEATURE_PHASES = {
131
+ 1: (
132
+ "Brainstorm",
133
+ """\
134
+ Since this is an autonomous recovery session, work with whatever context is
135
+ available. Read existing project files, `.prizmkit/prizm-docs/`, and any user-provided
136
+ materials to understand the requirements. Skip interactive Q&A.
137
+ Produce a requirements summary if one doesn't already exist.""",
138
+ ),
139
+ 2: (
140
+ "Plan",
141
+ """\
142
+ Invoke `/feature-planner` skill with the requirements summary to generate
143
+ `.prizmkit/plans/feature-list.json`. Validate the output exists and contains
144
+ properly structured features.""",
145
+ ),
146
+ 3: (
147
+ "Launch",
148
+ """\
149
+ Invoke `/feature-pipeline-launcher` skill:
150
+ - Input: path to `.prizmkit/plans/feature-list.json`
151
+ - The launcher handles execution mode selection and prerequisites
152
+ - Let the launcher present options and manage the pipeline start
153
+
154
+ If `/feature-pipeline-launcher` is not available, run the pipeline directly:
155
+ ```powershell
156
+ .\\.prizmkit\\dev-pipeline\\run-feature.ps1 run .prizmkit/plans/feature-list.json
157
+ ```""",
158
+ ),
159
+ 4: (
160
+ "Monitor",
161
+ """\
162
+ Check pipeline status and report results:
163
+ ```powershell
164
+ function Invoke-PrizmPython {
165
+ param([Parameter(ValueFromRemainingArguments = $true)][string[]]$Arguments)
166
+ $python = Get-Command python -ErrorAction SilentlyContinue
167
+ if ($python) {
168
+ & $python.Source -c 'import sys; raise SystemExit(0 if sys.version_info[0] == 3 else 1)' *> $null
169
+ if ($LASTEXITCODE -eq 0) {
170
+ & $python.Source @Arguments
171
+ return
172
+ }
173
+ }
174
+ $py = Get-Command py -ErrorAction SilentlyContinue
175
+ if ($py) {
176
+ & $py.Source -3 -c 'import sys; raise SystemExit(0 if sys.version_info[0] == 3 else 1)' *> $null
177
+ if ($LASTEXITCODE -eq 0) {
178
+ & $py.Source -3 @Arguments
179
+ return
180
+ }
181
+ }
182
+ throw "Python 3 is required. Install Python and ensure python or py is in PATH."
183
+ }
184
+ Invoke-PrizmPython .prizmkit\\dev-pipeline\\scripts\\update-feature-status.py `
185
+ --feature-list .prizmkit/plans/feature-list.json `
186
+ --state-dir .prizmkit/state/features `
187
+ --action status
188
+ ```
189
+ Report completion status for each feature.""",
190
+ ),
191
+ }
192
+
193
+ REFACTOR_PHASES = {
194
+ 1: (
195
+ "Brainstorm",
196
+ """\
197
+ Since this is an autonomous recovery session, work with whatever context is
198
+ available. Read existing project files, `.prizmkit/prizm-docs/`, and any materials
199
+ to understand the refactoring goals. Skip interactive Q&A.
200
+ Produce a refactoring goals summary if one doesn't already exist.""",
201
+ ),
202
+ 2: (
203
+ "Plan",
204
+ """\
205
+ Invoke `/refactor-planner` skill with the goals summary to generate
206
+ `.prizmkit/plans/refactor-list.json`. Validate the output exists and contains
207
+ properly structured refactor items.""",
208
+ ),
209
+ 3: (
210
+ "Launch",
211
+ """\
212
+ Invoke `/refactor-pipeline-launcher` skill:
213
+ - Input: path to `.prizmkit/plans/refactor-list.json`
214
+ - The launcher handles execution mode selection and prerequisites
215
+ - Let the launcher present options and manage the pipeline start
216
+
217
+ If `/refactor-pipeline-launcher` is not available, run the pipeline directly:
218
+ ```powershell
219
+ .\\.prizmkit\\dev-pipeline\\run-refactor.ps1 run .prizmkit/plans/refactor-list.json
220
+ ```""",
221
+ ),
222
+ 4: (
223
+ "Monitor",
224
+ """\
225
+ Check pipeline status and report results:
226
+ ```powershell
227
+ function Invoke-PrizmPython {
228
+ param([Parameter(ValueFromRemainingArguments = $true)][string[]]$Arguments)
229
+ $python = Get-Command python -ErrorAction SilentlyContinue
230
+ if ($python) {
231
+ & $python.Source -c 'import sys; raise SystemExit(0 if sys.version_info[0] == 3 else 1)' *> $null
232
+ if ($LASTEXITCODE -eq 0) {
233
+ & $python.Source @Arguments
234
+ return
235
+ }
236
+ }
237
+ $py = Get-Command py -ErrorAction SilentlyContinue
238
+ if ($py) {
239
+ & $py.Source -3 -c 'import sys; raise SystemExit(0 if sys.version_info[0] == 3 else 1)' *> $null
240
+ if ($LASTEXITCODE -eq 0) {
241
+ & $py.Source -3 @Arguments
242
+ return
243
+ }
244
+ }
245
+ throw "Python 3 is required. Install Python and ensure python or py is in PATH."
246
+ }
247
+ Invoke-PrizmPython .prizmkit\\dev-pipeline\\scripts\\update-refactor-status.py `
248
+ --refactor-list .prizmkit/plans/refactor-list.json `
249
+ --state-dir .prizmkit/state/refactor `
250
+ --action status
251
+ ```
252
+ Report completion status for each refactor item.""",
253
+ ),
254
+ }
255
+
256
+ # Maps workflow_type to (phase_map, all_phases_ordered)
257
+ WORKFLOW_REGISTRY = {
258
+ "bug-fix-workflow": (BUGFIX_PHASES, [0, 1, 2, 3, 4, 5, 6, 7]),
259
+ "feature-workflow": (FEATURE_PHASES, [1, 2, 3, 4]),
260
+ "refactor-workflow": (REFACTOR_PHASES, [1, 2, 3, 4]),
261
+ }
262
+
263
+
264
+ # ============================================================
265
+ # Artifact reading
266
+ # ============================================================
267
+
268
+ def read_file_safe(path, max_chars=8000):
269
+ """Read a file, truncate if too large. Returns content or None."""
270
+ if not os.path.isfile(path):
271
+ return None
272
+ try:
273
+ with open(path, "r", encoding="utf-8") as f:
274
+ content = f.read()
275
+ if len(content) > max_chars:
276
+ content = content[:max_chars] + "\n\n... (truncated)"
277
+ return content
278
+ except (IOError, UnicodeDecodeError):
279
+ return None
280
+
281
+
282
+ def read_bugfix_artifacts(project_root, bug_id):
283
+ """Read existing bug fix artifacts for context injection."""
284
+ if not bug_id:
285
+ return {}
286
+ bugfix_dir = os.path.join(project_root, ".prizmkit", "bugfix", bug_id)
287
+ artifacts = {}
288
+ for name in [
289
+ "fix-plan.md", "spec.md", "plan.md",
290
+ "context-snapshot.md", "fix-report.md",
291
+ ]:
292
+ path = os.path.join(bugfix_dir, name)
293
+ content = read_file_safe(path)
294
+ if content:
295
+ artifacts[name] = content
296
+ return artifacts
297
+
298
+
299
+ def read_feature_artifacts(project_root):
300
+ """Read existing feature workflow artifacts."""
301
+ artifacts = {}
302
+ # Feature list
303
+ for location in [
304
+ os.path.join(project_root, ".prizmkit", "plans", "feature-list.json"),
305
+ os.path.join(project_root, "feature-list.json"),
306
+ ]:
307
+ content = read_file_safe(location)
308
+ if content:
309
+ artifacts["feature-list.json"] = content
310
+ break
311
+ return artifacts
312
+
313
+
314
+ def read_refactor_artifacts(project_root):
315
+ """Read existing refactor workflow artifacts."""
316
+ artifacts = {}
317
+ for location in [
318
+ os.path.join(project_root, ".prizmkit", "plans", "refactor-list.json"),
319
+ os.path.join(project_root, "refactor-list.json"),
320
+ ]:
321
+ content = read_file_safe(location)
322
+ if content:
323
+ artifacts["refactor-list.json"] = content
324
+ break
325
+ return artifacts
326
+
327
+
328
+ def get_code_diff_summary(project_root, main_branch="main"):
329
+ """Get a summary of code changes for context."""
330
+ try:
331
+ result = subprocess.run(
332
+ ["git", "diff", main_branch, "--stat"],
333
+ capture_output=True, text=True, cwd=project_root, timeout=10,
334
+ )
335
+ if result.stdout.strip():
336
+ return result.stdout.strip()
337
+ except (subprocess.SubprocessError, FileNotFoundError):
338
+ pass
339
+ return "(no diff available)"
340
+
341
+
342
+ def read_bug_description(project_root, bug_id):
343
+ """Try to read bug description from bug-fix-list.json."""
344
+ if not bug_id:
345
+ return None
346
+ for location in [
347
+ os.path.join(project_root, ".prizmkit", "plans", "bug-fix-list.json"),
348
+ os.path.join(project_root, "bug-fix-list.json"),
349
+ ]:
350
+ if os.path.isfile(location):
351
+ try:
352
+ with open(location, "r", encoding="utf-8") as f:
353
+ data = json.load(f)
354
+ for bug in data.get("bugs", []):
355
+ if bug.get("id") == bug_id:
356
+ return bug
357
+ except (json.JSONDecodeError, IOError):
358
+ pass
359
+ return None
360
+
361
+
362
+ # ============================================================
363
+ # Prompt assembly
364
+ # ============================================================
365
+
366
+ def get_remaining_phases(workflow_type, current_phase):
367
+ """Get list of remaining phase numbers (inclusive of current)."""
368
+ phase_map, all_phases = WORKFLOW_REGISTRY.get(workflow_type, ({}, []))
369
+ remaining = [p for p in all_phases if p >= current_phase]
370
+ return remaining, phase_map
371
+
372
+
373
+ def format_artifact_section(artifacts):
374
+ """Format artifacts dict as markdown sections."""
375
+ if not artifacts:
376
+ return "(no artifacts found from previous session)"
377
+ sections = []
378
+ for name, content in sorted(artifacts.items()):
379
+ sections.append(
380
+ "### {name}\n\n```\n{content}\n```".format(
381
+ name=name, content=content,
382
+ )
383
+ )
384
+ return "\n\n".join(sections)
385
+
386
+
387
+ def build_bugfix_prompt(detection, project_root):
388
+ """Build recovery prompt for bug-fix-workflow."""
389
+ context = detection.get("context", {})
390
+ bug_id = context.get("bug_id", "UNKNOWN")
391
+ branch = context.get("branch", "unknown")
392
+ phase = detection.get("phase", 1)
393
+ phase_name = detection.get("phase_name", "Unknown")
394
+ git_state = detection.get("git", {})
395
+ code_state = detection.get("code", {})
396
+ recovery = detection.get("recovery", {})
397
+
398
+ # Read artifacts
399
+ artifacts = read_bugfix_artifacts(project_root, bug_id)
400
+ bug_desc = read_bug_description(project_root, bug_id)
401
+ diff_summary = get_code_diff_summary(project_root, "main")
402
+
403
+ # Get remaining phases
404
+ remaining, phase_map = get_remaining_phases("bug-fix-workflow", phase)
405
+
406
+ # Build prompt
407
+ lines = []
408
+ lines.append("# Recovery Session — Bug Fix Workflow")
409
+ lines.append("")
410
+ lines.append("## Context")
411
+ lines.append("")
412
+ lines.append("You are RECOVERING an interrupted bug-fix-workflow session.")
413
+ lines.append("")
414
+ lines.append("- **Bug ID**: {}".format(bug_id))
415
+ lines.append("- **Branch**: {}".format(branch))
416
+ lines.append("- **Interrupted at**: Phase {} — {}".format(phase, phase_name))
417
+ lines.append("- **Remaining work**: {}".format(recovery.get("remaining_work", "unknown")))
418
+ lines.append("")
419
+
420
+ lines.append("## CRITICAL RULES")
421
+ lines.append("")
422
+ lines.append("1. You MUST complete ALL remaining phases listed below — do NOT stop after implementation")
423
+ lines.append("2. Execute phases in ORDER. Do NOT skip any phase.")
424
+ lines.append("3. After the LAST phase, output a recovery summary.")
425
+ lines.append("4. This is a NON-INTERACTIVE autonomous session — proceed without asking for user input.")
426
+ lines.append("5. Use `/prizmkit-code-review`, `/prizmkit-committer`, `/prizmkit-retrospective` as specified in each phase.")
427
+ lines.append("6. When staging files for commit, always use explicit file names — NEVER use `git add -A` or `git add .`.")
428
+ lines.append("")
429
+
430
+ # Bug description (if available)
431
+ if bug_desc:
432
+ lines.append("## Bug Description (from bug-fix-list.json)")
433
+ lines.append("")
434
+ lines.append("- **ID**: {}".format(bug_desc.get("id", bug_id)))
435
+ lines.append("- **Title**: {}".format(bug_desc.get("title", "(untitled)")))
436
+ lines.append("- **Description**: {}".format(bug_desc.get("description", "(none)")))
437
+ lines.append("- **Severity**: {}".format(bug_desc.get("severity", "(unset)")))
438
+ if bug_desc.get("acceptance_criteria"):
439
+ lines.append("- **Acceptance Criteria**:")
440
+ for ac in bug_desc["acceptance_criteria"]:
441
+ lines.append(" - {}".format(ac))
442
+ lines.append("")
443
+
444
+ # Git state
445
+ lines.append("## Git State")
446
+ lines.append("")
447
+ lines.append("- **Branch**: {}".format(branch))
448
+ lines.append("- **Commits ahead of main**: {}".format(
449
+ git_state.get("commits_ahead_of_main", 0)))
450
+ lines.append("- **Uncommitted files**: {}".format(
451
+ git_state.get("uncommitted_files", 0)))
452
+ lines.append("- **Staged files**: {}".format(
453
+ git_state.get("staged_files", 0)))
454
+ lines.append("")
455
+
456
+ # Code changes summary
457
+ if code_state.get("has_changes"):
458
+ lines.append("## Code Changes (from interrupted session)")
459
+ lines.append("")
460
+ lines.append("- Files modified: {}".format(code_state.get("files_modified", 0)))
461
+ lines.append("- Files added: {}".format(code_state.get("files_added", 0)))
462
+ lines.append("- Files deleted: {}".format(code_state.get("files_deleted", 0)))
463
+ lines.append("- Test files touched: {}".format(code_state.get("test_files_touched", 0)))
464
+ lines.append("- Directories touched: {}".format(
465
+ ", ".join(code_state.get("directories_touched", [])) or "(none)"))
466
+ lines.append("")
467
+ lines.append("### Diff Summary")
468
+ lines.append("")
469
+ lines.append("```")
470
+ lines.append(diff_summary)
471
+ lines.append("```")
472
+ lines.append("")
473
+
474
+ # Existing artifacts
475
+ if artifacts:
476
+ lines.append("## Existing Artifacts (from interrupted session)")
477
+ lines.append("")
478
+ lines.append(format_artifact_section(artifacts))
479
+ lines.append("")
480
+
481
+ # Remaining phases
482
+ lines.append("---")
483
+ lines.append("")
484
+ lines.append("## Remaining Phases — Execute ALL of these in order")
485
+ lines.append("")
486
+
487
+ for i, phase_num in enumerate(remaining):
488
+ name, instructions = phase_map.get(phase_num, ("Unknown", ""))
489
+ # Substitute {bug_id} in instructions
490
+ instructions = instructions.replace("{bug_id}", bug_id)
491
+
492
+ label = "CURRENT PHASE" if i == 0 else ""
493
+ if label:
494
+ lines.append("### Phase {}: {} — {}".format(phase_num, name, label))
495
+ else:
496
+ lines.append("### Phase {}: {}".format(phase_num, name))
497
+ lines.append("")
498
+ lines.append(instructions)
499
+ lines.append("")
500
+
501
+ # Completion section
502
+ lines.append("---")
503
+ lines.append("")
504
+ lines.append("## FINAL: Recovery Summary")
505
+ lines.append("")
506
+ lines.append("After ALL phases above are complete, output:")
507
+ lines.append("")
508
+ lines.append("```")
509
+ lines.append("Recovery complete.")
510
+ lines.append(" Workflow: bug-fix-workflow")
511
+ lines.append(" Bug: {}".format(bug_id))
512
+ lines.append(" Recovered from: Phase {} ({})".format(phase, phase_name))
513
+ lines.append(" Completed: {}".format(
514
+ " → ".join("Phase {} ({})".format(p, phase_map.get(p, ("?",))[0])
515
+ for p in remaining)))
516
+ lines.append(" Commit: <commit hash>")
517
+ lines.append("```")
518
+ lines.append("")
519
+
520
+ # Reminders
521
+ lines.append("## Reminders")
522
+ lines.append("")
523
+ lines.append("- All bug-fix artifacts go in `.prizmkit/bugfix/{}/`".format(bug_id))
524
+ lines.append("- Commit with `fix(<scope>): <description>` prefix")
525
+ lines.append("- Do NOT ask for user input — this is autonomous")
526
+ lines.append("- Do NOT stop before completing ALL remaining phases")
527
+ lines.append("- `/prizmkit-committer` is MANDATORY — do NOT skip the commit phase")
528
+ lines.append("- `/prizmkit-retrospective` is MANDATORY — do NOT skip the docs sync phase")
529
+
530
+ return "\n".join(lines)
531
+
532
+
533
+ def build_feature_prompt(detection, project_root):
534
+ """Build recovery prompt for feature-workflow."""
535
+ context = detection.get("context", {})
536
+ branch = context.get("branch", "unknown")
537
+ phase = detection.get("phase", 1)
538
+ phase_name = detection.get("phase_name", "Unknown")
539
+ recovery = detection.get("recovery", {})
540
+
541
+ artifacts = read_feature_artifacts(project_root)
542
+ remaining, phase_map = get_remaining_phases("feature-workflow", phase)
543
+
544
+ lines = []
545
+ lines.append("# Recovery Session — Feature Workflow")
546
+ lines.append("")
547
+ lines.append("## Context")
548
+ lines.append("")
549
+ lines.append("You are RECOVERING an interrupted feature-workflow session.")
550
+ lines.append("")
551
+ lines.append("- **Branch**: {}".format(branch))
552
+ lines.append("- **Interrupted at**: Phase {} — {}".format(phase, phase_name))
553
+ lines.append("- **Remaining work**: {}".format(recovery.get("remaining_work", "unknown")))
554
+ lines.append("")
555
+
556
+ lines.append("## CRITICAL RULES")
557
+ lines.append("")
558
+ lines.append("1. You MUST complete ALL remaining phases listed below — do NOT stop early")
559
+ lines.append("2. Execute phases in ORDER. Do NOT skip any phase.")
560
+ lines.append("3. After the LAST phase, output a recovery summary.")
561
+ lines.append("4. This is a NON-INTERACTIVE autonomous session — proceed without asking for user input.")
562
+ lines.append("")
563
+
564
+ if artifacts:
565
+ lines.append("## Existing Artifacts")
566
+ lines.append("")
567
+ lines.append(format_artifact_section(artifacts))
568
+ lines.append("")
569
+
570
+ lines.append("---")
571
+ lines.append("")
572
+ lines.append("## Remaining Phases — Execute ALL of these in order")
573
+ lines.append("")
574
+
575
+ for i, phase_num in enumerate(remaining):
576
+ name, instructions = phase_map.get(phase_num, ("Unknown", ""))
577
+ label = "CURRENT PHASE" if i == 0 else ""
578
+ if label:
579
+ lines.append("### Phase {}: {} — {}".format(phase_num, name, label))
580
+ else:
581
+ lines.append("### Phase {}: {}".format(phase_num, name))
582
+ lines.append("")
583
+ lines.append(instructions)
584
+ lines.append("")
585
+
586
+ lines.append("---")
587
+ lines.append("")
588
+ lines.append("## FINAL: Recovery Summary")
589
+ lines.append("")
590
+ lines.append("After ALL phases above are complete, output:")
591
+ lines.append("")
592
+ lines.append("```")
593
+ lines.append("Recovery complete.")
594
+ lines.append(" Workflow: feature-workflow")
595
+ lines.append(" Recovered from: Phase {} ({})".format(phase, phase_name))
596
+ lines.append(" Completed: {}".format(
597
+ " → ".join("Phase {} ({})".format(p, phase_map.get(p, ("?",))[0])
598
+ for p in remaining)))
599
+ lines.append("```")
600
+ lines.append("")
601
+
602
+ lines.append("## Reminders")
603
+ lines.append("")
604
+ lines.append("- Use `/feature-pipeline-launcher` to start the pipeline (Phase 3)")
605
+ lines.append("- Do NOT ask for user input — this is autonomous")
606
+ lines.append("- Do NOT stop before completing ALL remaining phases")
607
+
608
+ return "\n".join(lines)
609
+
610
+
611
+ def build_refactor_prompt(detection, project_root):
612
+ """Build recovery prompt for refactor-workflow."""
613
+ context = detection.get("context", {})
614
+ branch = context.get("branch", "unknown")
615
+ phase = detection.get("phase", 1)
616
+ phase_name = detection.get("phase_name", "Unknown")
617
+ recovery = detection.get("recovery", {})
618
+
619
+ artifacts = read_refactor_artifacts(project_root)
620
+ remaining, phase_map = get_remaining_phases("refactor-workflow", phase)
621
+
622
+ lines = []
623
+ lines.append("# Recovery Session — Refactor Workflow")
624
+ lines.append("")
625
+ lines.append("## Context")
626
+ lines.append("")
627
+ lines.append("You are RECOVERING an interrupted refactor-workflow session.")
628
+ lines.append("")
629
+ lines.append("- **Branch**: {}".format(branch))
630
+ lines.append("- **Interrupted at**: Phase {} — {}".format(phase, phase_name))
631
+ lines.append("- **Remaining work**: {}".format(recovery.get("remaining_work", "unknown")))
632
+ lines.append("")
633
+
634
+ lines.append("## CRITICAL RULES")
635
+ lines.append("")
636
+ lines.append("1. You MUST complete ALL remaining phases listed below — do NOT stop early")
637
+ lines.append("2. Execute phases in ORDER. Do NOT skip any phase.")
638
+ lines.append("3. After the LAST phase, output a recovery summary.")
639
+ lines.append("4. This is a NON-INTERACTIVE autonomous session — proceed without asking for user input.")
640
+ lines.append("")
641
+
642
+ if artifacts:
643
+ lines.append("## Existing Artifacts")
644
+ lines.append("")
645
+ lines.append(format_artifact_section(artifacts))
646
+ lines.append("")
647
+
648
+ lines.append("---")
649
+ lines.append("")
650
+ lines.append("## Remaining Phases — Execute ALL of these in order")
651
+ lines.append("")
652
+
653
+ for i, phase_num in enumerate(remaining):
654
+ name, instructions = phase_map.get(phase_num, ("Unknown", ""))
655
+ label = "CURRENT PHASE" if i == 0 else ""
656
+ if label:
657
+ lines.append("### Phase {}: {} — {}".format(phase_num, name, label))
658
+ else:
659
+ lines.append("### Phase {}: {}".format(phase_num, name))
660
+ lines.append("")
661
+ lines.append(instructions)
662
+ lines.append("")
663
+
664
+ lines.append("---")
665
+ lines.append("")
666
+ lines.append("## FINAL: Recovery Summary")
667
+ lines.append("")
668
+ lines.append("After ALL phases above are complete, output:")
669
+ lines.append("")
670
+ lines.append("```")
671
+ lines.append("Recovery complete.")
672
+ lines.append(" Workflow: refactor-workflow")
673
+ lines.append(" Recovered from: Phase {} ({})".format(phase, phase_name))
674
+ lines.append(" Completed: {}".format(
675
+ " → ".join("Phase {} ({})".format(p, phase_map.get(p, ("?",))[0])
676
+ for p in remaining)))
677
+ lines.append("```")
678
+ lines.append("")
679
+
680
+ lines.append("## Reminders")
681
+ lines.append("")
682
+ lines.append("- Use `/refactor-pipeline-launcher` to start the pipeline (Phase 3)")
683
+ lines.append("- Do NOT ask for user input — this is autonomous")
684
+ lines.append("- Do NOT stop before completing ALL remaining phases")
685
+
686
+ return "\n".join(lines)
687
+
688
+
689
+ # ============================================================
690
+ # Main
691
+ # ============================================================
692
+
693
+ PROMPT_BUILDERS = {
694
+ "bug-fix-workflow": build_bugfix_prompt,
695
+ "feature-workflow": build_feature_prompt,
696
+ "refactor-workflow": build_refactor_prompt,
697
+ }
698
+
699
+
700
+ def parse_args():
701
+ parser = argparse.ArgumentParser(
702
+ description="Generate a recovery bootstrap prompt from detection output",
703
+ )
704
+ parser.add_argument(
705
+ "--detection-json",
706
+ required=True,
707
+ help="Path to JSON file with detect-recovery-state.py output",
708
+ )
709
+ parser.add_argument(
710
+ "--output",
711
+ required=True,
712
+ help="Output path for the rendered prompt",
713
+ )
714
+ parser.add_argument(
715
+ "--project-root",
716
+ default=None,
717
+ help="Project root directory (default: auto-detect from git)",
718
+ )
719
+ parser.add_argument(
720
+ "--session-id",
721
+ default=None,
722
+ help="Session ID for this recovery session",
723
+ )
724
+ return parser.parse_args()
725
+
726
+
727
+ def resolve_project_root(given_root):
728
+ """Resolve project root from argument or git."""
729
+ if given_root:
730
+ return os.path.abspath(given_root)
731
+ # Auto-detect across two layouts:
732
+ # <project>/.prizmkit/dev-pipeline/scripts/ → up 3 levels
733
+ # <repo>/dev-pipeline/scripts/ → up 2 levels
734
+ script_dir = os.path.dirname(os.path.abspath(__file__))
735
+ pipeline_dir = os.path.dirname(script_dir)
736
+ pipeline_parent = os.path.dirname(pipeline_dir)
737
+ if os.path.basename(pipeline_parent) == ".prizmkit":
738
+ return os.path.dirname(pipeline_parent)
739
+ return pipeline_parent
740
+
741
+
742
+ def emit_failure(message):
743
+ """Emit standardized failure JSON and exit."""
744
+ print(json.dumps({"success": False, "error": message}, indent=2, ensure_ascii=False))
745
+ sys.exit(1)
746
+
747
+
748
+ def main():
749
+ args = parse_args()
750
+ project_root = resolve_project_root(args.project_root)
751
+
752
+ # Load detection JSON
753
+ detection, err = load_json_file(args.detection_json)
754
+ if err:
755
+ emit_failure("Detection JSON error: {}".format(err))
756
+
757
+ if not detection.get("detected"):
758
+ emit_failure("No interrupted workflow detected — nothing to recover")
759
+
760
+ workflow_type = detection.get("workflow_type")
761
+ if workflow_type not in PROMPT_BUILDERS:
762
+ emit_failure("Unknown workflow type: {}".format(workflow_type))
763
+
764
+ # Build prompt
765
+ builder = PROMPT_BUILDERS[workflow_type]
766
+ prompt_content = builder(detection, project_root)
767
+
768
+ # Write output
769
+ output_path = os.path.abspath(args.output)
770
+ output_dir = os.path.dirname(output_path)
771
+ if output_dir and not os.path.isdir(output_dir):
772
+ os.makedirs(output_dir, exist_ok=True)
773
+
774
+ try:
775
+ with open(output_path, "w", encoding="utf-8") as f:
776
+ f.write(prompt_content)
777
+ except IOError as e:
778
+ emit_failure("Cannot write output: {}".format(str(e)))
779
+
780
+ # Success JSON
781
+ phase = detection.get("phase", 0)
782
+ phase_name = detection.get("phase_name", "Unknown")
783
+ remaining, _ = get_remaining_phases(workflow_type, phase)
784
+ output = {
785
+ "success": True,
786
+ "workflow_type": workflow_type,
787
+ "resume_phase": phase,
788
+ "resume_phase_name": phase_name,
789
+ "remaining_phases": remaining,
790
+ "prompt_path": output_path,
791
+ }
792
+ print(json.dumps(output, indent=2, ensure_ascii=False))
793
+ sys.exit(0)
794
+
795
+
796
+ if __name__ == "__main__":
797
+ try:
798
+ main()
799
+ except KeyboardInterrupt:
800
+ emit_failure("generate-recovery-prompt interrupted")
801
+ except SystemExit:
802
+ raise
803
+ except Exception as exc:
804
+ LOGGER.exception("Unhandled exception in generate-recovery-prompt")
805
+ emit_failure("Unexpected error: {}".format(str(exc)))