@12ui/design 0.2.55 → 0.2.57

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 (222) hide show
  1. package/SKILL.md +1 -1
  2. package/dist/branch-client.d.ts +2 -0
  3. package/dist/branch-client.d.ts.map +1 -1
  4. package/dist/branch-client.js +1 -0
  5. package/dist/branch-client.js.map +1 -1
  6. package/dist/cli-arguments.d.ts.map +1 -1
  7. package/dist/cli-arguments.js +2 -0
  8. package/dist/cli-arguments.js.map +1 -1
  9. package/dist/cli-conversion-derivation.d.ts +2 -1
  10. package/dist/cli-conversion-derivation.d.ts.map +1 -1
  11. package/dist/cli-conversion-derivation.js +9 -1
  12. package/dist/cli-conversion-derivation.js.map +1 -1
  13. package/dist/cli-convert-command.d.ts.map +1 -1
  14. package/dist/cli-convert-command.js +111 -16
  15. package/dist/cli-convert-command.js.map +1 -1
  16. package/dist/cli-corpus-command.d.ts.map +1 -1
  17. package/dist/cli-corpus-command.js +5 -2
  18. package/dist/cli-corpus-command.js.map +1 -1
  19. package/dist/cli-corpus-evidence.d.ts.map +1 -1
  20. package/dist/cli-corpus-evidence.js +2 -1
  21. package/dist/cli-corpus-evidence.js.map +1 -1
  22. package/dist/cli-corpus-reference-downloads.d.ts +1 -0
  23. package/dist/cli-corpus-reference-downloads.d.ts.map +1 -1
  24. package/dist/cli-corpus-reference-downloads.js +13 -3
  25. package/dist/cli-corpus-reference-downloads.js.map +1 -1
  26. package/dist/cli-corpus-types.d.ts +2 -0
  27. package/dist/cli-corpus-types.d.ts.map +1 -1
  28. package/dist/cli-draft-command.d.ts +11 -0
  29. package/dist/cli-draft-command.d.ts.map +1 -1
  30. package/dist/cli-draft-command.js +10 -1
  31. package/dist/cli-draft-command.js.map +1 -1
  32. package/dist/cli-help/design.d.ts +2 -2
  33. package/dist/cli-help/design.d.ts.map +1 -1
  34. package/dist/cli-help/design.js +12 -2
  35. package/dist/cli-help/design.js.map +1 -1
  36. package/dist/cli-help/index.d.ts +2 -2
  37. package/dist/cli-improve-command.d.ts.map +1 -1
  38. package/dist/cli-improve-command.js +317 -70
  39. package/dist/cli-improve-command.js.map +1 -1
  40. package/dist/cli-next-command.d.ts.map +1 -1
  41. package/dist/cli-next-command.js +44 -4
  42. package/dist/cli-next-command.js.map +1 -1
  43. package/dist/cli-usage.js +2 -2
  44. package/dist/concept-input.d.ts +21 -0
  45. package/dist/concept-input.d.ts.map +1 -1
  46. package/dist/concept-input.js +32 -10
  47. package/dist/concept-input.js.map +1 -1
  48. package/dist/conversion-client.d.ts +39 -1
  49. package/dist/conversion-client.d.ts.map +1 -1
  50. package/dist/conversion-client.js +205 -3
  51. package/dist/conversion-client.js.map +1 -1
  52. package/dist/corpus-client.d.ts +7 -1
  53. package/dist/corpus-client.d.ts.map +1 -1
  54. package/dist/corpus-client.js +6 -2
  55. package/dist/corpus-client.js.map +1 -1
  56. package/dist/corpus-reference-download-retry.d.ts +68 -0
  57. package/dist/corpus-reference-download-retry.d.ts.map +1 -0
  58. package/dist/corpus-reference-download-retry.js +123 -0
  59. package/dist/corpus-reference-download-retry.js.map +1 -0
  60. package/dist/corpus-request-error.d.ts +17 -0
  61. package/dist/corpus-request-error.d.ts.map +1 -0
  62. package/dist/corpus-request-error.js +21 -0
  63. package/dist/corpus-request-error.js.map +1 -0
  64. package/dist/draft-run.d.ts +9 -0
  65. package/dist/draft-run.d.ts.map +1 -1
  66. package/dist/draft-run.js +22 -5
  67. package/dist/draft-run.js.map +1 -1
  68. package/dist/draft-workspace.d.ts +2 -1
  69. package/dist/draft-workspace.d.ts.map +1 -1
  70. package/dist/draft-workspace.js.map +1 -1
  71. package/dist/hosted-draft-identity.d.ts +1 -0
  72. package/dist/hosted-draft-identity.d.ts.map +1 -1
  73. package/dist/hosted-draft-identity.js +1 -0
  74. package/dist/hosted-draft-identity.js.map +1 -1
  75. package/dist/improve-added-specs.d.ts +9 -0
  76. package/dist/improve-added-specs.d.ts.map +1 -1
  77. package/dist/improve-added-specs.js +28 -7
  78. package/dist/improve-added-specs.js.map +1 -1
  79. package/dist/improve-bootstrap-secret.d.ts +35 -0
  80. package/dist/improve-bootstrap-secret.d.ts.map +1 -0
  81. package/dist/improve-bootstrap-secret.js +61 -0
  82. package/dist/improve-bootstrap-secret.js.map +1 -0
  83. package/dist/improve-capture-redirect.d.ts +46 -0
  84. package/dist/improve-capture-redirect.d.ts.map +1 -0
  85. package/dist/improve-capture-redirect.js +68 -0
  86. package/dist/improve-capture-redirect.js.map +1 -0
  87. package/dist/improve-concept.d.ts +14 -1
  88. package/dist/improve-concept.d.ts.map +1 -1
  89. package/dist/improve-concept.js +29 -8
  90. package/dist/improve-concept.js.map +1 -1
  91. package/dist/improve-conversion-attempts.d.ts +96 -0
  92. package/dist/improve-conversion-attempts.d.ts.map +1 -0
  93. package/dist/improve-conversion-attempts.js +93 -0
  94. package/dist/improve-conversion-attempts.js.map +1 -0
  95. package/dist/improve-conversion-stage.d.ts +14 -0
  96. package/dist/improve-conversion-stage.d.ts.map +1 -1
  97. package/dist/improve-conversion-stage.js +254 -70
  98. package/dist/improve-conversion-stage.js.map +1 -1
  99. package/dist/improve-convert-progress.d.ts +36 -0
  100. package/dist/improve-convert-progress.d.ts.map +1 -0
  101. package/dist/improve-convert-progress.js +43 -0
  102. package/dist/improve-convert-progress.js.map +1 -0
  103. package/dist/improve-convert-resilience.d.ts +116 -0
  104. package/dist/improve-convert-resilience.d.ts.map +1 -1
  105. package/dist/improve-convert-resilience.js +158 -1
  106. package/dist/improve-convert-resilience.js.map +1 -1
  107. package/dist/improve-delivery-stages.d.ts.map +1 -1
  108. package/dist/improve-delivery-stages.js +5 -0
  109. package/dist/improve-delivery-stages.js.map +1 -1
  110. package/dist/improve-dom-diff.d.ts +2 -0
  111. package/dist/improve-dom-diff.d.ts.map +1 -1
  112. package/dist/improve-dom-diff.js +7 -0
  113. package/dist/improve-dom-diff.js.map +1 -1
  114. package/dist/improve-dom-gate.d.ts +7 -0
  115. package/dist/improve-dom-gate.d.ts.map +1 -1
  116. package/dist/improve-dom-gate.js +13 -0
  117. package/dist/improve-dom-gate.js.map +1 -1
  118. package/dist/improve-generation-stages.d.ts +3 -0
  119. package/dist/improve-generation-stages.d.ts.map +1 -1
  120. package/dist/improve-generation-stages.js +56 -10
  121. package/dist/improve-generation-stages.js.map +1 -1
  122. package/dist/improve-icon-svg.d.ts +47 -0
  123. package/dist/improve-icon-svg.d.ts.map +1 -0
  124. package/dist/improve-icon-svg.js +83 -0
  125. package/dist/improve-icon-svg.js.map +1 -0
  126. package/dist/improve-kit-assets.d.ts +129 -0
  127. package/dist/improve-kit-assets.d.ts.map +1 -0
  128. package/dist/improve-kit-assets.js +333 -0
  129. package/dist/improve-kit-assets.js.map +1 -0
  130. package/dist/improve-kit-ignore.d.ts +32 -0
  131. package/dist/improve-kit-ignore.d.ts.map +1 -0
  132. package/dist/improve-kit-ignore.js +111 -0
  133. package/dist/improve-kit-ignore.js.map +1 -0
  134. package/dist/improve-kit-readme.d.ts +11 -2
  135. package/dist/improve-kit-readme.d.ts.map +1 -1
  136. package/dist/improve-kit-readme.js +282 -26
  137. package/dist/improve-kit-readme.js.map +1 -1
  138. package/dist/improve-kit-stall.d.ts +113 -0
  139. package/dist/improve-kit-stall.d.ts.map +1 -0
  140. package/dist/improve-kit-stall.js +311 -0
  141. package/dist/improve-kit-stall.js.map +1 -0
  142. package/dist/improve-kit-status.d.ts +105 -0
  143. package/dist/improve-kit-status.d.ts.map +1 -0
  144. package/dist/improve-kit-status.js +215 -0
  145. package/dist/improve-kit-status.js.map +1 -0
  146. package/dist/improve-options.d.ts +16 -1
  147. package/dist/improve-options.d.ts.map +1 -1
  148. package/dist/improve-options.js +65 -15
  149. package/dist/improve-options.js.map +1 -1
  150. package/dist/improve-plan-annotated-render.d.ts +45 -0
  151. package/dist/improve-plan-annotated-render.d.ts.map +1 -0
  152. package/dist/improve-plan-annotated-render.js +196 -0
  153. package/dist/improve-plan-annotated-render.js.map +1 -0
  154. package/dist/improve-plan-annotator.d.ts +7 -1
  155. package/dist/improve-plan-annotator.d.ts.map +1 -1
  156. package/dist/improve-plan-annotator.js +22 -45
  157. package/dist/improve-plan-annotator.js.map +1 -1
  158. package/dist/improve-raster-layers-section.d.ts +21 -0
  159. package/dist/improve-raster-layers-section.d.ts.map +1 -0
  160. package/dist/improve-raster-layers-section.js +45 -0
  161. package/dist/improve-raster-layers-section.js.map +1 -0
  162. package/dist/improve-reset.d.ts +122 -0
  163. package/dist/improve-reset.d.ts.map +1 -0
  164. package/dist/improve-reset.js +141 -0
  165. package/dist/improve-reset.js.map +1 -0
  166. package/dist/improve-run-summary.d.ts +35 -0
  167. package/dist/improve-run-summary.d.ts.map +1 -0
  168. package/dist/improve-run-summary.js +180 -0
  169. package/dist/improve-run-summary.js.map +1 -0
  170. package/dist/improve-stage-shared.d.ts +44 -1
  171. package/dist/improve-stage-shared.d.ts.map +1 -1
  172. package/dist/improve-stage-shared.js +80 -3
  173. package/dist/improve-stage-shared.js.map +1 -1
  174. package/dist/improve-stop-handler.d.ts +73 -0
  175. package/dist/improve-stop-handler.d.ts.map +1 -0
  176. package/dist/improve-stop-handler.js +126 -0
  177. package/dist/improve-stop-handler.js.map +1 -0
  178. package/dist/improve-terminal-event.d.ts +118 -0
  179. package/dist/improve-terminal-event.d.ts.map +1 -0
  180. package/dist/improve-terminal-event.js +87 -0
  181. package/dist/improve-terminal-event.js.map +1 -0
  182. package/dist/improve-token-patch.d.ts +2 -0
  183. package/dist/improve-token-patch.d.ts.map +1 -1
  184. package/dist/improve-token-patch.js +23 -5
  185. package/dist/improve-token-patch.js.map +1 -1
  186. package/dist/improve-workspace.d.ts +94 -2
  187. package/dist/improve-workspace.d.ts.map +1 -1
  188. package/dist/improve-workspace.js +19 -1
  189. package/dist/improve-workspace.js.map +1 -1
  190. package/dist/index.d.ts +2 -1
  191. package/dist/index.d.ts.map +1 -1
  192. package/dist/index.js +1 -0
  193. package/dist/index.js.map +1 -1
  194. package/dist/legacy-skill-catalog.d.ts.map +1 -1
  195. package/dist/legacy-skill-catalog.js +143 -0
  196. package/dist/legacy-skill-catalog.js.map +1 -1
  197. package/dist/mcp-tool-definitions.js +1 -1
  198. package/dist/mcp-tool-definitions.js.map +1 -1
  199. package/dist/mcp-tool-handler.d.ts.map +1 -1
  200. package/dist/mcp-tool-handler.js +3 -0
  201. package/dist/mcp-tool-handler.js.map +1 -1
  202. package/dist/redesign-capture.d.ts +17 -0
  203. package/dist/redesign-capture.d.ts.map +1 -1
  204. package/dist/redesign-capture.js +55 -3
  205. package/dist/redesign-capture.js.map +1 -1
  206. package/dist/responsive-alternative-materializer.d.ts +19 -0
  207. package/dist/responsive-alternative-materializer.d.ts.map +1 -0
  208. package/dist/responsive-alternative-materializer.js +76 -0
  209. package/dist/responsive-alternative-materializer.js.map +1 -0
  210. package/dist/run-journal-unfinished.d.ts +56 -0
  211. package/dist/run-journal-unfinished.d.ts.map +1 -0
  212. package/dist/run-journal-unfinished.js +126 -0
  213. package/dist/run-journal-unfinished.js.map +1 -0
  214. package/dist/run-journal.d.ts +25 -1
  215. package/dist/run-journal.d.ts.map +1 -1
  216. package/dist/run-journal.js +15 -1
  217. package/dist/run-journal.js.map +1 -1
  218. package/open-design.json +2 -2
  219. package/package.json +1 -1
  220. package/skills/12ui-design/SKILL.md +9 -1
  221. package/skills/12ui-design/improve.md +83 -6
  222. package/skills/12ui-design/inspire.md +1 -1
