@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
@@ -0,0 +1,311 @@
1
+ import { mkdir, readFile, stat, writeFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { formatDuration } from './cli-progress.js';
4
+ import { readImproveKitAssets } from './improve-kit-assets.js';
5
+ import { IMPROVE_NO_APPROXIMATION_RULE, IMPROVE_STALL_RESOLVED_HEADING, improveRecoveryLine, readImproveKitStatus, shellArg, } from './improve-kit-status.js';
6
+ import { improveConversionIdFromText, improveErrorText, improveResumeConversion, } from './improve-convert-resilience.js';
7
+ import { renderImproveRasterLayers } from './improve-raster-layers-section.js';
8
+ import { improveAbandonedLines } from './improve-reset.js';
9
+ import { readRunJournal } from './run-journal.js';
10
+ import { improvePaths } from './improve-workspace.js';
11
+ /**
12
+ * A stalled run still writes a plan directory.
13
+ *
14
+ * Pipedrive's conversion sat in `materializing_assets` for sixteen minutes and
15
+ * never journalled a terminal event, so the kit had an empty `target/`, no
16
+ * `plan/`, and nothing at all telling the lane what to do. It hand-authored the
17
+ * hero in CSS. This file is what should have been there instead: which stage,
18
+ * how long it waited, the hosted run id, what exists, and the three commands
19
+ * that recover — plus the raster layers, whenever a LayerDoc survived.
20
+ */
21
+ const UUID = /[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}/iu;
22
+ /**
23
+ * What the run was waiting on, from the journal it kept writing plus the error
24
+ * that ended the local process. The journal is authoritative for elapsed time
25
+ * because the error text carries none.
26
+ */
27
+ export const collectImproveStallFacts = async (args) => {
28
+ const text = improveErrorText(args.error);
29
+ const entries = args.entries
30
+ ?? (await readRunJournal({ workspace: args.record.runDir }).catch(() => ({ entries: [] }))).entries;
31
+ const progress = [...entries].reverse().find((entry) => (entry.event === 'progress' && entry.paid && entry.elapsed_seconds !== undefined));
32
+ const journalled = [...entries].reverse().find((entry) => (entry.paid && typeof entry.run_id === 'string' && UUID.test(entry.run_id)))?.run_id;
33
+ const recorded = args.record.convert?.sourceConversionId;
34
+ const hostedRunId = args.inFlight
35
+ ? journalled ?? improveConversionIdFromText(text) ?? recorded
36
+ : recorded ?? improveConversionIdFromText(text) ?? journalled;
37
+ const resume = improveResumeConversion(args.record);
38
+ // An attempt whose id never reached the record, named from the journal
39
+ // instead. It is the same conversion: the open attempt is what THIS
40
+ // invocation dispatched, and `inFlight` is what makes the journal's newest
41
+ // paid line this invocation's own heartbeat rather than an earlier run's.
42
+ const named = resume && !resume.id && args.inFlight && hostedRunId
43
+ ? { ...resume, id: hostedRunId }
44
+ : resume;
45
+ return {
46
+ stage: args.stage,
47
+ kind: args.kind ?? 'stalled',
48
+ ...(hostedRunId ? { hostedRunId } : {}),
49
+ ...(named ? { resume: named } : {}),
50
+ ...(progress?.elapsed_seconds === undefined ? {} : { waitedSeconds: progress.elapsed_seconds }),
51
+ ...(progress?.typical_seconds === undefined ? {} : { typicalSeconds: progress.typical_seconds }),
52
+ ...(progress?.stage ? { serviceStage: progress.stage } : {}),
53
+ reason: text.split('\n')[0]?.trim() || 'The stage ended without settling.',
54
+ };
55
+ };
56
+ const targetContents = (status) => {
57
+ if (!status.present.layerDoc)
58
+ return 'nothing';
59
+ if (!status.present.assets)
60
+ return 'the LayerDoc only';
61
+ return status.present.targetHtml
62
+ ? 'the LayerDoc, its assets, and target HTML'
63
+ : 'the LayerDoc and its assets';
64
+ };
65
+ /**
66
+ * Which conversion the recovery command below actually reaches, and — when this
67
+ * run was watching a different one — that the one it was watching is gone.
68
+ *
69
+ * A `--fresh` or retry conversion is recorded by its exact key before it is
70
+ * dispatched (`improve-conversion-attempts.ts`), so a run stopped inside one
71
+ * resumes onto the conversion it was actually watching. The "cannot be
72
+ * resumed" line survives for kits written before that ledger: they hold two
73
+ * conversions, the base-key one `--fresh` rotated away from, which the resume
74
+ * lands back on, and the fresh one dispatched under a one-off nonce nothing
75
+ * recorded. Naming only the second reads as "resume and you get this back",
76
+ * which is false and costs a conversion when the reader buys another instead.
77
+ */
78
+ const resumeLines = (facts) => {
79
+ if (!facts.resume)
80
+ return [];
81
+ const reaches = facts.resume.reason === 'settled'
82
+ ? 'the first command below replays it and buys nothing'
83
+ : 'the first command below rebuilds this kit\'s conversion key and re-attaches to it,'
84
+ + ' rather than buying another';
85
+ const lines = [
86
+ facts.resume.id
87
+ ? `- Resume attaches to: \`${facts.resume.id}\` — ${reaches}`
88
+ : '- Resume attaches to: the conversion this kit dispatched under its recorded key —'
89
+ + ' it never reported an id, but the key is on the record, so'
90
+ + ` ${reaches}`,
91
+ ];
92
+ if (facts.resume.reason === 'fresh-rotated-away'
93
+ && facts.hostedRunId
94
+ && facts.hostedRunId !== facts.resume.id) {
95
+ lines.push(`- Cannot be resumed: \`${facts.hostedRunId}\` — this run dispatched it under a one-off`
96
+ + ' `--fresh` key that nothing durable records, so no later command can re-attach to it.'
97
+ + ' It keeps running and keeps billing.');
98
+ }
99
+ return lines;
100
+ };
101
+ /**
102
+ * What a recovered run owes its reader: what stalled, what shipped instead, and
103
+ * how to collect the stalled half later without buying anything.
104
+ *
105
+ * `12ui resume` collects an existing purchase — it never retries, reconfigures
106
+ * or creates — so it is the only honest way to offer the responsive export a
107
+ * lane already paid for. The kit itself needs no re-run: the plan is built.
108
+ */
109
+ const fallbackLines = (facts, runDir) => [
110
+ '',
111
+ '## What shipped instead',
112
+ '',
113
+ '- The fixed-layout HTML derived free from the same conversion, and the plan was built from'
114
+ + ' that derivation. It is not a responsive deliverable.',
115
+ '- The LayerDoc and its assets are unaffected: they are the full-quality source of truth and'
116
+ + ' the plan anchors to them.',
117
+ '- Nothing here needs re-running, and nothing was bought twice.',
118
+ '',
119
+ '## Recovery',
120
+ '',
121
+ 'If the responsive export completes later, collect it. `resume` recovers an existing purchase;'
122
+ + ' it never retries, reconfigures, or creates a conversion, so it buys nothing:',
123
+ '',
124
+ ...(facts.hostedRunId
125
+ ? [` 12ui resume ${facts.hostedRunId} --out-dir ${shellArg(path.join(runDir, 'target'))}`]
126
+ : [' 12ui resume <conversion-id> --out-dir <kit>/target']),
127
+ '',
128
+ ];
129
+ export const renderImproveStall = (args) => {
130
+ const waited = args.facts.waitedSeconds === undefined
131
+ ? 'unrecorded'
132
+ : `${formatDuration(args.facts.waitedSeconds)}`
133
+ + `${args.facts.boundSeconds === undefined
134
+ ? ''
135
+ : ` (bound ${formatDuration(args.facts.boundSeconds)})`}`
136
+ + `${args.facts.typicalSeconds === undefined
137
+ ? ''
138
+ : ` against a typical ${formatDuration(args.facts.typicalSeconds)}`}`;
139
+ const fallback = args.facts.kind === 'fallback';
140
+ const lines = [
141
+ // A recovered run is not INCOMPLETE — the kit is whole and the plan is
142
+ // built — so it must not lead with the word that tells a lane to stop and
143
+ // resume. It still leads with what stalled, because that is the fact the
144
+ // summary, the README and this file all have to agree on (F8).
145
+ fallback
146
+ ? '# Responsive export stalled — plan from the fixed-layout fallback'
147
+ : `# INCOMPLETE — this run ${args.facts.kind === 'stopped' ? 'was stopped' : 'stalled'}`,
148
+ '',
149
+ `- Stage: ${args.facts.stage}${fallback ? ' (responsive export)' : ''}`
150
+ + `${args.facts.serviceStage ? ` (service stage \`${args.facts.serviceStage}\`)` : ''}`,
151
+ `- Waited: ${waited}`,
152
+ `- Hosted run: ${args.facts.hostedRunId ? `\`${args.facts.hostedRunId}\`` : 'not recorded'}`,
153
+ ...(fallback ? [] : resumeLines(args.facts)),
154
+ `- In \`target/\`: ${targetContents(args.status)}`,
155
+ `- Reason: ${args.facts.reason}`,
156
+ ...improveAbandonedLines(args.record),
157
+ ...(fallback ? fallbackLines(args.facts, args.record.runDir) : [
158
+ '',
159
+ '## Recovery',
160
+ '',
161
+ 'Run the first command; it resumes and replays every settled stage rather than buying them again.',
162
+ '',
163
+ ...args.status.recovery.map(improveRecoveryLine),
164
+ // The conversion this run was waiting on is still running and still
165
+ // billing, and improve bought nothing to replace it (F19). `resume`
166
+ // collects it — it never retries, reconfigures or creates — so it is the
167
+ // second thing to reach for, ahead of any command that converts again.
168
+ ...(args.facts.hostedRunId ? [
169
+ '',
170
+ 'The conversion above is still running. Collect it directly once it finishes;'
171
+ + ' `resume` recovers an existing purchase and buys nothing:',
172
+ '',
173
+ ` 12ui resume ${args.facts.hostedRunId}`
174
+ + ` --out-dir ${shellArg(path.join(args.record.runDir, 'target'))}`,
175
+ ] : []),
176
+ '',
177
+ // Only for a kit that is actually missing something. Telling a complete
178
+ // fallback kit to "resume or convert first" would send a lane to buy the
179
+ // conversion it already has.
180
+ IMPROVE_NO_APPROXIMATION_RULE,
181
+ '',
182
+ ]),
183
+ ];
184
+ if (args.status.present.layerDoc) {
185
+ lines.push(
186
+ // What the LayerDoc makes available, in the words the README uses for the
187
+ // same fact (F22). "Usable without a plan" read as permission to build
188
+ // the page without one, three lines under a rule that forbids exactly
189
+ // that; the boundary now lives in one place and both files print it.
190
+ 'A LayerDoc survived this run, so the design\'s raster layers are already extracted.'
191
+ + ' They are files: carry them.', '', ...renderImproveRasterLayers({ layers: args.index.rasterLayers }));
192
+ }
193
+ return lines.join('\n');
194
+ };
195
+ /**
196
+ * The same file, for the run that recovered.
197
+ *
198
+ * The facts come off the durable record rather than out of an error, because
199
+ * there is no error: the responsive export stalled, the free derivation took
200
+ * over, and the run went on to build a plan. A kit written before
201
+ * `responsiveStall` existed records the fallback but not its timings, so this
202
+ * writes what it has and never invents a number.
203
+ */
204
+ export const writeImproveFallbackStall = async (args) => {
205
+ const convert = args.record.convert;
206
+ if (convert?.layout !== 'fixed')
207
+ return undefined;
208
+ const paths = improvePaths(args.record.runDir);
209
+ const stall = convert.responsiveStall;
210
+ const facts = {
211
+ stage: 'convert',
212
+ kind: 'fallback',
213
+ ...(stall?.conversionId ?? convert.sourceConversionId
214
+ ? { hostedRunId: stall?.conversionId ?? convert.sourceConversionId }
215
+ : {}),
216
+ ...(stall ? { waitedSeconds: stall.waitedSeconds, boundSeconds: stall.boundSeconds } : {}),
217
+ reason: convert.responsiveWarning ?? 'Responsive HTML was unavailable.',
218
+ };
219
+ const [status, index] = await Promise.all([
220
+ readImproveKitStatus({
221
+ record: args.record,
222
+ ...(args.requestedTo ? { requestedTo: args.requestedTo } : {}),
223
+ }),
224
+ readImproveKitAssets({ runDir: args.record.runDir, layerDocPath: paths.targetLayerDoc }),
225
+ ]);
226
+ await mkdir(paths.planDir, { recursive: true });
227
+ const file = path.join(paths.planDir, 'STALL.md');
228
+ await writeFile(file, renderImproveStall({ record: args.record, facts, status, index }), 'utf8');
229
+ return file;
230
+ };
231
+ const stalledStageFrom = (content) => (/^- Stage: ([a-z]+)/mu.exec(content)?.[1]);
232
+ /**
233
+ * The stall this kit recorded is over, so the file that recorded it stops
234
+ * saying the kit is INCOMPLETE (F21).
235
+ *
236
+ * Freshdesk's `--from convert` resume settled at 18:56:41Z and wrote a whole
237
+ * plan; the `plan/STALL.md` from 18:48:17Z survived beside it, still saying
238
+ * "this run was stopped", "no plan", and "resume or convert first" — directly
239
+ * contradicting the README above it, which said the plan was settled. A reader
240
+ * opening that kit cold got two mutually exclusive statuses and no way to tell
241
+ * which was current.
242
+ *
243
+ * The file is REPLACED rather than deleted: it is the durable record that this
244
+ * kit stalled once, which is worth keeping, and a README that links to it must
245
+ * not link to nothing. Its mtime is when the stall was written, which is the
246
+ * one timestamp neither the record nor the journal keeps.
247
+ */
248
+ export const resolveImproveStall = async (args) => {
249
+ // Only once every stage this kit was asked for has settled. A `--to pick`
250
+ // run, or one that stalled again, leaves the file standing because it is
251
+ // still true.
252
+ if (!args.status.present.stall)
253
+ return undefined;
254
+ if (args.status.stages.some((stage) => stage.state === 'incomplete'))
255
+ return undefined;
256
+ // A fallback kit's STALL.md is rewritten by `writeImproveFallbackStall` every
257
+ // run and describes a stall that is not over: the responsive export never
258
+ // arrived, and the recovery it offers still collects it.
259
+ if (args.record.convert?.layout === 'fixed')
260
+ return undefined;
261
+ const file = path.join(improvePaths(args.record.runDir).planDir, 'STALL.md');
262
+ const [content, stalledAt] = await Promise.all([
263
+ readFile(file, 'utf8').catch(() => undefined),
264
+ stat(file).then((entry) => entry.mtime).catch(() => undefined),
265
+ ]);
266
+ if (content === undefined)
267
+ return undefined;
268
+ if (content.startsWith(IMPROVE_STALL_RESOLVED_HEADING))
269
+ return file;
270
+ const stage = stalledStageFrom(content);
271
+ await writeFile(file, [
272
+ IMPROVE_STALL_RESOLVED_HEADING,
273
+ '',
274
+ `- Stalled at: ${stalledAt ? stalledAt.toISOString() : 'unrecorded'}`
275
+ + `${stage ? ` (stage ${stage})` : ''}`,
276
+ `- Resumed and settled at: ${(args.now ?? new Date()).toISOString()}`,
277
+ '- Every stage this kit was asked for has settled since. The plan and the target'
278
+ + ' beside this file are current, and nothing here needs re-running.',
279
+ '',
280
+ 'This file is kept as the record that the run stalled once. `README.md` has the'
281
+ + ' kit\'s status, and `plan/plan-annotated.md` has the work.',
282
+ '',
283
+ ].join('\n'), 'utf8');
284
+ return file;
285
+ };
286
+ /**
287
+ * Write `plan/STALL.md`, creating `plan/` when the plan stage never ran.
288
+ * Returns the file so the caller can journal it as an artifact.
289
+ */
290
+ export const writeImproveStallReport = async (args) => {
291
+ const paths = improvePaths(args.record.runDir);
292
+ const [facts, status, index] = await Promise.all([
293
+ collectImproveStallFacts({
294
+ record: args.record,
295
+ stage: args.stage,
296
+ error: args.error,
297
+ ...(args.kind ? { kind: args.kind } : {}),
298
+ ...(args.inFlight === undefined ? {} : { inFlight: args.inFlight }),
299
+ }),
300
+ readImproveKitStatus({
301
+ record: args.record,
302
+ ...(args.requestedTo ? { requestedTo: args.requestedTo } : {}),
303
+ }),
304
+ readImproveKitAssets({ runDir: args.record.runDir, layerDocPath: paths.targetLayerDoc }),
305
+ ]);
306
+ await mkdir(paths.planDir, { recursive: true });
307
+ const file = path.join(paths.planDir, 'STALL.md');
308
+ await writeFile(file, renderImproveStall({ record: args.record, facts, status, index }), 'utf8');
309
+ return file;
310
+ };
311
+ //# sourceMappingURL=improve-kit-stall.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"improve-kit-stall.js","sourceRoot":"","sources":["../src/improve-kit-stall.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,105 @@
1
+ import { type ImproveRecord, type ImproveStage } from './improve-workspace.js';
2
+ /**
3
+ * One honest reading of "how far did this kit actually get".
4
+ *
5
+ * Read from the durable record AND the filesystem, because the record only
6
+ * ever describes stages that settled: a run killed inside `materializing_assets`
7
+ * leaves a record that says capture, draft and pick are fine and says nothing
8
+ * at all about the empty `target/` the reader is looking at.
9
+ */
10
+ export type ImproveStageState = 'settled' | 'replayed' | 'skipped' | 'fallback' | 'blocked' | 'incomplete' | 'not-requested';
11
+ export type ImproveStageStatus = {
12
+ stage: ImproveStage;
13
+ state: ImproveStageState;
14
+ detail?: string;
15
+ };
16
+ export type ImproveTargetMode = 'responsive HTML' | 'fixed-layout fallback' | 'LayerDoc only' | 'none';
17
+ /** One recovery command and what running it costs. */
18
+ export type ImproveRecoveryCommand = {
19
+ command: string;
20
+ spends: string;
21
+ };
22
+ export type ImproveKitStatus = {
23
+ stages: ImproveStageStatus[];
24
+ /** Every requested stage settled and the artifacts it promises are on disk. */
25
+ complete: boolean;
26
+ /**
27
+ * The coverage gate blocked the anchored plan, so `plan/GATE.md` replaced
28
+ * `plan-annotated.md` and `token-patch.css`. Nothing is missing and nothing
29
+ * stalled: it is a third outcome, and a reader sent to files the gate deleted
30
+ * is a reader who gives up on the kit.
31
+ */
32
+ gateBlocked: boolean;
33
+ /** What a reader will not find, in the words the recovery commands answer. */
34
+ missing: string[];
35
+ targetMode: ImproveTargetMode;
36
+ present: {
37
+ design: boolean;
38
+ layerDoc: boolean;
39
+ assets: boolean;
40
+ targetHtml: boolean;
41
+ plan: boolean;
42
+ gate: boolean;
43
+ stall: boolean;
44
+ /** The `STALL.md` present is the record of a stall that has since settled. */
45
+ stallResolved: boolean;
46
+ };
47
+ /** The file a reader should look at and a conversion can be re-run from. */
48
+ designImage: string;
49
+ /** A supplied `*.layerdoc.json` target kit has a document, not a picture. */
50
+ designKind: 'image' | 'layerdoc';
51
+ recovery: ImproveRecoveryCommand[];
52
+ };
53
+ /**
54
+ * The heading a `plan/STALL.md` leads with once the stall it recorded has
55
+ * settled. It lives here rather than beside the renderer because the kit
56
+ * status has to be able to tell a live stall from a resolved one without
57
+ * importing the renderer that writes it.
58
+ */
59
+ export declare const IMPROVE_STALL_RESOLVED_HEADING = "# Resolved \u2014 the stall recorded here has settled";
60
+ /**
61
+ * THE ONE BOUNDARY SENTENCE, and the reason it is one sentence in one module.
62
+ *
63
+ * The README and `plan/STALL.md` shipped together and disagreed (F22). The
64
+ * README said "do not approximate the design in CSS from the PNG while a stage
65
+ * is incomplete"; three lines further down STALL.md said "a LayerDoc survived
66
+ * this run, so the design's raster layers are usable without a plan". Both are
67
+ * true of different things — carry the rasters, do not redraw the layout — but
68
+ * nothing in the kit said so, and a lane had to adjudicate the contradiction
69
+ * itself, after both of its conversions were already spent. Every renderer
70
+ * prints this string; none writes its own version of it.
71
+ */
72
+ export declare const IMPROVE_NO_APPROXIMATION_RULE: string;
73
+ /**
74
+ * A recovery command is presented as copy-and-run, so it has to survive being
75
+ * pasted. Capture URLs carry query strings and `--out-dir` paths carry spaces;
76
+ * either one unquoted breaks the line or backgrounds it at the `&`.
77
+ */
78
+ export declare const shellArg: (value: string) => string;
79
+ /**
80
+ * The draw is ready and nobody has chosen.
81
+ *
82
+ * `--pick` has no default, so a run with candidates and no pick is a finished
83
+ * run holding a drafts-only kit — not a stall. It is the one incomplete state
84
+ * whose recovery is neither a resume nor a conversion.
85
+ */
86
+ export declare const improveAwaitingPick: (record: ImproveRecord) => boolean;
87
+ /**
88
+ * The `--pick` placeholder, in one place, so the run summary and the kit README
89
+ * cannot drift into naming different slots for the same draw.
90
+ */
91
+ export declare const improvePickSlotHint: (record: ImproveRecord) => string;
92
+ /** The one sentence a never-picked kit needs before its recovery command. */
93
+ export declare const IMPROVE_AWAITING_PICK_RULE: string;
94
+ export declare const improveRecoveryCommands: (args: {
95
+ record: ImproveRecord;
96
+ designImage: string;
97
+ }) => ImproveRecoveryCommand[];
98
+ /** One indented, copy-pasteable line; the cost rides along as a shell comment. */
99
+ export declare const improveRecoveryLine: (entry: ImproveRecoveryCommand) => string;
100
+ export declare const readImproveKitStatus: (args: {
101
+ record: ImproveRecord;
102
+ requestedTo?: ImproveStage;
103
+ }) => Promise<ImproveKitStatus>;
104
+ export declare const improveStageStatusLine: (status: ImproveStageStatus) => string;
105
+ //# sourceMappingURL=improve-kit-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"improve-kit-status.d.ts","sourceRoot":"","sources":["../src/improve-kit-status.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgC,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAE7G;;;;;;;GAOG;AAEH,MAAM,MAAM,iBAAiB,GACzB,SAAS,GACT,UAAU,GACV,SAAS,GACT,UAAU,GACV,SAAS,GACT,YAAY,GACZ,eAAe,CAAC;AAEpB,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,YAAY,CAAC;IACpB,KAAK,EAAE,iBAAiB,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GACzB,iBAAiB,GACjB,uBAAuB,GACvB,eAAe,GACf,MAAM,CAAC;AAEX,sDAAsD;AACtD,MAAM,MAAM,sBAAsB,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,+EAA+E;IAC/E,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,WAAW,EAAE,OAAO,CAAC;IACrB,8EAA8E;IAC9E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,iBAAiB,CAAC;IAC9B,OAAO,EAAE;QACP,MAAM,EAAE,OAAO,CAAC;QAChB,QAAQ,EAAE,OAAO,CAAC;QAClB,MAAM,EAAE,OAAO,CAAC;QAChB,UAAU,EAAE,OAAO,CAAC;QACpB,IAAI,EAAE,OAAO,CAAC;QACd,IAAI,EAAE,OAAO,CAAC;QACd,KAAK,EAAE,OAAO,CAAC;QACf,8EAA8E;QAC9E,aAAa,EAAE,OAAO,CAAC;KACxB,CAAC;IACF,4EAA4E;IAC5E,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,UAAU,EAAE,OAAO,GAAG,UAAU,CAAC;IACjC,QAAQ,EAAE,sBAAsB,EAAE,CAAC;CACpC,CAAC;AA8DF;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,0DAAqD,CAAC;AAEjG;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,6BAA6B,QAE2C,CAAC;AAEtF;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,OAAO,MAAM,KAAG,MAExC,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAAI,QAAQ,aAAa,KAAG,OAE3D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAAI,QAAQ,aAAa,KAAG,MAG3D,CAAC;AAEF,6EAA6E;AAC7E,eAAO,MAAM,0BAA0B,QAEoC,CAAC;AAE5E,eAAO,MAAM,uBAAuB,GAAI,MAAM;IAC5C,MAAM,EAAE,aAAa,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB,KAAG,sBAAsB,EA8BzB,CAAC;AAEF,kFAAkF;AAClF,eAAO,MAAM,mBAAmB,GAAI,OAAO,sBAAsB,KAAG,MAEnE,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAU,MAAM;IAC/C,MAAM,EAAE,aAAa,CAAC;IACtB,WAAW,CAAC,EAAE,YAAY,CAAC;CAC5B,KAAG,OAAO,CAAC,gBAAgB,CAmF3B,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,QAAQ,kBAAkB,KAAG,MAGnE,CAAC"}
@@ -0,0 +1,215 @@
1
+ import { readFile, stat } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { IMPROVE_STAGES, improvePaths } from './improve-workspace.js';
4
+ const isFile = async (file) => Boolean(await stat(file).then((entry) => entry.isFile()).catch(() => false));
5
+ const isDirectory = async (file) => Boolean(await stat(file).then((entry) => entry.isDirectory()).catch(() => false));
6
+ const stageState = (args) => {
7
+ const settled = args.record.stages[args.stage];
8
+ if (!settled) {
9
+ return IMPROVE_STAGES.indexOf(args.stage) > IMPROVE_STAGES.indexOf(args.requestedTo)
10
+ ? { stage: args.stage, state: 'not-requested', detail: 'outside the requested stage range' }
11
+ : { stage: args.stage, state: 'incomplete' };
12
+ }
13
+ if (settled.outcome === 'skipped') {
14
+ return { stage: args.stage, state: 'skipped', detail: 'a target was supplied' };
15
+ }
16
+ // Recorded at dispatch and never settled (F19). The entry exists so the kit
17
+ // can price the paid call it is still owed a result for; it is not evidence
18
+ // the stage ran, and reading it as one would call a stalled kit settled.
19
+ // `stalled` is the same entry after the run gave up on it (F28) — still
20
+ // incomplete, and still the stage `plan/STALL.md` is about.
21
+ if (settled.outcome === 'dispatched' || settled.outcome === 'stalled') {
22
+ return {
23
+ stage: args.stage,
24
+ state: 'incomplete',
25
+ detail: settled.outcome === 'stalled'
26
+ ? 'a paid call was dispatched and stalled; read `plan/STALL.md`'
27
+ : 'a paid call was dispatched and has not settled; read `plan/STALL.md`',
28
+ };
29
+ }
30
+ if (args.blocked) {
31
+ return {
32
+ stage: args.stage,
33
+ state: 'blocked',
34
+ detail: 'the coverage gate blocked the anchored plan; read `plan/GATE.md`',
35
+ };
36
+ }
37
+ if (!args.delivered)
38
+ return { stage: args.stage, state: 'incomplete', detail: 'recorded, but its files are not in the kit' };
39
+ if (args.stage === 'convert' && args.record.convert?.layout === 'fixed') {
40
+ return {
41
+ stage: 'convert',
42
+ state: 'fallback',
43
+ detail: args.record.convert.responsiveWarning ?? 'Responsive HTML was unavailable.',
44
+ };
45
+ }
46
+ return {
47
+ stage: args.stage,
48
+ state: settled.replayCount > 0 ? 'replayed' : 'settled',
49
+ ...(settled.replayCount > 0 ? { detail: `replayed ${settled.replayCount}×, bought once` } : {}),
50
+ };
51
+ };
52
+ /**
53
+ * The heading a `plan/STALL.md` leads with once the stall it recorded has
54
+ * settled. It lives here rather than beside the renderer because the kit
55
+ * status has to be able to tell a live stall from a resolved one without
56
+ * importing the renderer that writes it.
57
+ */
58
+ export const IMPROVE_STALL_RESOLVED_HEADING = '# Resolved — the stall recorded here has settled';
59
+ /**
60
+ * THE ONE BOUNDARY SENTENCE, and the reason it is one sentence in one module.
61
+ *
62
+ * The README and `plan/STALL.md` shipped together and disagreed (F22). The
63
+ * README said "do not approximate the design in CSS from the PNG while a stage
64
+ * is incomplete"; three lines further down STALL.md said "a LayerDoc survived
65
+ * this run, so the design's raster layers are usable without a plan". Both are
66
+ * true of different things — carry the rasters, do not redraw the layout — but
67
+ * nothing in the kit said so, and a lane had to adjudicate the contradiction
68
+ * itself, after both of its conversions were already spent. Every renderer
69
+ * prints this string; none writes its own version of it.
70
+ */
71
+ export const IMPROVE_NO_APPROXIMATION_RULE = 'Once the LayerDoc exists, carry its raster layers as'
72
+ + ' real assets — copy the files and reference them. Do not approximate the design\'s layout or'
73
+ + ' text in CSS from the PNG while a stage is incomplete; resume or convert first.';
74
+ /**
75
+ * A recovery command is presented as copy-and-run, so it has to survive being
76
+ * pasted. Capture URLs carry query strings and `--out-dir` paths carry spaces;
77
+ * either one unquoted breaks the line or backgrounds it at the `&`.
78
+ */
79
+ export const shellArg = (value) => (/^[A-Za-z0-9_./:=-]+$/u.test(value) ? value : `'${value.replace(/'/gu, "'\\''")}'`);
80
+ /**
81
+ * The draw is ready and nobody has chosen.
82
+ *
83
+ * `--pick` has no default, so a run with candidates and no pick is a finished
84
+ * run holding a drafts-only kit — not a stall. It is the one incomplete state
85
+ * whose recovery is neither a resume nor a conversion.
86
+ */
87
+ export const improveAwaitingPick = (record) => (!record.pick && !record.target && (record.draft?.candidates.length ?? 0) > 0);
88
+ /**
89
+ * The `--pick` placeholder, in one place, so the run summary and the kit README
90
+ * cannot drift into naming different slots for the same draw.
91
+ */
92
+ export const improvePickSlotHint = (record) => {
93
+ const slots = (record.draft?.candidates ?? []).map((candidate) => candidate.slot);
94
+ return `<A-${slots.at(-1) ?? 'P'}>`;
95
+ };
96
+ /** The one sentence a never-picked kit needs before its recovery command. */
97
+ export const IMPROVE_AWAITING_PICK_RULE = 'The draw is ready and nothing has been picked.'
98
+ + ' The CLI stops after drafting by design: nothing is converted until you choose a candidate,'
99
+ + ' because converting a candidate nobody chose spends money on a guess.';
100
+ export const improveRecoveryCommands = (args) => {
101
+ const runDir = shellArg(args.record.runDir);
102
+ const input = shellArg(args.record.input.value);
103
+ const design = shellArg(args.designImage);
104
+ // A never-picked kit has no winner, so `designImage` falls back to the
105
+ // capture — the page the run was asked to improve. The three commands below
106
+ // all resolve to it, so offering them here sent a reader to buy a conversion
107
+ // of the page they were improving. The pick is this state's only recovery.
108
+ if (improveAwaitingPick(args.record)) {
109
+ return [{
110
+ command: `12ui improve ${input} --out-dir ${runDir}`
111
+ + ` --from pick --pick ${improvePickSlotHint(args.record)}`,
112
+ spends: 'picks a candidate, then buys its conversion and plan',
113
+ }];
114
+ }
115
+ return [
116
+ {
117
+ command: `12ui improve ${input} --out-dir ${runDir} --from convert`,
118
+ spends: 'resumes; settled stages replay',
119
+ },
120
+ { command: `12ui convert ${design} --output html`, spends: 'buys one conversion' },
121
+ // `--target` is documented against a URL input. Offering it for an image
122
+ // input would name a mode the CLI does not document.
123
+ ...(args.record.input.kind === 'url'
124
+ ? [{
125
+ command: `12ui improve ${input} --target ${design}`,
126
+ spends: 'buys one fused target conversion',
127
+ }]
128
+ : []),
129
+ ];
130
+ };
131
+ /** One indented, copy-pasteable line; the cost rides along as a shell comment. */
132
+ export const improveRecoveryLine = (entry) => (` ${entry.command} # ${entry.spends}`);
133
+ export const readImproveKitStatus = async (args) => {
134
+ const paths = improvePaths(args.record.runDir);
135
+ const requestedTo = args.requestedTo ?? IMPROVE_STAGES[IMPROVE_STAGES.length - 1];
136
+ const [winner, sourceImage, layerDoc, assets, plan, gate, stall] = await Promise.all([
137
+ isFile(paths.winnerImage),
138
+ isFile(paths.sourceImage),
139
+ isFile(paths.targetLayerDoc),
140
+ isDirectory(`${paths.targetLayerDoc}.assets`),
141
+ isFile(path.join(paths.planDir, 'plan-annotated.md')),
142
+ isFile(path.join(paths.planDir, 'GATE.md')),
143
+ isFile(path.join(paths.planDir, 'STALL.md')),
144
+ ]);
145
+ const stallResolved = stall && (await readFile(path.join(paths.planDir, 'STALL.md'), 'utf8')
146
+ .then((content) => content.startsWith(IMPROVE_STALL_RESOLVED_HEADING))
147
+ .catch(() => false));
148
+ const recordedHtml = args.record.convert?.html;
149
+ const targetHtml = recordedHtml ? await isFile(recordedHtml) : await isFile(paths.targetHtml);
150
+ // Name a file that is actually here. A `--target <layerdoc>` kit never gets a
151
+ // winner.png, and a run that stalled before pick has only its capture.
152
+ const captured = args.record.capture?.sourceImage;
153
+ const designImage = winner
154
+ ? paths.winnerImage
155
+ : sourceImage
156
+ ? paths.sourceImage
157
+ : captured && await isFile(captured)
158
+ ? captured
159
+ : layerDoc && args.record.target?.kind === 'layerdoc'
160
+ ? paths.targetLayerDoc
161
+ : paths.winnerImage;
162
+ const designKind = designImage === paths.targetLayerDoc ? 'layerdoc' : 'image';
163
+ const delivered = {
164
+ capture: Boolean(args.record.capture),
165
+ draft: Boolean(args.record.draft),
166
+ pick: Boolean(args.record.pick),
167
+ convert: layerDoc,
168
+ plan: plan || gate,
169
+ };
170
+ const gateBlocked = gate && !plan;
171
+ const stages = IMPROVE_STAGES.map((stage) => stageState({
172
+ record: args.record,
173
+ stage,
174
+ requestedTo,
175
+ delivered: delivered[stage],
176
+ blocked: stage === 'plan' && gateBlocked,
177
+ }));
178
+ const targetMode = !layerDoc
179
+ ? 'none'
180
+ : args.record.convert?.layout === 'fixed'
181
+ ? 'fixed-layout fallback'
182
+ : targetHtml ? 'responsive HTML' : 'LayerDoc only';
183
+ // Only stages the caller actually asked for can be missing. `--to pick` is a
184
+ // finished run, not an incomplete one.
185
+ const owed = (stage) => (IMPROVE_STAGES.indexOf(stage) <= IMPROVE_STAGES.indexOf(requestedTo));
186
+ // A supplied `*.layerdoc.json` target buys no conversion, so it owes neither
187
+ // extracted assets nor target HTML: naming them missing would be a false alarm.
188
+ const suppliedDocument = args.record.target?.kind === 'layerdoc';
189
+ const convertOwed = owed('convert') && !suppliedDocument;
190
+ const missing = [
191
+ ...(!owed('convert') || layerDoc ? [] : ['no LayerDoc']),
192
+ ...(!convertOwed || assets ? [] : ['no assets']),
193
+ ...(!convertOwed || targetHtml ? [] : ['no target HTML']),
194
+ ...(!owed('plan') || plan || gate ? [] : ['no plan']),
195
+ ];
196
+ const complete = stages.every((entry) => entry.state !== 'incomplete') && missing.length === 0;
197
+ return {
198
+ stages,
199
+ complete,
200
+ gateBlocked,
201
+ missing,
202
+ targetMode,
203
+ present: {
204
+ design: winner || sourceImage, layerDoc, assets, targetHtml, plan, gate, stall, stallResolved,
205
+ },
206
+ designImage,
207
+ designKind,
208
+ recovery: improveRecoveryCommands({ record: args.record, designImage }),
209
+ };
210
+ };
211
+ export const improveStageStatusLine = (status) => {
212
+ const label = status.state === 'incomplete' ? 'INCOMPLETE' : status.state;
213
+ return `${status.stage}: ${label}${status.detail ? ` — ${status.detail}` : ''}`;
214
+ };
215
+ //# sourceMappingURL=improve-kit-status.js.map