@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.
- package/SKILL.md +1 -1
- package/dist/branch-client.d.ts +2 -0
- package/dist/branch-client.d.ts.map +1 -1
- package/dist/branch-client.js +1 -0
- package/dist/branch-client.js.map +1 -1
- package/dist/cli-arguments.d.ts.map +1 -1
- package/dist/cli-arguments.js +2 -0
- package/dist/cli-arguments.js.map +1 -1
- package/dist/cli-conversion-derivation.d.ts +2 -1
- package/dist/cli-conversion-derivation.d.ts.map +1 -1
- package/dist/cli-conversion-derivation.js +9 -1
- package/dist/cli-conversion-derivation.js.map +1 -1
- package/dist/cli-convert-command.d.ts.map +1 -1
- package/dist/cli-convert-command.js +111 -16
- package/dist/cli-convert-command.js.map +1 -1
- package/dist/cli-corpus-command.d.ts.map +1 -1
- package/dist/cli-corpus-command.js +5 -2
- package/dist/cli-corpus-command.js.map +1 -1
- package/dist/cli-corpus-evidence.d.ts.map +1 -1
- package/dist/cli-corpus-evidence.js +2 -1
- package/dist/cli-corpus-evidence.js.map +1 -1
- package/dist/cli-corpus-reference-downloads.d.ts +1 -0
- package/dist/cli-corpus-reference-downloads.d.ts.map +1 -1
- package/dist/cli-corpus-reference-downloads.js +13 -3
- package/dist/cli-corpus-reference-downloads.js.map +1 -1
- package/dist/cli-corpus-types.d.ts +2 -0
- package/dist/cli-corpus-types.d.ts.map +1 -1
- package/dist/cli-draft-command.d.ts +11 -0
- package/dist/cli-draft-command.d.ts.map +1 -1
- package/dist/cli-draft-command.js +10 -1
- package/dist/cli-draft-command.js.map +1 -1
- package/dist/cli-help/design.d.ts +2 -2
- package/dist/cli-help/design.d.ts.map +1 -1
- package/dist/cli-help/design.js +12 -2
- package/dist/cli-help/design.js.map +1 -1
- package/dist/cli-help/index.d.ts +2 -2
- package/dist/cli-improve-command.d.ts.map +1 -1
- package/dist/cli-improve-command.js +317 -70
- package/dist/cli-improve-command.js.map +1 -1
- package/dist/cli-next-command.d.ts.map +1 -1
- package/dist/cli-next-command.js +44 -4
- package/dist/cli-next-command.js.map +1 -1
- package/dist/cli-usage.js +2 -2
- package/dist/concept-input.d.ts +21 -0
- package/dist/concept-input.d.ts.map +1 -1
- package/dist/concept-input.js +32 -10
- package/dist/concept-input.js.map +1 -1
- package/dist/conversion-client.d.ts +39 -1
- package/dist/conversion-client.d.ts.map +1 -1
- package/dist/conversion-client.js +205 -3
- package/dist/conversion-client.js.map +1 -1
- package/dist/corpus-client.d.ts +7 -1
- package/dist/corpus-client.d.ts.map +1 -1
- package/dist/corpus-client.js +6 -2
- package/dist/corpus-client.js.map +1 -1
- package/dist/corpus-reference-download-retry.d.ts +68 -0
- package/dist/corpus-reference-download-retry.d.ts.map +1 -0
- package/dist/corpus-reference-download-retry.js +123 -0
- package/dist/corpus-reference-download-retry.js.map +1 -0
- package/dist/corpus-request-error.d.ts +17 -0
- package/dist/corpus-request-error.d.ts.map +1 -0
- package/dist/corpus-request-error.js +21 -0
- package/dist/corpus-request-error.js.map +1 -0
- package/dist/draft-run.d.ts +9 -0
- package/dist/draft-run.d.ts.map +1 -1
- package/dist/draft-run.js +22 -5
- package/dist/draft-run.js.map +1 -1
- package/dist/draft-workspace.d.ts +2 -1
- package/dist/draft-workspace.d.ts.map +1 -1
- package/dist/draft-workspace.js.map +1 -1
- package/dist/hosted-draft-identity.d.ts +1 -0
- package/dist/hosted-draft-identity.d.ts.map +1 -1
- package/dist/hosted-draft-identity.js +1 -0
- package/dist/hosted-draft-identity.js.map +1 -1
- package/dist/improve-added-specs.d.ts +9 -0
- package/dist/improve-added-specs.d.ts.map +1 -1
- package/dist/improve-added-specs.js +28 -7
- package/dist/improve-added-specs.js.map +1 -1
- package/dist/improve-bootstrap-secret.d.ts +35 -0
- package/dist/improve-bootstrap-secret.d.ts.map +1 -0
- package/dist/improve-bootstrap-secret.js +61 -0
- package/dist/improve-bootstrap-secret.js.map +1 -0
- package/dist/improve-capture-redirect.d.ts +46 -0
- package/dist/improve-capture-redirect.d.ts.map +1 -0
- package/dist/improve-capture-redirect.js +68 -0
- package/dist/improve-capture-redirect.js.map +1 -0
- package/dist/improve-concept.d.ts +14 -1
- package/dist/improve-concept.d.ts.map +1 -1
- package/dist/improve-concept.js +29 -8
- package/dist/improve-concept.js.map +1 -1
- package/dist/improve-conversion-attempts.d.ts +96 -0
- package/dist/improve-conversion-attempts.d.ts.map +1 -0
- package/dist/improve-conversion-attempts.js +93 -0
- package/dist/improve-conversion-attempts.js.map +1 -0
- package/dist/improve-conversion-stage.d.ts +14 -0
- package/dist/improve-conversion-stage.d.ts.map +1 -1
- package/dist/improve-conversion-stage.js +254 -70
- package/dist/improve-conversion-stage.js.map +1 -1
- package/dist/improve-convert-progress.d.ts +36 -0
- package/dist/improve-convert-progress.d.ts.map +1 -0
- package/dist/improve-convert-progress.js +43 -0
- package/dist/improve-convert-progress.js.map +1 -0
- package/dist/improve-convert-resilience.d.ts +116 -0
- package/dist/improve-convert-resilience.d.ts.map +1 -1
- package/dist/improve-convert-resilience.js +158 -1
- package/dist/improve-convert-resilience.js.map +1 -1
- package/dist/improve-delivery-stages.d.ts.map +1 -1
- package/dist/improve-delivery-stages.js +5 -0
- package/dist/improve-delivery-stages.js.map +1 -1
- package/dist/improve-dom-diff.d.ts +2 -0
- package/dist/improve-dom-diff.d.ts.map +1 -1
- package/dist/improve-dom-diff.js +7 -0
- package/dist/improve-dom-diff.js.map +1 -1
- package/dist/improve-dom-gate.d.ts +7 -0
- package/dist/improve-dom-gate.d.ts.map +1 -1
- package/dist/improve-dom-gate.js +13 -0
- package/dist/improve-dom-gate.js.map +1 -1
- package/dist/improve-generation-stages.d.ts +3 -0
- package/dist/improve-generation-stages.d.ts.map +1 -1
- package/dist/improve-generation-stages.js +56 -10
- package/dist/improve-generation-stages.js.map +1 -1
- package/dist/improve-icon-svg.d.ts +47 -0
- package/dist/improve-icon-svg.d.ts.map +1 -0
- package/dist/improve-icon-svg.js +83 -0
- package/dist/improve-icon-svg.js.map +1 -0
- package/dist/improve-kit-assets.d.ts +129 -0
- package/dist/improve-kit-assets.d.ts.map +1 -0
- package/dist/improve-kit-assets.js +333 -0
- package/dist/improve-kit-assets.js.map +1 -0
- package/dist/improve-kit-ignore.d.ts +32 -0
- package/dist/improve-kit-ignore.d.ts.map +1 -0
- package/dist/improve-kit-ignore.js +111 -0
- package/dist/improve-kit-ignore.js.map +1 -0
- package/dist/improve-kit-readme.d.ts +11 -2
- package/dist/improve-kit-readme.d.ts.map +1 -1
- package/dist/improve-kit-readme.js +282 -26
- package/dist/improve-kit-readme.js.map +1 -1
- package/dist/improve-kit-stall.d.ts +113 -0
- package/dist/improve-kit-stall.d.ts.map +1 -0
- package/dist/improve-kit-stall.js +311 -0
- package/dist/improve-kit-stall.js.map +1 -0
- package/dist/improve-kit-status.d.ts +105 -0
- package/dist/improve-kit-status.d.ts.map +1 -0
- package/dist/improve-kit-status.js +215 -0
- package/dist/improve-kit-status.js.map +1 -0
- package/dist/improve-options.d.ts +16 -1
- package/dist/improve-options.d.ts.map +1 -1
- package/dist/improve-options.js +65 -15
- package/dist/improve-options.js.map +1 -1
- package/dist/improve-plan-annotated-render.d.ts +45 -0
- package/dist/improve-plan-annotated-render.d.ts.map +1 -0
- package/dist/improve-plan-annotated-render.js +196 -0
- package/dist/improve-plan-annotated-render.js.map +1 -0
- package/dist/improve-plan-annotator.d.ts +7 -1
- package/dist/improve-plan-annotator.d.ts.map +1 -1
- package/dist/improve-plan-annotator.js +22 -45
- package/dist/improve-plan-annotator.js.map +1 -1
- package/dist/improve-raster-layers-section.d.ts +21 -0
- package/dist/improve-raster-layers-section.d.ts.map +1 -0
- package/dist/improve-raster-layers-section.js +45 -0
- package/dist/improve-raster-layers-section.js.map +1 -0
- package/dist/improve-reset.d.ts +122 -0
- package/dist/improve-reset.d.ts.map +1 -0
- package/dist/improve-reset.js +141 -0
- package/dist/improve-reset.js.map +1 -0
- package/dist/improve-run-summary.d.ts +35 -0
- package/dist/improve-run-summary.d.ts.map +1 -0
- package/dist/improve-run-summary.js +180 -0
- package/dist/improve-run-summary.js.map +1 -0
- package/dist/improve-stage-shared.d.ts +44 -1
- package/dist/improve-stage-shared.d.ts.map +1 -1
- package/dist/improve-stage-shared.js +80 -3
- package/dist/improve-stage-shared.js.map +1 -1
- package/dist/improve-stop-handler.d.ts +73 -0
- package/dist/improve-stop-handler.d.ts.map +1 -0
- package/dist/improve-stop-handler.js +126 -0
- package/dist/improve-stop-handler.js.map +1 -0
- package/dist/improve-terminal-event.d.ts +118 -0
- package/dist/improve-terminal-event.d.ts.map +1 -0
- package/dist/improve-terminal-event.js +87 -0
- package/dist/improve-terminal-event.js.map +1 -0
- package/dist/improve-token-patch.d.ts +2 -0
- package/dist/improve-token-patch.d.ts.map +1 -1
- package/dist/improve-token-patch.js +23 -5
- package/dist/improve-token-patch.js.map +1 -1
- package/dist/improve-workspace.d.ts +94 -2
- package/dist/improve-workspace.d.ts.map +1 -1
- package/dist/improve-workspace.js +19 -1
- package/dist/improve-workspace.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/legacy-skill-catalog.d.ts.map +1 -1
- package/dist/legacy-skill-catalog.js +143 -0
- package/dist/legacy-skill-catalog.js.map +1 -1
- package/dist/mcp-tool-definitions.js +1 -1
- package/dist/mcp-tool-definitions.js.map +1 -1
- package/dist/mcp-tool-handler.d.ts.map +1 -1
- package/dist/mcp-tool-handler.js +3 -0
- package/dist/mcp-tool-handler.js.map +1 -1
- package/dist/redesign-capture.d.ts +17 -0
- package/dist/redesign-capture.d.ts.map +1 -1
- package/dist/redesign-capture.js +55 -3
- package/dist/redesign-capture.js.map +1 -1
- package/dist/responsive-alternative-materializer.d.ts +19 -0
- package/dist/responsive-alternative-materializer.d.ts.map +1 -0
- package/dist/responsive-alternative-materializer.js +76 -0
- package/dist/responsive-alternative-materializer.js.map +1 -0
- package/dist/run-journal-unfinished.d.ts +56 -0
- package/dist/run-journal-unfinished.d.ts.map +1 -0
- package/dist/run-journal-unfinished.js +126 -0
- package/dist/run-journal-unfinished.js.map +1 -0
- package/dist/run-journal.d.ts +25 -1
- package/dist/run-journal.d.ts.map +1 -1
- package/dist/run-journal.js +15 -1
- package/dist/run-journal.js.map +1 -1
- package/open-design.json +2 -2
- package/package.json +1 -1
- package/skills/12ui-design/SKILL.md +9 -1
- package/skills/12ui-design/improve.md +83 -6
- 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
|