@@ -10,7 +10,7 @@ export declare const DESIGN_HELP: {
10
10
  readonly summary: "Search the Design Corpus and download validated visual references.";
11
11
  readonly sections: readonly [{
12
12
  readonly heading: "Behavior";
13
- readonly items: readonly ["Runs in the foreground and writes an attempt record before the metered search, then a manifest, evidence, receipts, and downloaded references.", "Defaults to four references in balanced mode; --count accepts 1–48.", "--reference-image conditions retrieval on an existing PNG, JPEG, or WebP."];
13
+ readonly items: readonly ["Runs in the foreground and writes an attempt record before the metered search, then a manifest, evidence, receipts, and downloaded references.", "Defaults to four references in balanced mode; --count accepts 1–48 (hedge: 4–12).", "--reference-image conditions retrieval on an existing PNG, JPEG, or WebP."];
14
14
  }, {
15
15
  readonly heading: "Modes";
16
16
  readonly items: readonly ["direct stays closest to the literal query.", "balanced is the default relevance, quality, and variety trade-off.", "adventurer keeps a relevant head while exploring less expected directions."];
@@ -84,7 +84,7 @@ export declare const DESIGN_HELP: {
84
84
  readonly summary: "Improve one live interface or screenshot and produce a replayable implementation kit.";
85
85
  readonly sections: readonly [{
86
86
  readonly heading: "Behavior";
87
- readonly items: readonly ["Five stages run in order: local capture, hosted draft candidates retaining layout and content, explicit pick, fused LayerDoc and responsive HTML conversion, then a local implementation plan.", "URL input uses one Playwright context for repeated --bootstrap actions, screenshot capture, and selector-verified DOM extraction. Image input normalizes the source locally.", "The kit keeps every candidate, winner, target, plan, assets, and improve.json replay record. Repeating a settled stage reuses it; --from pick --pick <slot> invalidates only the old target and plan.", "--responsive-quality selects standard or pro responsive export. If that export fails or reaches the improve deadline after LayerDoc materialization, improve derives fixed HTML free and continues to plan with a warning.", "--fresh abandons and records a stuck conversion identity, then uses a new idempotency key. A temporarily unavailable stage retries once after 30 seconds.", "--target brings your own design image or LayerDoc, skips draft and pick, converts an image when needed, and aligns the plan to the captured URL DOM."];
87
+ readonly items: readonly ["Five stages run in order: local capture, hosted draft candidates retaining layout and content, explicit pick, fused LayerDoc and responsive HTML conversion, then a local implementation plan.", "The pick is explicit and has no default. With no --pick and no pick already recorded, the run stops after the draw, prints where the candidates are and the exact command that continues (--from pick --pick <slot>), and buys no conversion: converting a candidate nobody chose spends money on a guess that cannot be cancelled. --target supplies the design instead and skips draft and pick.", "URL input uses one Playwright context for repeated --bootstrap actions, screenshot capture, and selector-verified DOM extraction. Image input normalizes the source locally.", string, "The kit keeps every candidate, winner, target, plan, assets, and improve.json replay record. Repeating a settled stage reuses it; --from pick --pick <slot> invalidates only the old target and plan.", "--responsive-quality selects standard or pro responsive export. If that export fails or reaches the improve deadline after LayerDoc materialization, improve derives fixed HTML free and continues to plan with a warning.", "--convert-stall-seconds bounds every hosted wait the convert stage makes, including the free fixed-layout derivation (default: twice the model's typical wall, 480s standard and pro, 300s fast; refused below one typical wall). If a wait ends with no LayerDoc on disk there is nothing to derive, so improve records the abandoned conversion and dispatches exactly ONE fresh one; a second stall writes plan/STALL.md and exits non-zero. The retry budget belongs to the kit: a resume re-attaches to the newest conversion already bought, a kit that has spent its retry refuses to dispatch again, and a pro conversion is never retried automatically because no measured wall justifies it. Stopping the wait does not stop the conversion: there is no cancel, so an abandoned run keeps billing.", "--fresh re-buys ONE conversion of the same settled winner under a new idempotency key: it records the abandoned conversion identity and reuses capture, draft and pick untouched. --redraw is the one that buys new candidates — it discards draft, pick, convert and plan, moves the old draw to candidates.previous, records any conversion it drops, and runs the draft stage again; it is also the one path allowed to change --direction, --candidates or --retain against the record. A temporarily unavailable stage retries once after 30 seconds.", "--target brings your own design image or LayerDoc, skips draft and pick, converts an image when needed, and aligns the plan to the captured URL DOM."];
88
88
  }, {
89
89
  readonly heading: "Planning";
90
90
  readonly items: readonly ["URL plans require at least 60% plausible DOM-side coverage; a blocked gate writes GATE.md while target HTML and LayerDoc remain authoritative sidecars.", "Image plans are target-only by default. --plan-source-convert buys one source LayerDoc conversion for an unanchored LayerDoc comparison.", "--repo adds evidence-ranked src/ TSX, JSX, and CSS file hints to a URL plan. The command never applies code.", "--dry-run prints exact catalog price ceilings for every stage and makes no network request."];
@@ -1 +1 @@
1
- {"version":3,"file":"design.d.ts","sourceRoot":"","sources":["../../src/cli-help/design.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8NW,CAAC"}
1
+ {"version":3,"file":"design.d.ts","sourceRoot":"","sources":["../../src/cli-help/design.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwOW,CAAC"}
@@ -16,7 +16,7 @@ export const DESIGN_HELP = {
16
16
  heading: 'Behavior',
17
17
  items: [
18
18
  'Runs in the foreground and writes an attempt record before the metered search, then a manifest, evidence, receipts, and downloaded references.',
19
- 'Defaults to four references in balanced mode; --count accepts 1–48.',
19
+ 'Defaults to four references in balanced mode; --count accepts 1–48 (hedge: 4–12).',
20
20
  '--reference-image conditions retrieval on an existing PNG, JPEG, or WebP.',
21
21
  ],
22
22
  },
@@ -168,10 +168,20 @@ export const DESIGN_HELP = {
168
168
  heading: 'Behavior',
169
169
  items: [
170
170
  'Five stages run in order: local capture, hosted draft candidates retaining layout and content, explicit pick, fused LayerDoc and responsive HTML conversion, then a local implementation plan.',
171
+ 'The pick is explicit and has no default. With no --pick and no pick already recorded, the run stops after the draw, prints where the candidates are and the exact command that continues (--from pick --pick <slot>), and buys no conversion: converting a candidate nobody chose spends money on a guess that cannot be cancelled. --target supplies the design instead and skips draft and pick.',
171
172
  'URL input uses one Playwright context for repeated --bootstrap actions, screenshot capture, and selector-verified DOM extraction. Image input normalizes the source locally.',
173
+ "--bootstrap takes ONE quoted pipe-separated triple, not three alternatives:"
174
+ + " '<url>|<click-selector>|<wait-url>'. Any field may be empty and the flag repeats, so"
175
+ + " --bootstrap '|button[data-test=sign-in]|**/dashboard' clicks and then waits. A value"
176
+ + ' with no pipe is read as a click selector unless it starts with http:// or https://.'
177
+ + ' A magic-link triple carries a live session token, so improve.json records only a'
178
+ + ' redacted form of it (query values and fragment replaced) plus a sha256; the live'
179
+ + ' value is never written to disk, and a resume that has to capture again asks for'
180
+ + ' --bootstrap once more.',
172
181
  'The kit keeps every candidate, winner, target, plan, assets, and improve.json replay record. Repeating a settled stage reuses it; --from pick --pick <slot> invalidates only the old target and plan.',
173
182
  '--responsive-quality selects standard or pro responsive export. If that export fails or reaches the improve deadline after LayerDoc materialization, improve derives fixed HTML free and continues to plan with a warning.',
174
- '--fresh abandons and records a stuck conversion identity, then uses a new idempotency key. A temporarily unavailable stage retries once after 30 seconds.',
183
+ "--convert-stall-seconds bounds every hosted wait the convert stage makes, including the free fixed-layout derivation (default: twice the model's typical wall, 480s standard and pro, 300s fast; refused below one typical wall). If a wait ends with no LayerDoc on disk there is nothing to derive, so improve records the abandoned conversion and dispatches exactly ONE fresh one; a second stall writes plan/STALL.md and exits non-zero. The retry budget belongs to the kit: a resume re-attaches to the newest conversion already bought, a kit that has spent its retry refuses to dispatch again, and a pro conversion is never retried automatically because no measured wall justifies it. Stopping the wait does not stop the conversion: there is no cancel, so an abandoned run keeps billing.",
184
+ '--fresh re-buys ONE conversion of the same settled winner under a new idempotency key: it records the abandoned conversion identity and reuses capture, draft and pick untouched. --redraw is the one that buys new candidates — it discards draft, pick, convert and plan, moves the old draw to candidates.previous, records any conversion it drops, and runs the draft stage again; it is also the one path allowed to change --direction, --candidates or --retain against the record. A temporarily unavailable stage retries once after 30 seconds.',
175
185
  '--target brings your own design image or LayerDoc, skips draft and pick, converts an image when needed, and aligns the plan to the captured URL DOM.',
176
186
  ],
177
187
  },
@@ -1 +1 @@
1
- {"version":3,"file":"design.js","sourceRoot":"","sources":["../../src/cli-help/design.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"design.js","sourceRoot":"","sources":["../../src/cli-help/design.ts"],"names":[],"mappings":"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"}
@@ -70,7 +70,7 @@ export declare const CLI_HELP_CONTEXTS: {
70
70
  readonly summary: "Search the Design Corpus and download validated visual references.";
71
71
  readonly sections: readonly [{
72
72
  readonly heading: "Behavior";
73
- readonly items: readonly ["Runs in the foreground and writes an attempt record before the metered search, then a manifest, evidence, receipts, and downloaded references.", "Defaults to four references in balanced mode; --count accepts 1–48.", "--reference-image conditions retrieval on an existing PNG, JPEG, or WebP."];
73
+ readonly items: readonly ["Runs in the foreground and writes an attempt record before the metered search, then a manifest, evidence, receipts, and downloaded references.", "Defaults to four references in balanced mode; --count accepts 1–48 (hedge: 4–12).", "--reference-image conditions retrieval on an existing PNG, JPEG, or WebP."];
74
74
  }, {
75
75
  readonly heading: "Modes";
76
76
  readonly items: readonly ["direct stays closest to the literal query.", "balanced is the default relevance, quality, and variety trade-off.", "adventurer keeps a relevant head while exploring less expected directions."];
@@ -144,7 +144,7 @@ export declare const CLI_HELP_CONTEXTS: {
144
144
  readonly summary: "Improve one live interface or screenshot and produce a replayable implementation kit.";
145
145
  readonly sections: readonly [{
146
146
  readonly heading: "Behavior";
147
- readonly items: readonly ["Five stages run in order: local capture, hosted draft candidates retaining layout and content, explicit pick, fused LayerDoc and responsive HTML conversion, then a local implementation plan.", "URL input uses one Playwright context for repeated --bootstrap actions, screenshot capture, and selector-verified DOM extraction. Image input normalizes the source locally.", "The kit keeps every candidate, winner, target, plan, assets, and improve.json replay record. Repeating a settled stage reuses it; --from pick --pick <slot> invalidates only the old target and plan.", "--responsive-quality selects standard or pro responsive export. If that export fails or reaches the improve deadline after LayerDoc materialization, improve derives fixed HTML free and continues to plan with a warning.", "--fresh abandons and records a stuck conversion identity, then uses a new idempotency key. A temporarily unavailable stage retries once after 30 seconds.", "--target brings your own design image or LayerDoc, skips draft and pick, converts an image when needed, and aligns the plan to the captured URL DOM."];
147
+ readonly items: readonly ["Five stages run in order: local capture, hosted draft candidates retaining layout and content, explicit pick, fused LayerDoc and responsive HTML conversion, then a local implementation plan.", "The pick is explicit and has no default. With no --pick and no pick already recorded, the run stops after the draw, prints where the candidates are and the exact command that continues (--from pick --pick <slot>), and buys no conversion: converting a candidate nobody chose spends money on a guess that cannot be cancelled. --target supplies the design instead and skips draft and pick.", "URL input uses one Playwright context for repeated --bootstrap actions, screenshot capture, and selector-verified DOM extraction. Image input normalizes the source locally.", string, "The kit keeps every candidate, winner, target, plan, assets, and improve.json replay record. Repeating a settled stage reuses it; --from pick --pick <slot> invalidates only the old target and plan.", "--responsive-quality selects standard or pro responsive export. If that export fails or reaches the improve deadline after LayerDoc materialization, improve derives fixed HTML free and continues to plan with a warning.", "--convert-stall-seconds bounds every hosted wait the convert stage makes, including the free fixed-layout derivation (default: twice the model's typical wall, 480s standard and pro, 300s fast; refused below one typical wall). If a wait ends with no LayerDoc on disk there is nothing to derive, so improve records the abandoned conversion and dispatches exactly ONE fresh one; a second stall writes plan/STALL.md and exits non-zero. The retry budget belongs to the kit: a resume re-attaches to the newest conversion already bought, a kit that has spent its retry refuses to dispatch again, and a pro conversion is never retried automatically because no measured wall justifies it. Stopping the wait does not stop the conversion: there is no cancel, so an abandoned run keeps billing.", "--fresh re-buys ONE conversion of the same settled winner under a new idempotency key: it records the abandoned conversion identity and reuses capture, draft and pick untouched. --redraw is the one that buys new candidates — it discards draft, pick, convert and plan, moves the old draw to candidates.previous, records any conversion it drops, and runs the draft stage again; it is also the one path allowed to change --direction, --candidates or --retain against the record. A temporarily unavailable stage retries once after 30 seconds.", "--target brings your own design image or LayerDoc, skips draft and pick, converts an image when needed, and aligns the plan to the captured URL DOM."];
148
148
  }, {
149
149
  readonly heading: "Planning";
150
150
  readonly items: readonly ["URL plans require at least 60% plausible DOM-side coverage; a blocked gate writes GATE.md while target HTML and LayerDoc remain authoritative sidecars.", "Image plans are target-only by default. --plan-source-convert buys one source LayerDoc conversion for an unanchored LayerDoc comparison.", "--repo adds evidence-ranked src/ TSX, JSX, and CSS file hints to a URL plan. The command never applies code.", "--dry-run prints exact catalog price ceilings for every stage and makes no network request."];
@@ -1 +1 @@
1
- {"version":3,"file":"cli-improve-command.d.ts","sourceRoot":"","sources":["../src/cli-improve-command.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAMnD,OAAO,EAQL,KAAK,0BAA0B,EAChC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAIL,KAAK,aAAa,EAEnB,MAAM,wBAAwB,CAAC;AAgEhC,eAAO,MAAM,iBAAiB,GAC5B,SAAS,SAAS,MAAM,EAAE,EAC1B,OAAO,QAAQ,EACf,eAAc,0BAA+B,KAC5C,OAAO,CAAC,aAAa,CAqJvB,CAAC"}
1
+ {"version":3,"file":"cli-improve-command.d.ts","sourceRoot":"","sources":["../src/cli-improve-command.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AA4BnD,OAAO,EAQL,KAAK,0BAA0B,EAChC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAIL,KAAK,aAAa,EAEnB,MAAM,wBAAwB,CAAC;AAyGhC,eAAO,MAAM,iBAAiB,GAC5B,SAAS,SAAS,MAAM,EAAE,EAC1B,OAAO,QAAQ,EACf,eAAc,0BAA+B,KAC5C,OAAO,CAAC,aAAa,CA2VvB,CAAC"}
@@ -1,10 +1,21 @@
1
1
  import { createHash, randomUUID } from 'node:crypto';
2
2
  import { readFile } from 'node:fs/promises';
3
+ import path from 'node:path';
3
4
  import { CliRefusal } from './cli-refusal.js';
4
5
  import { prepareOutputDirectory } from './cli-output-paths.js';
5
6
  import { parseImproveOptions } from './improve-options.js';
6
7
  import { buildImprovePricingPlan } from './improve-pricing-plan.js';
7
- import { retryImproveTemporarilyUnavailable } from './improve-convert-resilience.js';
8
+ import { assertImproveCaptureNotRedirected } from './improve-capture-redirect.js';
9
+ import { improveBootstrapDigest, improveBootstrapRecordFields, redactImproveBootstrap, } from './improve-bootstrap-secret.js';
10
+ import { improveStalled, retryImproveTemporarilyUnavailable } from './improve-convert-resilience.js';
11
+ import { ensureImproveKitIgnored } from './improve-kit-ignore.js';
12
+ import { resolveImproveStall, writeImproveFallbackStall, writeImproveStallReport, } from './improve-kit-stall.js';
13
+ import { readImproveKitStatus } from './improve-kit-status.js';
14
+ import { resetImproveDraw } from './improve-reset.js';
15
+ import { awaitingImprovePick, buildImproveRunSummary, improveStallErrorWithSummary, } from './improve-run-summary.js';
16
+ import { markImproveStageStalled } from './improve-stage-shared.js';
17
+ import { registerImproveStopHandler } from './improve-stop-handler.js';
18
+ import { noteImproveTerminalEvent } from './improve-terminal-event.js';
8
19
  import { runImproveCaptureStage, runImproveConvertStage, runImproveDraftStage, markImproveStageSkipped, runImprovePickStage, runImprovePlanStage, writeImproveReadme, } from './improve-stage-runners.js';
9
20
  import { IMPROVE_STAGES, readImproveRecord, writeImproveRecord, } from './improve-workspace.js';
10
21
  /**
@@ -13,11 +24,34 @@ import { IMPROVE_STAGES, readImproveRecord, writeImproveRecord, } from './improv
13
24
  * modules. No server route or billing path is introduced here.
14
25
  */
15
26
  const same = (left, right) => JSON.stringify(left) === JSON.stringify(right);
27
+ /**
28
+ * A mismatch refusal that names neither value is a dead end: the reader knows
29
+ * the flag disagrees with the record and has to open `improve.json` to find out
30
+ * what it holds. `--bootstrap` is the case that cost a run — its recorded value
31
+ * is a quoted triple nobody remembers typing.
32
+ */
33
+ const describeRecordedValue = (value) => {
34
+ if (value === undefined || value === null)
35
+ return 'nothing';
36
+ if (Array.isArray(value)) {
37
+ return value.length === 0 ? 'nothing' : value.map((entry) => `'${String(entry)}'`).join(', ');
38
+ }
39
+ if (typeof value === 'object')
40
+ return JSON.stringify(value);
41
+ return `'${String(value)}'`;
42
+ };
16
43
  const assertCompatibleRecord = async (args) => {
17
44
  if (!same(args.record.input.kind, args.parsed.input.kind)
18
45
  || !same(args.record.input.value, args.parsed.input.value)) {
19
46
  throw new CliRefusal('This improve directory belongs to a different input', 'improve_record_mismatch');
20
47
  }
48
+ // `--redraw` throws the draw away and buys another one, so the three flags
49
+ // that describe a draw are the ones it is entitled to change. Refusing them
50
+ // made the documented redraw command — the one that passes a new
51
+ // `--direction` — impossible to run, and sent the reader to a fresh
52
+ // `--out-dir`, which re-buys the capture too. Everything else still has to
53
+ // match: a redraw does not license a different model or a different page.
54
+ const drawFlags = new Set(args.parsed.redraw ? ['direction', 'candidates', 'retain'] : []);
21
55
  const explicitChecks = [
22
56
  ['direction', args.record.direction, args.parsed.direction],
23
57
  ['candidates', args.record.candidates, args.parsed.candidates],
@@ -26,14 +60,31 @@ const assertCompatibleRecord = async (args) => {
26
60
  ['responsive-quality', args.record.responsiveQuality, args.parsed.responsiveQuality],
27
61
  ['viewport', args.record.viewport, args.parsed.viewport],
28
62
  ['full-page', args.record.fullPage, args.parsed.fullPage],
29
- ['bootstrap', args.record.bootstrap, args.parsed.bootstrapValues],
30
63
  ['repo', args.record.repo, args.parsed.repo],
31
64
  ['plan-source-convert', args.record.planSourceConvert, args.parsed.planSourceConvert],
32
65
  ['target', args.record.target && { kind: args.record.target.kind, value: args.record.target.value }, args.parsed.target],
33
66
  ];
67
+ // `--bootstrap` compares by digest, because the record deliberately holds no
68
+ // live value to compare against (F31), and neither side of the refusal may
69
+ // print the secret.
70
+ if (args.flags.bootstrap !== undefined
71
+ && !same(args.record.bootstrapSha256 ?? [], args.parsed.bootstrapValues.map(improveBootstrapDigest))) {
72
+ throw new CliRefusal('--bootstrap does not match the durable improve record.'
73
+ + ` The record holds ${describeRecordedValue(args.record.bootstrap)}`
74
+ + ' (query values redacted; the live value is never stored);'
75
+ + ` this run asked for ${describeRecordedValue(args.parsed.bootstrapValues.map(redactImproveBootstrap))}.`
76
+ + ' Drop --bootstrap to reuse what the record already captured,'
77
+ + ' or pass a fresh --out-dir to start over with the changed input.', 'improve_record_mismatch');
78
+ }
34
79
  for (const [flag, recorded, requested] of explicitChecks) {
80
+ if (drawFlags.has(flag))
81
+ continue;
35
82
  if (args.flags[flag] !== undefined && !same(recorded, requested)) {
36
- throw new CliRefusal(`--${flag} does not match the durable improve record. Start a new --out-dir for changed inputs.`, 'improve_record_mismatch');
83
+ throw new CliRefusal(`--${flag} does not match the durable improve record.`
84
+ + ` The record holds ${describeRecordedValue(recorded)};`
85
+ + ` this run asked for ${describeRecordedValue(requested)}.`
86
+ + ` Drop --${flag} to reuse what the record already captured,`
87
+ + ' or pass a fresh --out-dir to start over with the changed input.', 'improve_record_mismatch');
37
88
  }
38
89
  }
39
90
  if (args.record.input.kind === 'image' && args.record.input.sha256) {
@@ -95,7 +146,7 @@ export const runImproveCommand = async (command, flags, dependencies = {}) => {
95
146
  responsiveQuality: parsed.responsiveQuality,
96
147
  viewport: parsed.viewport,
97
148
  fullPage: parsed.fullPage,
98
- bootstrap: parsed.bootstrapValues,
149
+ ...improveBootstrapRecordFields(parsed.bootstrapValues),
99
150
  ...(parsed.repo ? { repo: parsed.repo } : {}),
100
151
  planSourceConvert: parsed.planSourceConvert,
101
152
  stages: {},
@@ -122,92 +173,288 @@ export const runImproveCommand = async (command, flags, dependencies = {}) => {
122
173
  responsiveQuality: parsed.responsiveQuality,
123
174
  viewport: parsed.viewport,
124
175
  fullPage: parsed.fullPage,
125
- bootstrap: parsed.bootstrapValues,
176
+ ...improveBootstrapRecordFields(parsed.bootstrapValues),
126
177
  ...(parsed.repo ? { repo: parsed.repo } : {}),
127
178
  planSourceConvert: parsed.planSourceConvert,
128
179
  stages: {},
129
180
  };
181
+ // A kit written inside the repository it improves is ~100 MB of paid
182
+ // artifacts one `git add -A` away from someone's history (F17). Decided every
183
+ // run, because the repository's own `.gitignore` can change between them.
184
+ const kitIgnore = await ensureImproveKitIgnored({ outDir: parsed.paths.runDir });
185
+ record = { ...record, ...(kitIgnore ? { kitIgnore } : {}) };
130
186
  await writeImproveRecord(parsed.paths.record, record);
131
187
  const write = dependencies.write ?? ((line) => { process.stdout.write(`${line}\n`); });
132
188
  write(parsed.paths.runDir);
133
189
  dependencies.onRunDirectory?.(parsed.paths.runDir);
134
190
  dependencies.journal?.note({ workspace: parsed.paths.runDir, writes: [parsed.paths.record] });
191
+ // The kit describes itself after every stage, not only at the end. It derives
192
+ // from the record plus what is on disk, so writing it repeatedly is cheap and
193
+ // idempotent — and a run that dies between stages still leaves a front door.
194
+ const refreshReadme = async () => writeImproveReadme(record, { requestedTo: parsed.to });
135
195
  const index = (stage) => IMPROVE_STAGES.indexOf(stage);
136
196
  const within = (stage) => index(stage) >= index(parsed.from) && index(stage) <= index(parsed.to);
137
197
  const needed = (stage) => index(stage) <= index(parsed.to);
138
- const runStage = (stage, action) => (retryImproveTemporarilyUnavailable({
139
- stage,
140
- action,
141
- ...(dependencies.sleep ? { sleep: dependencies.sleep } : {}),
142
- ...(dependencies.warn ? { warn: dependencies.warn } : {}),
143
- }));
198
+ // The stage this invocation is INSIDE, which is what tells a stop mid-flight
199
+ // apart from a signal after completion. The record cannot: `--fresh` clears
200
+ // convert and plan from the durable record inside the convert stage, and
201
+ // `record` here is only reassigned when that stage returns.
202
+ let liveStage;
203
+ const runStage = async (stage, action) => {
204
+ liveStage = stage;
205
+ try {
206
+ return await retryImproveTemporarilyUnavailable({
207
+ stage,
208
+ action,
209
+ ...(dependencies.sleep ? { sleep: dependencies.sleep } : {}),
210
+ ...(dependencies.warn ? { warn: dependencies.warn } : {}),
211
+ });
212
+ }
213
+ finally {
214
+ liveStage = undefined;
215
+ }
216
+ };
144
217
  const freshConversionNonce = parsed.fresh ? randomUUID() : undefined;
145
- if (needed('capture')) {
146
- if (within('capture'))
147
- record = await runStage('capture', () => runImproveCaptureStage({
148
- record, options: parsed, dependencies, price: price.get('capture') ?? 0,
149
- }));
150
- if (!record.capture)
151
- missingStage('capture', parsed.paths.runDir);
152
- }
153
- if (needed('draft')) {
154
- if (record.target) {
155
- record = await markImproveStageSkipped(record, 'draft');
218
+ // A stalled or killed stage still owes the reader a kit that says what is
219
+ // missing and how to recover, and owes every other shell a terminal journal
220
+ // line. Without them a lane reads an empty `target/` and hand-authors the
221
+ // design in CSS — which is what happened on the pipedrive landing, and that
222
+ // lane was KILLED, not stalled, so it threw nothing the catch below could
223
+ // have seen. The handler is armed here, before the first stage, because a
224
+ // kill during capture, draft or pick used to leave nothing at all.
225
+ // A signal wrote this kit's `plan/STALL.md` during this very invocation, so
226
+ // nothing later in it may resolve that file away: in production the handler
227
+ // exits the process, and a harness that lets the stage unwind must not answer
228
+ // the signal by declaring the run fine (F21).
229
+ let stopped = false;
230
+ const disarmStop = registerImproveStopHandler({
231
+ getRecord: () => record,
232
+ onStopped: () => { stopped = true; },
233
+ getLiveStage: () => liveStage,
234
+ write,
235
+ requestedTo: parsed.to,
236
+ ...(dependencies.journal ? { journal: dependencies.journal } : {}),
237
+ ...(dependencies.stopTarget ? { target: dependencies.stopTarget } : {}),
238
+ ...(dependencies.exit ? { exit: dependencies.exit } : {}),
239
+ });
240
+ try {
241
+ // `--redraw` is the flag `--fresh` was being mistaken for. `--fresh` rotates
242
+ // the conversion key and re-buys ONE conversion of the SAME settled winner;
243
+ // it never touches the draw. A caller who wanted different candidates had no
244
+ // flag at all. This one empties draft, pick, convert and plan, renames the
245
+ // old draw aside rather than deleting it, and lets the normal stage order buy
246
+ // a new one — announced, because it is the most expensive thing improve does.
247
+ if (parsed.redraw) {
248
+ const hadDraw = Boolean(record.draft || record.pick);
249
+ // Only the flags this run actually passed reach the record. A redraw that
250
+ // reset `--candidates` to the default because the flag was absent would
251
+ // buy a draw nobody asked for.
252
+ const reset = await resetImproveDraw({
253
+ record,
254
+ draw: {
255
+ ...(flags.direction !== undefined
256
+ ? { direction: parsed.direction, concept: parsed.concept }
257
+ : {}),
258
+ ...(flags.candidates !== undefined ? { candidates: parsed.candidates } : {}),
259
+ ...(flags.retain !== undefined
260
+ ? { retain: parsed.retain, retainFlag: parsed.retainFlag }
261
+ : {}),
262
+ },
263
+ ...(dependencies.warn ? { warn: dependencies.warn } : {}),
264
+ });
265
+ record = reset.record;
266
+ await writeImproveRecord(parsed.paths.record, record);
267
+ if (hadDraw) {
268
+ write(`--redraw: the previous draw moved to ${parsed.paths.candidatesDir}.previous;`
269
+ + ` buying ${record.candidates} new candidates.`);
270
+ dependencies.journal?.note({ degradations: ['improve_draw_discarded'] });
271
+ }
272
+ // A settled conversion the redraw threw away is paid work, and there is
273
+ // no cancel. It belongs in the same ledger `--fresh` and a re-pick write.
274
+ if (reset.abandonedId) {
275
+ dependencies.journal?.note({ degradations: ['improve_redraw_abandoned_conversion'] });
276
+ }
156
277
  }
157
- else {
158
- if (within('draft'))
159
- record = await runStage('draft', () => runImproveDraftStage({
160
- record, options: parsed, flags, dependencies, price: price.get('draft') ?? 0,
278
+ if (needed('capture')) {
279
+ if (within('capture'))
280
+ record = await runStage('capture', () => runImproveCaptureStage({
281
+ record, options: parsed, dependencies, price: price.get('capture') ?? 0,
161
282
  }));
162
- if (!record.draft)
163
- missingStage('draft', parsed.paths.runDir);
283
+ if (!record.capture)
284
+ missingStage('capture', parsed.paths.runDir);
285
+ await refreshReadme();
286
+ // Free, deterministic, and BEFORE the draft purchase: the captured page
287
+ // and the requested one have to be the same page, or nothing is bought
288
+ // (F27). The capture and the README above are already on disk, so the
289
+ // refusal costs a reader nothing and the next run replays them.
290
+ assertImproveCaptureNotRedirected({
291
+ record, allowRedirect: parsed.allowRedirect, runDir: parsed.paths.runDir,
292
+ });
164
293
  }
165
- }
166
- if (needed('pick')) {
167
- if (record.target) {
168
- record = await markImproveStageSkipped(record, 'pick');
294
+ if (needed('draft')) {
295
+ if (record.target) {
296
+ record = await markImproveStageSkipped(record, 'draft');
297
+ }
298
+ else {
299
+ if (within('draft'))
300
+ record = await runStage('draft', () => runImproveDraftStage({
301
+ record, options: parsed, flags, dependencies, price: price.get('draft') ?? 0,
302
+ }));
303
+ if (!record.draft)
304
+ missingStage('draft', parsed.paths.runDir);
305
+ }
306
+ await refreshReadme();
169
307
  }
170
- else {
171
- if (within('pick'))
172
- record = await runStage('pick', () => runImprovePickStage({
173
- record, options: parsed, price: price.get('pick') ?? 0,
174
- }));
175
- if (!record.pick)
176
- missingStage('pick', parsed.paths.runDir);
308
+ if (needed('pick')) {
309
+ if (record.target) {
310
+ record = await markImproveStageSkipped(record, 'pick');
311
+ }
312
+ else {
313
+ // DISPATCH DISCIPLINE. A draw is alternatives; converting one of them
314
+ // before anyone has looked spends money on a guess. `--pick` used to
315
+ // default to A and the convert stage ran straight on, so notion bought
316
+ // a conversion of candidate A four milliseconds after the draft
317
+ // settled — and then a second process converted D, the one actually
318
+ // chosen. With no `--pick` and no recorded pick, the run stops here.
319
+ const chosen = parsed.pick ?? record.pick?.slot;
320
+ if (within('pick')) {
321
+ // Nothing to settle and nobody to ask: stop, and print the one
322
+ // command that continues. A range that starts AFTER pick asked to
323
+ // skip this stage, so it falls through to the honest refusal below
324
+ // rather than quietly stopping where it was told not to.
325
+ if (!chosen) {
326
+ await refreshReadme();
327
+ write(awaitingImprovePick({ record, options: parsed }));
328
+ dependencies.journal?.note({
329
+ workspace: parsed.paths.runDir,
330
+ artifacts: [parsed.paths.record, parsed.paths.readme],
331
+ purchased: record.draft ? [record.draft.runId] : [],
332
+ terminal: false,
333
+ });
334
+ console.log(JSON.stringify({ from: parsed.from, to: parsed.to, ...record }, null, 2));
335
+ return record;
336
+ }
337
+ record = await runStage('pick', () => runImprovePickStage({
338
+ record, options: parsed, pick: chosen, dependencies, price: price.get('pick') ?? 0,
339
+ }));
340
+ }
341
+ if (!record.pick)
342
+ missingStage('pick', parsed.paths.runDir);
343
+ }
344
+ await refreshReadme();
177
345
  }
178
- }
179
- if (needed('convert')) {
180
- if (within('convert'))
181
- record = await runStage('convert', () => runImproveConvertStage({
346
+ try {
347
+ if (needed('convert')) {
348
+ if (within('convert'))
349
+ record = await runStage('convert', () => runImproveConvertStage({
350
+ record,
351
+ options: parsed,
352
+ dependencies,
353
+ price: price.get('convert') ?? 0,
354
+ ...(freshConversionNonce ? { freshConversionNonce } : {}),
355
+ }));
356
+ if (!record.convert)
357
+ missingStage('convert', parsed.paths.runDir);
358
+ await refreshReadme();
359
+ }
360
+ if (needed('plan')) {
361
+ if (within('plan'))
362
+ record = await runStage('plan', () => runImprovePlanStage({
363
+ record, options: parsed, dependencies, price: price.get('plan') ?? 0,
364
+ }));
365
+ if (!record.plan)
366
+ missingStage('plan', parsed.paths.runDir);
367
+ }
368
+ }
369
+ catch (error) {
370
+ // The durable record is the truth here: a stage that failed still wrote
371
+ // down what it abandoned before it threw, and the in-memory copy this
372
+ // function holds predates that.
373
+ record = await readImproveRecord(parsed.paths.record) ?? record;
374
+ const stalledStage = record.convert ? 'plan' : 'convert';
375
+ // A stall closes the record itself, before the recovery files, so a
376
+ // reader never sees a run whose last line is a progress entry. A stage
377
+ // that failed for a reason the journal can already classify — an auth
378
+ // failure, a refusal — keeps that classification: `withRunJournal` ends
379
+ // it on the way out and the throw below is what gets there.
380
+ const stalled = improveStalled(error);
381
+ // The durable record has to say the paid call never came back. `outcome`
382
+ // is the one field a supervisor or a parser reads, and it stayed
383
+ // `dispatched` — which reads as "in flight" long after the run ended (F28).
384
+ const marked = markImproveStageStalled({ record, stage: stalledStage, stalled });
385
+ if (marked !== record) {
386
+ record = marked;
387
+ await writeImproveRecord(parsed.paths.record, record);
388
+ }
389
+ if (stalled) {
390
+ // Everything the record is owed goes in HERE. The session refuses to
391
+ // write after its end line, so the note that used to follow this call
392
+ // was dropped in silence and `improve_<stage>_stalled` never reached a
393
+ // single stalled record.
394
+ await noteImproveTerminalEvent({
395
+ record,
396
+ stage: stalledStage,
397
+ kind: 'stalled',
398
+ error,
399
+ writes: [path.join(parsed.paths.planDir, 'STALL.md'), parsed.paths.readme],
400
+ degradations: [`improve_${stalledStage}_stalled`],
401
+ ...(dependencies.journal ? { journal: dependencies.journal } : {}),
402
+ });
403
+ }
404
+ const stall = await writeImproveStallReport({
405
+ record, stage: stalledStage, error, requestedTo: parsed.to,
406
+ });
407
+ const readme = await refreshReadme();
408
+ // A failure the journal can already classify — an auth failure, a refusal
409
+ // — has an open session still, and `withRunJournal` ends it on the way
410
+ // out; this is the last chance to name what it produced.
411
+ if (!stalled) {
412
+ dependencies.journal?.note({
413
+ workspace: parsed.paths.runDir,
414
+ artifacts: [parsed.paths.record, readme, stall],
415
+ degradations: [`improve_${stalledStage}_stalled`],
416
+ });
417
+ }
418
+ throw improveStallErrorWithSummary(error, await buildImproveRunSummary({ record, requestedTo: parsed.to }));
419
+ }
420
+ // A run that fell back to fixed layout finished, but something stalled on
421
+ // the way. It gets the same `plan/STALL.md` a dead run gets — written after
422
+ // the plan, so it can say the plan was built from the derivation — and the
423
+ // README, written next, links to it (F8).
424
+ const fallbackStall = await writeImproveFallbackStall({ record, requestedTo: parsed.to });
425
+ // And a run that SETTLED what an earlier one stalled on replaces the file
426
+ // that earlier one left. Freshdesk shipped a settled plan under a README
427
+ // saying "settled" beside a STALL.md saying "INCOMPLETE — no plan"; the
428
+ // reader had no way to tell which was current (F21).
429
+ const resolvedStall = fallbackStall || stopped
430
+ ? undefined
431
+ : await resolveImproveStall({
182
432
  record,
183
- options: parsed,
184
- dependencies,
185
- price: price.get('convert') ?? 0,
186
- ...(freshConversionNonce ? { freshConversionNonce } : {}),
187
- }));
188
- if (!record.convert)
189
- missingStage('convert', parsed.paths.runDir);
433
+ status: await readImproveKitStatus({ record, requestedTo: parsed.to }),
434
+ });
435
+ const stallFile = fallbackStall ?? resolvedStall;
436
+ const readme = await refreshReadme();
437
+ dependencies.journal?.note({
438
+ workspace: parsed.paths.runDir,
439
+ artifacts: [
440
+ parsed.paths.record,
441
+ readme,
442
+ ...(stallFile ? [stallFile] : []),
443
+ ...(record.plan?.artifacts ?? []),
444
+ ],
445
+ purchased: [
446
+ ...(record.draft ? [record.draft.runId] : []),
447
+ ...(record.convert?.purchaseIds ?? []),
448
+ ...(record.sourceConvert?.purchaseIds ?? []),
449
+ ],
450
+ terminal: parsed.to === 'plan',
451
+ });
452
+ console.log(JSON.stringify({ from: parsed.from, to: parsed.to, ...record }, null, 2));
453
+ write(await buildImproveRunSummary({ record, requestedTo: parsed.to }));
454
+ return record;
190
455
  }
191
- if (needed('plan')) {
192
- if (within('plan'))
193
- record = await runStage('plan', () => runImprovePlanStage({
194
- record, options: parsed, dependencies, price: price.get('plan') ?? 0,
195
- }));
196
- if (!record.plan)
197
- missingStage('plan', parsed.paths.runDir);
456
+ finally {
457
+ disarmStop();
198
458
  }
199
- const readme = await writeImproveReadme(record);
200
- dependencies.journal?.note({
201
- workspace: parsed.paths.runDir,
202
- artifacts: [parsed.paths.record, readme, ...(record.plan?.artifacts ?? [])],
203
- purchased: [
204
- ...(record.draft ? [record.draft.runId] : []),
205
- ...(record.convert?.purchaseIds ?? []),
206
- ...(record.sourceConvert?.purchaseIds ?? []),
207
- ],
208
- terminal: parsed.to === 'plan',
209
- });
210
- console.log(JSON.stringify({ from: parsed.from, to: parsed.to, ...record }, null, 2));
211
- return record;
212
459
  };
213
460
  //# sourceMappingURL=cli-improve-command.js.map