@12ui/design 0.2.28 → 0.2.30
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/README.md +97 -3
- package/SKILL.md +1 -1
- package/dist/branch-execution-types.d.ts +2 -0
- package/dist/branch-execution-types.d.ts.map +1 -1
- package/dist/branch-execution.d.ts.map +1 -1
- package/dist/branch-execution.js +3 -0
- package/dist/branch-execution.js.map +1 -1
- package/dist/branch-run-record.d.ts +1 -0
- package/dist/branch-run-record.d.ts.map +1 -1
- package/dist/branch-run-record.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-branch-command.d.ts +4 -0
- package/dist/cli-branch-command.d.ts.map +1 -1
- package/dist/cli-branch-command.js +30 -3
- package/dist/cli-branch-command.js.map +1 -1
- package/dist/cli-capabilities.d.ts +15 -0
- package/dist/cli-capabilities.d.ts.map +1 -1
- package/dist/cli-capabilities.js +19 -0
- package/dist/cli-capabilities.js.map +1 -1
- package/dist/cli-help/design.d.ts +18 -1
- package/dist/cli-help/design.d.ts.map +1 -1
- package/dist/cli-help/design.js +33 -0
- package/dist/cli-help/design.js.map +1 -1
- package/dist/cli-help/index.d.ts +18 -1
- package/dist/cli-help/index.d.ts.map +1 -1
- package/dist/cli-prototype-command.d.ts +12 -0
- package/dist/cli-prototype-command.d.ts.map +1 -0
- package/dist/cli-prototype-command.js +29 -0
- package/dist/cli-prototype-command.js.map +1 -0
- package/dist/cli-review-command.d.ts +8 -0
- package/dist/cli-review-command.d.ts.map +1 -0
- package/dist/cli-review-command.js +90 -0
- package/dist/cli-review-command.js.map +1 -0
- package/dist/cli-run.d.ts.map +1 -1
- package/dist/cli-run.js +16 -0
- package/dist/cli-run.js.map +1 -1
- package/dist/cli-usage.d.ts.map +1 -1
- package/dist/cli-usage.js +8 -1
- package/dist/cli-usage.js.map +1 -1
- package/dist/conversion-client.d.ts.map +1 -1
- package/dist/conversion-client.js +8 -1
- package/dist/conversion-client.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/legacy-skill-catalog.d.ts.map +1 -1
- package/dist/legacy-skill-catalog.js +8 -0
- package/dist/legacy-skill-catalog.js.map +1 -1
- package/dist/next-wait-lease.d.ts +2 -1
- package/dist/next-wait-lease.d.ts.map +1 -1
- package/dist/next-wait-lease.js +73 -22
- package/dist/next-wait-lease.js.map +1 -1
- package/dist/next-wait-process.d.ts +17 -0
- package/dist/next-wait-process.d.ts.map +1 -0
- package/dist/next-wait-process.js +40 -0
- package/dist/next-wait-process.js.map +1 -0
- package/dist/prototype-gap-html.d.ts +10 -0
- package/dist/prototype-gap-html.d.ts.map +1 -0
- package/dist/prototype-gap-html.js +55 -0
- package/dist/prototype-gap-html.js.map +1 -0
- package/dist/prototype-gap-source.d.ts +14 -0
- package/dist/prototype-gap-source.d.ts.map +1 -0
- package/dist/prototype-gap-source.js +87 -0
- package/dist/prototype-gap-source.js.map +1 -0
- package/dist/prototype-gates.d.ts +24 -0
- package/dist/prototype-gates.d.ts.map +1 -0
- package/dist/prototype-gates.js +76 -0
- package/dist/prototype-gates.js.map +1 -0
- package/dist/prototype-label-client.d.ts +51 -0
- package/dist/prototype-label-client.d.ts.map +1 -0
- package/dist/prototype-label-client.js +53 -0
- package/dist/prototype-label-client.js.map +1 -0
- package/dist/prototype-label-score.d.ts +26 -0
- package/dist/prototype-label-score.d.ts.map +1 -0
- package/dist/prototype-label-score.js +51 -0
- package/dist/prototype-label-score.js.map +1 -0
- package/dist/prototype-process.d.ts +13 -0
- package/dist/prototype-process.d.ts.map +1 -0
- package/dist/prototype-process.js +26 -0
- package/dist/prototype-process.js.map +1 -0
- package/dist/prototype-requests.d.ts +29 -0
- package/dist/prototype-requests.d.ts.map +1 -0
- package/dist/prototype-requests.js +34 -0
- package/dist/prototype-requests.js.map +1 -0
- package/dist/prototype-runner.d.ts +22 -0
- package/dist/prototype-runner.d.ts.map +1 -0
- package/dist/prototype-runner.js +159 -0
- package/dist/prototype-runner.js.map +1 -0
- package/dist/prototype-source.d.ts +9 -0
- package/dist/prototype-source.d.ts.map +1 -0
- package/dist/prototype-source.js +48 -0
- package/dist/prototype-source.js.map +1 -0
- package/dist/review-discovery.d.ts +11 -0
- package/dist/review-discovery.d.ts.map +1 -0
- package/dist/review-discovery.js +427 -0
- package/dist/review-discovery.js.map +1 -0
- package/dist/review-edit-html.d.ts +6 -0
- package/dist/review-edit-html.d.ts.map +1 -0
- package/dist/review-edit-html.js +11 -0
- package/dist/review-edit-html.js.map +1 -0
- package/dist/review-edit-source.d.ts +22 -0
- package/dist/review-edit-source.d.ts.map +1 -0
- package/dist/review-edit-source.js +103 -0
- package/dist/review-edit-source.js.map +1 -0
- package/dist/review-edit.d.ts +15 -0
- package/dist/review-edit.d.ts.map +1 -0
- package/dist/review-edit.js +192 -0
- package/dist/review-edit.js.map +1 -0
- package/dist/review-layerdoc-diff.d.ts +7 -0
- package/dist/review-layerdoc-diff.d.ts.map +1 -0
- package/dist/review-layerdoc-diff.js +92 -0
- package/dist/review-layerdoc-diff.js.map +1 -0
- package/dist/review-page-assets.d.ts +3 -0
- package/dist/review-page-assets.d.ts.map +1 -0
- package/dist/review-page-assets.js +62 -0
- package/dist/review-page-assets.js.map +1 -0
- package/dist/review-page.d.ts +3 -0
- package/dist/review-page.d.ts.map +1 -0
- package/dist/review-page.js +275 -0
- package/dist/review-page.js.map +1 -0
- package/dist/review-pricing.d.ts +14 -0
- package/dist/review-pricing.d.ts.map +1 -0
- package/dist/review-pricing.js +23 -0
- package/dist/review-pricing.js.map +1 -0
- package/dist/review-prototype-gap.d.ts +48 -0
- package/dist/review-prototype-gap.d.ts.map +1 -0
- package/dist/review-prototype-gap.js +192 -0
- package/dist/review-prototype-gap.js.map +1 -0
- package/dist/review-server.d.ts +22 -0
- package/dist/review-server.d.ts.map +1 -0
- package/dist/review-server.js +268 -0
- package/dist/review-server.js.map +1 -0
- package/dist/review-store.d.ts +11 -0
- package/dist/review-store.d.ts.map +1 -0
- package/dist/review-store.js +96 -0
- package/dist/review-store.js.map +1 -0
- package/dist/review-types.d.ts +140 -0
- package/dist/review-types.d.ts.map +1 -0
- package/dist/review-types.js +2 -0
- package/dist/review-types.js.map +1 -0
- package/dist/run-journal-commands.d.ts.map +1 -1
- package/dist/run-journal-commands.js +19 -0
- package/dist/run-journal-commands.js.map +1 -1
- package/open-design.json +2 -2
- package/package.json +7 -1
- package/prototype-kit/analyze.mjs +275 -0
- package/prototype-kit/build.mjs +393 -0
- package/prototype-kit/inventory.mjs +104 -0
- package/prototype-kit/label-briefs.mjs +47 -0
- package/prototype-kit/lib/actions.mjs +15 -0
- package/prototype-kit/lib/navigation.mjs +33 -0
- package/prototype-kit/lib/runtime-check.mjs +126 -0
- package/prototype-kit/lib/shells.mjs +68 -0
- package/prototype-kit/lib/static-server.mjs +40 -0
- package/prototype-kit/lib/text.mjs +20 -0
- package/prototype-kit/runtime/proto.css +46 -0
- package/prototype-kit/runtime/proto.js +173 -0
- package/prototype-kit/score-labels.mjs +42 -0
- package/prototype-kit/tests/README.md +28 -0
- package/prototype-kit/tests/adversarial-runtime.mjs +90 -0
- package/prototype-kit/tests/discover-runs.mjs +29 -0
- package/prototype-kit/tests/fixtures/no-semantic/branch.plan.json +7 -0
- package/prototype-kit/tests/fixtures/no-semantic/pages/legacy.html +1 -0
- package/prototype-kit/tests/fixtures/partial-plan/branch.plan.json +5 -0
- package/prototype-kit/tests/fixtures/partial-plan/pages/orphan.html +4 -0
- package/prototype-kit/tests/fixtures/runtime/double.html +5 -0
- package/prototype-kit/tests/fixtures/runtime/history-destination.html +1 -0
- package/prototype-kit/tests/fixtures/runtime/history.html +6 -0
- package/prototype-kit/tests/fixtures/runtime/hover-stack.html +15 -0
- package/prototype-kit/tests/fixtures/runtime/invalid-dropdown.html +6 -0
- package/prototype-kit/tests/fixtures/runtime/nested.html +7 -0
- package/prototype-kit/tests/fixtures/three-shell/branch.plan.json +30 -0
- package/prototype-kit/tests/fixtures/three-shell/pages/p0-home.html +11 -0
- package/prototype-kit/tests/fixtures/three-shell/pages/p1-reports.html +11 -0
- package/prototype-kit/tests/lib/run-discovery.mjs +87 -0
- package/prototype-kit/tests/lib/run-process.mjs +49 -0
- package/prototype-kit/tests/offline-check.mjs +41 -0
- package/prototype-kit/tests/population-sweep.mjs +94 -0
- package/prototype-kit/tests/rules-check.mjs +50 -0
- package/prototype-kit/verify-runtime.mjs +36 -0
- package/skills/12ui-design/SKILL.md +8 -2
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { reviewFileUrl } from './review-discovery.js';
|
|
3
|
+
import { REVIEW_PAGE_SCRIPT, REVIEW_PAGE_STYLES } from './review-page-assets.js';
|
|
4
|
+
import { usd } from './review-pricing.js';
|
|
5
|
+
import { REVIEW_PROTOTYPE_GAP_BASE_USD } from './review-prototype-gap.js';
|
|
6
|
+
const escapeHtml = (value) => value
|
|
7
|
+
.replaceAll('&', '&')
|
|
8
|
+
.replaceAll('<', '<')
|
|
9
|
+
.replaceAll('>', '>')
|
|
10
|
+
.replaceAll('"', '"')
|
|
11
|
+
.replaceAll("'", ''');
|
|
12
|
+
const groupLabels = {
|
|
13
|
+
drafts: 'Draft candidates',
|
|
14
|
+
screens: 'Branch screens',
|
|
15
|
+
'branch-pages': 'Branch design',
|
|
16
|
+
pages: 'Exported pages',
|
|
17
|
+
conversions: 'Conversions',
|
|
18
|
+
};
|
|
19
|
+
const mediaAt = (file) => {
|
|
20
|
+
const lower = file.toLowerCase();
|
|
21
|
+
if (lower.endsWith('.html'))
|
|
22
|
+
return 'html';
|
|
23
|
+
if (/\.(?:png|jpe?g|webp)$/u.test(lower))
|
|
24
|
+
return 'image';
|
|
25
|
+
return 'layerdoc';
|
|
26
|
+
};
|
|
27
|
+
const mediaFrame = (args) => {
|
|
28
|
+
const url = reviewFileUrl(args.run, args.media.path);
|
|
29
|
+
if (args.media.kind === 'image') {
|
|
30
|
+
return `<a class="preview preview--image" href="${url}" target="_blank" rel="noreferrer">
|
|
31
|
+
<img src="${url}" alt="${escapeHtml(args.label)}">
|
|
32
|
+
</a>`;
|
|
33
|
+
}
|
|
34
|
+
if (args.media.kind === 'html') {
|
|
35
|
+
return `<div class="preview preview--html">
|
|
36
|
+
<iframe src="${url}" title="${escapeHtml(args.label)}" loading="lazy" sandbox="allow-scripts"></iframe>
|
|
37
|
+
<a class="open" href="${url}" target="_blank" rel="noreferrer">Open</a>
|
|
38
|
+
</div>`;
|
|
39
|
+
}
|
|
40
|
+
return `<div class="preview preview--layerdoc">
|
|
41
|
+
<span class="layerdoc-mark" aria-hidden="true">{ }</span>
|
|
42
|
+
<strong>LayerDoc ready</strong>
|
|
43
|
+
<span>Apply an edit to render a comparison.</span>
|
|
44
|
+
</div>`;
|
|
45
|
+
};
|
|
46
|
+
const changedRegionStrip = (edit) => {
|
|
47
|
+
const regions = edit.changedRegions ?? [];
|
|
48
|
+
if (regions.length === 0) {
|
|
49
|
+
return '<div class="diff-strip"><div class="diff-region"><strong>No declared region change found</strong><span>The original and edited results remain available for visual inspection.</span></div></div>';
|
|
50
|
+
}
|
|
51
|
+
return `<div class="diff-strip" aria-label="Changed-region diff">${regions.map((region) => {
|
|
52
|
+
const box = region.box ? ` · ${region.box.map((value) => Math.round(value)).join(', ')}` : '';
|
|
53
|
+
const contentChanged = region.before !== region.after;
|
|
54
|
+
return `<div class="diff-region">
|
|
55
|
+
<strong>${escapeHtml(region.viewport)} · ${escapeHtml(region.label)}</strong>
|
|
56
|
+
<span>${escapeHtml(region.fields.join(', '))}${escapeHtml(box)}</span>
|
|
57
|
+
${contentChanged && region.before ? `<del>${escapeHtml(region.before)}</del>` : ''}
|
|
58
|
+
${contentChanged && region.after ? `<ins>${escapeHtml(region.after)}</ins>` : ''}
|
|
59
|
+
</div>`;
|
|
60
|
+
}).join('')}</div>`;
|
|
61
|
+
};
|
|
62
|
+
const comparison = (run, item) => {
|
|
63
|
+
if (!item.latestEdit)
|
|
64
|
+
return '';
|
|
65
|
+
const originalPath = path.resolve(run.root, item.latestEdit.original);
|
|
66
|
+
const editedPath = path.resolve(run.root, item.latestEdit.resultPath ?? item.latestEdit.html);
|
|
67
|
+
const operations = item.latestEdit.editOperationIds ?? (item.latestEdit.editOperationId ? [item.latestEdit.editOperationId] : []);
|
|
68
|
+
const cost = item.latestEdit.cost ? usd(item.latestEdit.cost.baseUsd) : 'price not recorded';
|
|
69
|
+
return `<div class="comparison">
|
|
70
|
+
<section>
|
|
71
|
+
<p class="eyebrow">Original</p>
|
|
72
|
+
${mediaFrame({
|
|
73
|
+
run,
|
|
74
|
+
media: { kind: mediaAt(originalPath), path: originalPath },
|
|
75
|
+
label: `${item.title}, original`,
|
|
76
|
+
})}
|
|
77
|
+
</section>
|
|
78
|
+
<section>
|
|
79
|
+
<p class="eyebrow">Edited</p>
|
|
80
|
+
${mediaFrame({
|
|
81
|
+
run,
|
|
82
|
+
media: { kind: 'html', path: editedPath },
|
|
83
|
+
label: `${item.title}, edited`,
|
|
84
|
+
})}
|
|
85
|
+
</section>
|
|
86
|
+
</div>
|
|
87
|
+
${changedRegionStrip(item.latestEdit)}
|
|
88
|
+
<p class="edit-receipt">Applied “${escapeHtml(item.latestEdit.prompt)}” · ${escapeHtml(cost)} base · ${operations.length} ${operations.length === 1 ? 'edit' : 'edits'}${operations.length > 0 ? ` · ${escapeHtml(operations.join(', '))}` : ''}</p>`;
|
|
89
|
+
};
|
|
90
|
+
const branchSequence = (run, item) => {
|
|
91
|
+
if (!item.branchPage || item.branchPage.screens.length === 0)
|
|
92
|
+
return '';
|
|
93
|
+
return `<section class="screen-sequence">
|
|
94
|
+
<p class="eyebrow">Plan sequence</p>
|
|
95
|
+
<div class="sequence-track">${item.branchPage.screens.map((screen) => `<figure class="screen">
|
|
96
|
+
${mediaFrame({ run, media: screen.media, label: `${item.title}, ${screen.label}` })}
|
|
97
|
+
<figcaption>
|
|
98
|
+
<p class="eyebrow">${screen.winner ? 'Winner' : escapeHtml(screen.label)}</p>
|
|
99
|
+
<h5>${escapeHtml(screen.direction)}</h5>
|
|
100
|
+
${screen.caption ? `<p>${escapeHtml(screen.caption)}</p>` : ''}
|
|
101
|
+
</figcaption>
|
|
102
|
+
</figure>`).join('')}</div>
|
|
103
|
+
</section>`;
|
|
104
|
+
};
|
|
105
|
+
const feedbackPanel = (run, item) => {
|
|
106
|
+
const mark = item.feedback?.mark ?? null;
|
|
107
|
+
return `<form class="feedback" data-feedback data-run="${escapeHtml(run.id)}" data-item="${escapeHtml(item.id)}" data-mark="${mark ?? ''}">
|
|
108
|
+
<div class="mark-row" role="group" aria-label="Review mark">
|
|
109
|
+
<button type="button" data-mark="pick" aria-pressed="${mark === 'pick'}" class="${mark === 'pick' ? 'active' : ''}">Pick</button>
|
|
110
|
+
<button type="button" data-mark="approve" aria-pressed="${mark === 'approve'}" class="${mark === 'approve' ? 'active' : ''}">Approve</button>
|
|
111
|
+
<button type="button" data-mark="" class="clear">Clear</button>
|
|
112
|
+
</div>
|
|
113
|
+
<label>
|
|
114
|
+
<span>Feedback</span>
|
|
115
|
+
<textarea name="note" maxlength="8192" placeholder="Say what to keep or change">${escapeHtml(item.feedback?.note ?? '')}</textarea>
|
|
116
|
+
</label>
|
|
117
|
+
<div class="save-row">
|
|
118
|
+
<button type="submit" class="save">Save</button>
|
|
119
|
+
<span class="status" role="status">${item.feedback ? 'Saved' : ''}</span>
|
|
120
|
+
</div>
|
|
121
|
+
</form>`;
|
|
122
|
+
};
|
|
123
|
+
const editPanel = (model, run, item) => {
|
|
124
|
+
if (!item.editSource || !item.editQuote)
|
|
125
|
+
return '';
|
|
126
|
+
const draft = item.editQuote.mode === 'convert-then-edit';
|
|
127
|
+
const price = `${usd(item.editQuote.baseUsd)}+`;
|
|
128
|
+
const explanation = draft
|
|
129
|
+
? 'Raw image. This converts once, then edits the resulting LayerDoc; the image is not edited in place.'
|
|
130
|
+
: item.editSource.kind === 'package-page'
|
|
131
|
+
? `Edits this page directly through its ${item.editSource.viewportCount} stored screen LayerDocs.`
|
|
132
|
+
: 'Edits this stored LayerDoc directly.';
|
|
133
|
+
if (!model.editAvailable) {
|
|
134
|
+
return `<div class="edit edit--disabled">
|
|
135
|
+
<p class="eyebrow">${draft ? 'Convert, then edit' : 'Direct edit'} · ${escapeHtml(price)}</p>
|
|
136
|
+
<p class="edit-note">${escapeHtml(explanation)} Run <code>12ui auth login</code> to enable paid actions.</p>
|
|
137
|
+
</div>`;
|
|
138
|
+
}
|
|
139
|
+
return `<form class="edit" data-edit data-mode="${item.editQuote.mode}" data-run="${escapeHtml(run.id)}" data-item="${escapeHtml(item.id)}">
|
|
140
|
+
<p class="eyebrow">${draft ? 'Convert, then edit' : 'Direct edit'}</p>
|
|
141
|
+
<p class="edit-note">${escapeHtml(explanation)}</p>
|
|
142
|
+
<label>
|
|
143
|
+
<span>Instruction</span>
|
|
144
|
+
<textarea name="prompt" maxlength="8192" required placeholder="Make the title shorter and increase its size"></textarea>
|
|
145
|
+
</label>
|
|
146
|
+
<p class="cost"><strong>${escapeHtml(usd(item.editQuote.baseUsd))} base after daily allowances.</strong> Image actions can add ${escapeHtml(usd(item.editQuote.possibleImageActionUsd.minimum))}–${escapeHtml(usd(item.editQuote.possibleImageActionUsd.maximum))} each. Comparison renders are included.</p>
|
|
147
|
+
<div class="save-row">
|
|
148
|
+
<button type="submit" class="apply">${draft ? 'Convert and edit' : 'Apply edit'} · ${escapeHtml(price)}</button>
|
|
149
|
+
<span class="status" role="status"></span>
|
|
150
|
+
</div>
|
|
151
|
+
</form>`;
|
|
152
|
+
};
|
|
153
|
+
const historyPanel = (run, item) => {
|
|
154
|
+
const history = item.editHistory ?? [];
|
|
155
|
+
if (history.length === 0)
|
|
156
|
+
return '';
|
|
157
|
+
return `<details class="history"><summary>${history.length} ${history.length === 1 ? 'edit' : 'edits'} saved in review.json</summary>
|
|
158
|
+
<ol>${history.map((edit) => {
|
|
159
|
+
const result = path.resolve(run.root, edit.resultPath ?? edit.html);
|
|
160
|
+
const cost = edit.cost ? usd(edit.cost.baseUsd) : 'price not recorded';
|
|
161
|
+
return `<li>“${escapeHtml(edit.prompt)}” · ${escapeHtml(cost)} · <a href="${reviewFileUrl(run, result)}" target="_blank" rel="noreferrer">Open result</a></li>`;
|
|
162
|
+
}).join('')}</ol>
|
|
163
|
+
</details>`;
|
|
164
|
+
};
|
|
165
|
+
const itemCard = (model, run, item) => {
|
|
166
|
+
const branch = item.group === 'branch-pages';
|
|
167
|
+
const mode = item.editQuote?.mode === 'convert-then-edit' ? 'Converts first' : item.editSource ? 'Edits directly' : '';
|
|
168
|
+
return `<article class="item ${branch || item.group === 'pages' || item.group === 'conversions' ? 'item--wide' : ''}" id="${escapeHtml(item.id)}">
|
|
169
|
+
<header class="item-head">
|
|
170
|
+
<div>
|
|
171
|
+
${branch ? `<p class="eyebrow">Page ${(item.branchPage?.index ?? 0) + 1}</p>` : ''}
|
|
172
|
+
<h4>${escapeHtml(item.title)}</h4>
|
|
173
|
+
${item.detail ? `<p>${escapeHtml(item.detail)}</p>` : ''}
|
|
174
|
+
</div>
|
|
175
|
+
<div class="item-badges">
|
|
176
|
+
${mode ? `<span class="edit-mode">${escapeHtml(mode)}</span>` : ''}
|
|
177
|
+
${item.feedback?.mark ? `<span class="mark-chip">${escapeHtml(item.feedback.mark)}</span>` : ''}
|
|
178
|
+
</div>
|
|
179
|
+
</header>
|
|
180
|
+
${branchSequence(run, item)}
|
|
181
|
+
${branch
|
|
182
|
+
? `<section class="published-page"><p class="eyebrow">Exported page · drag the lower edge to resize</p>${mediaFrame({ run, media: item.media, label: item.title })}</section>${comparison(run, item)}`
|
|
183
|
+
: item.latestEdit ? comparison(run, item) : mediaFrame({ run, media: item.media, label: item.title })}
|
|
184
|
+
<div class="controls">
|
|
185
|
+
${feedbackPanel(run, item)}
|
|
186
|
+
${editPanel(model, run, item)}
|
|
187
|
+
${historyPanel(run, item)}
|
|
188
|
+
</div>
|
|
189
|
+
</article>`;
|
|
190
|
+
};
|
|
191
|
+
const branchNavigation = (run) => {
|
|
192
|
+
if (run.branch?.scope !== 'site')
|
|
193
|
+
return '';
|
|
194
|
+
return `<nav class="site-nav" aria-label="Branch pages">${run.branch.pageItemIds.map((id, index) => {
|
|
195
|
+
const item = run.items.find((candidate) => candidate.id === id);
|
|
196
|
+
return item ? `<a href="#${escapeHtml(id)}">${index + 1}. ${escapeHtml(item.title)}</a>` : '';
|
|
197
|
+
}).join('')}</nav>`;
|
|
198
|
+
};
|
|
199
|
+
const prototypeAction = (model, run, label) => {
|
|
200
|
+
if (!model.prototypeAvailable) {
|
|
201
|
+
return `<div class="prototype-action prototype-action--disabled"><p>Run <code>12ui auth login</code> to enable prototype actions.</p></div>`;
|
|
202
|
+
}
|
|
203
|
+
return `<form class="prototype-action" data-prototype data-run="${escapeHtml(run.id)}">
|
|
204
|
+
<button type="submit" class="apply">${escapeHtml(label)}</button>
|
|
205
|
+
<span class="status" role="status"></span>
|
|
206
|
+
</form>`;
|
|
207
|
+
};
|
|
208
|
+
const prototypePanel = (model, run) => {
|
|
209
|
+
if (!run.branch)
|
|
210
|
+
return '';
|
|
211
|
+
const prototype = run.branch.prototype;
|
|
212
|
+
if (!prototype) {
|
|
213
|
+
return `<section class="prototype-panel prototype-panel--empty">
|
|
214
|
+
<div><p class="eyebrow">Interactive branch</p><h3>Prototype this run</h3><p>Builds navigation, state transitions, content, and honest holding pages. Labeling uses one cheap product-provider call per exported screen.</p></div>
|
|
215
|
+
${prototypeAction(model, run, 'Prototype')}
|
|
216
|
+
</section>`;
|
|
217
|
+
}
|
|
218
|
+
const holdings = prototype.holdings.length === 0 ? '' : `<section class="prototype-holdings">
|
|
219
|
+
<header><p class="eyebrow">Missing destinations</p><h3>${prototype.holdings.length} ${prototype.holdings.length === 1 ? 'gap' : 'gaps'} surfaced by navigation</h3><p>Each action is explicit. It claims one matching draft, converts it with Standard, adds the real page, then rebuilds the prototype.</p></header>
|
|
220
|
+
<div class="holding-grid">${prototype.holdings.map((holding) => `<article class="holding-card">
|
|
221
|
+
<div class="item-head"><div><p class="eyebrow">Holding page</p><h4>${escapeHtml(holding.title)}</h4></div></div>
|
|
222
|
+
${mediaFrame({ run, media: { kind: 'html', path: holding.path }, label: `${holding.title} holding page` })}
|
|
223
|
+
${model.prototypeAvailable ? `<form class="edit" data-fill-gap data-run="${escapeHtml(run.id)}" data-holding="${escapeHtml(holding.slug)}">
|
|
224
|
+
<p class="edit-note">Generates this destination from the approved winner, converts it, and rebuilds the prototype. Nothing runs until you press the button.</p>
|
|
225
|
+
<div class="save-row"><button type="submit" class="apply">Fill this gap · ${escapeHtml(usd(REVIEW_PROTOTYPE_GAP_BASE_USD))}+</button><span class="status" role="status"></span></div>
|
|
226
|
+
</form>` : `<div class="edit edit--disabled" data-holding="${escapeHtml(holding.slug)}"><p>Run <code>12ui auth login</code> to enable this paid action.</p><div class="save-row"><button type="button" class="apply" disabled>Fill this gap · ${escapeHtml(usd(REVIEW_PROTOTYPE_GAP_BASE_USD))}+</button></div></div>`}
|
|
227
|
+
</article>`).join('')}</div>
|
|
228
|
+
</section>`;
|
|
229
|
+
return `<section class="prototype-panel">
|
|
230
|
+
<div class="prototype-copy"><p class="eyebrow">Interactive branch</p><h3>Prototype</h3><p>Open it, resize it, and follow the real navigation. The manifest records deterministic precedence, model labels, gates, and warnings.</p>${prototypeAction(model, run, 'Rebuild prototype')}</div>
|
|
231
|
+
${mediaFrame({ run, media: prototype.index, label: `${run.label} prototype` })}
|
|
232
|
+
${holdings}
|
|
233
|
+
</section>`;
|
|
234
|
+
};
|
|
235
|
+
const runSection = (model, run) => {
|
|
236
|
+
const groups = [...new Set(run.items.map((item) => item.group))];
|
|
237
|
+
return `<section class="run" id="${escapeHtml(run.id)}">
|
|
238
|
+
<header class="run-head">
|
|
239
|
+
<div>
|
|
240
|
+
<p class="eyebrow">${run.branch ? `${run.branch.scope} branch` : 'Run'}</p>
|
|
241
|
+
<h2>${escapeHtml(run.label)}</h2>
|
|
242
|
+
${run.branch ? `<p class="run-purpose">${escapeHtml(run.branch.concept)}</p>` : ''}
|
|
243
|
+
${run.branch?.sitePurpose ? `<p><strong>Site intent:</strong> ${escapeHtml(run.branch.sitePurpose)}</p>` : ''}
|
|
244
|
+
<p>${escapeHtml(run.detail)}</p>
|
|
245
|
+
${branchNavigation(run)}
|
|
246
|
+
</div>
|
|
247
|
+
<span class="count">${run.items.length} ${run.items.length === 1 ? 'item' : 'items'}</span>
|
|
248
|
+
</header>
|
|
249
|
+
${prototypePanel(model, run)}
|
|
250
|
+
${groups.map((group) => `<section class="group group--${group}">
|
|
251
|
+
<h3>${groupLabels[group]}</h3>
|
|
252
|
+
<div class="items">${run.items.filter((item) => item.group === group).map((item) => itemCard(model, run, item)).join('')}</div>
|
|
253
|
+
</section>`).join('')}
|
|
254
|
+
</section>`;
|
|
255
|
+
};
|
|
256
|
+
export const renderReviewPage = (model) => {
|
|
257
|
+
const itemCount = model.runs.reduce((total, run) => total + run.items.length, 0);
|
|
258
|
+
const marked = model.runs.reduce((total, run) => (total + run.items.filter((item) => item.feedback?.mark).length), 0);
|
|
259
|
+
const body = model.runs.length > 0
|
|
260
|
+
? model.runs.map((run) => runSection(model, run)).join('')
|
|
261
|
+
: '<section class="empty"><h2>No stored runs found</h2><p>Pass a run directory, or use <code>12ui review --all</code> from the project that owns its <code>.12ui</code> runs.</p></section>';
|
|
262
|
+
return `<!doctype html>
|
|
263
|
+
<html lang="en">
|
|
264
|
+
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>12ui review</title><style>${REVIEW_PAGE_STYLES}</style></head>
|
|
265
|
+
<body>
|
|
266
|
+
<header class="mast">
|
|
267
|
+
<div class="brand"><span class="brand-mark">12</span><div><h1>12ui review</h1><p>Review the design, edit what is structured, and leave exact feedback.</p></div></div>
|
|
268
|
+
<div class="summary"><span>${model.runs.length} ${model.runs.length === 1 ? 'run' : 'runs'}</span><span>${itemCount} ${itemCount === 1 ? 'item' : 'items'}</span><span>${marked} marked</span></div>
|
|
269
|
+
</header>
|
|
270
|
+
<main class="shell">${body}</main>
|
|
271
|
+
<script>${REVIEW_PAGE_SCRIPT}</script>
|
|
272
|
+
</body>
|
|
273
|
+
</html>`;
|
|
274
|
+
};
|
|
275
|
+
//# sourceMappingURL=review-page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-page.js","sourceRoot":"","sources":["../src/review-page.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ReviewEditCost, ReviewEditQuote } from './review-types.js';
|
|
2
|
+
export declare const REVIEW_CONVERSION_USD = 1;
|
|
3
|
+
export declare const REVIEW_EDIT_USD = 0.03;
|
|
4
|
+
export declare const REVIEW_IMAGE_ACTION_USD: {
|
|
5
|
+
readonly minimum: 0.02;
|
|
6
|
+
readonly maximum: 0.3;
|
|
7
|
+
};
|
|
8
|
+
export declare const reviewEditQuote: (args: {
|
|
9
|
+
conversions?: number;
|
|
10
|
+
edits?: number;
|
|
11
|
+
}) => ReviewEditQuote;
|
|
12
|
+
export declare const reviewEditCost: (quote: ReviewEditQuote) => ReviewEditCost;
|
|
13
|
+
export declare const usd: (value: number) => string;
|
|
14
|
+
//# sourceMappingURL=review-pricing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-pricing.d.ts","sourceRoot":"","sources":["../src/review-pricing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzE,eAAO,MAAM,qBAAqB,IAAI,CAAC;AACvC,eAAO,MAAM,eAAe,OAAO,CAAC;AACpC,eAAO,MAAM,uBAAuB;;;CAA2C,CAAC;AAEhF,eAAO,MAAM,eAAe,GAAI,MAAM;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,KAAG,eAUH,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,OAAO,eAAe,KAAG,cAMtD,CAAC;AAEH,eAAO,MAAM,GAAG,GAAI,OAAO,MAAM,KAAG,MAAgC,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const REVIEW_CONVERSION_USD = 1;
|
|
2
|
+
export const REVIEW_EDIT_USD = 0.03;
|
|
3
|
+
export const REVIEW_IMAGE_ACTION_USD = { minimum: 0.02, maximum: 0.3 };
|
|
4
|
+
export const reviewEditQuote = (args) => {
|
|
5
|
+
const conversionUsd = REVIEW_CONVERSION_USD * (args.conversions ?? 0);
|
|
6
|
+
const editUsd = REVIEW_EDIT_USD * (args.edits ?? 1);
|
|
7
|
+
return {
|
|
8
|
+
mode: conversionUsd > 0 ? 'convert-then-edit' : 'direct',
|
|
9
|
+
conversionUsd,
|
|
10
|
+
editUsd,
|
|
11
|
+
baseUsd: conversionUsd + editUsd,
|
|
12
|
+
possibleImageActionUsd: { ...REVIEW_IMAGE_ACTION_USD },
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export const reviewEditCost = (quote) => ({
|
|
16
|
+
currency: 'USD',
|
|
17
|
+
conversionUsd: quote.conversionUsd,
|
|
18
|
+
editUsd: quote.editUsd,
|
|
19
|
+
baseUsd: quote.baseUsd,
|
|
20
|
+
possibleImageActionUsd: { ...quote.possibleImageActionUsd },
|
|
21
|
+
});
|
|
22
|
+
export const usd = (value) => `$${value.toFixed(2)}`;
|
|
23
|
+
//# sourceMappingURL=review-pricing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-pricing.js","sourceRoot":"","sources":["../src/review-pricing.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC;AACvC,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC;AACpC,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAW,CAAC;AAEhF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,IAG/B,EAAmB,EAAE;IACpB,MAAM,aAAa,GAAG,qBAAqB,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC;IACtE,MAAM,OAAO,GAAG,eAAe,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;IACpD,OAAO;QACL,IAAI,EAAE,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,QAAQ;QACxD,aAAa;QACb,OAAO;QACP,OAAO,EAAE,aAAa,GAAG,OAAO;QAChC,sBAAsB,EAAE,EAAE,GAAG,uBAAuB,EAAE;KACvD,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAsB,EAAkB,EAAE,CAAC,CAAC;IACzE,QAAQ,EAAE,KAAK;IACf,aAAa,EAAE,KAAK,CAAC,aAAa;IAClC,OAAO,EAAE,KAAK,CAAC,OAAO;IACtB,OAAO,EAAE,KAAK,CAAC,OAAO;IACtB,sBAAsB,EAAE,EAAE,GAAG,KAAK,CAAC,sBAAsB,EAAE;CAC5D,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { TwelveUiBranchClient } from './branch-client.js';
|
|
2
|
+
import type { TwelveUiConversionClient } from './conversion-client.js';
|
|
3
|
+
import type { TwelveUiPrototypeLabelClient } from './prototype-label-client.js';
|
|
4
|
+
import { runPrototypePipeline } from './prototype-runner.js';
|
|
5
|
+
import type { ReviewPrototypeHolding } from './review-types.js';
|
|
6
|
+
export declare const REVIEW_PROTOTYPE_GAP_DRAFT_USD = 0.06;
|
|
7
|
+
export declare const REVIEW_PROTOTYPE_GAP_CONVERSION_USD = 0.45;
|
|
8
|
+
export declare const REVIEW_PROTOTYPE_GAP_BASE_USD: number;
|
|
9
|
+
export declare const REVIEW_PROTOTYPE_GAPS_DIRECTORY = "prototype-gaps";
|
|
10
|
+
export type ReviewPrototypeGapReceipt = {
|
|
11
|
+
version: 1;
|
|
12
|
+
holding: {
|
|
13
|
+
slug: string;
|
|
14
|
+
title: string;
|
|
15
|
+
};
|
|
16
|
+
create: {
|
|
17
|
+
runId: string;
|
|
18
|
+
slot: string;
|
|
19
|
+
sha256: string;
|
|
20
|
+
};
|
|
21
|
+
conversion: {
|
|
22
|
+
operationId: string;
|
|
23
|
+
model: 'standard';
|
|
24
|
+
output: 'html';
|
|
25
|
+
};
|
|
26
|
+
source: {
|
|
27
|
+
pageId: string;
|
|
28
|
+
path: string;
|
|
29
|
+
rewrittenIds: number;
|
|
30
|
+
};
|
|
31
|
+
prototypeManifestPath: string;
|
|
32
|
+
quotedBaseUsd: number;
|
|
33
|
+
};
|
|
34
|
+
type GapBranchClient = Pick<TwelveUiBranchClient, 'startCreateRun' | 'dispatchScreen' | 'getRun' | 'downloadScreen'>;
|
|
35
|
+
type GapConversionClient = Pick<TwelveUiConversionClient, 'createConversion' | 'waitForConversion' | 'downloadResult'>;
|
|
36
|
+
export type ReviewPrototypeGapRunner = (args: {
|
|
37
|
+
runRoot: string;
|
|
38
|
+
branchDir: string;
|
|
39
|
+
holding: ReviewPrototypeHolding;
|
|
40
|
+
}) => Promise<ReviewPrototypeGapReceipt>;
|
|
41
|
+
export declare const createReviewPrototypeGapRunner: (dependencies: {
|
|
42
|
+
branchClient: GapBranchClient;
|
|
43
|
+
conversionClient: GapConversionClient;
|
|
44
|
+
labelClient: TwelveUiPrototypeLabelClient;
|
|
45
|
+
prototypeRunner?: typeof runPrototypePipeline;
|
|
46
|
+
}) => ReviewPrototypeGapRunner;
|
|
47
|
+
export {};
|
|
48
|
+
//# sourceMappingURL=review-prototype-gap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-prototype-gap.d.ts","sourceRoot":"","sources":["../src/review-prototype-gap.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAgB,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE7E,OAAO,KAAK,EAAE,wBAAwB,EAAuB,MAAM,wBAAwB,CAAC;AAG5F,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,6BAA6B,CAAC;AAChF,OAAO,EAAoD,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE/G,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAEhE,eAAO,MAAM,8BAA8B,OAAO,CAAC;AACnD,eAAO,MAAM,mCAAmC,OAAO,CAAC;AACxD,eAAO,MAAM,6BAA6B,QAEzC,CAAC;AACF,eAAO,MAAM,+BAA+B,mBAAmB,CAAC;AAEhE,MAAM,MAAM,yBAAyB,GAAG;IACtC,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACxD,UAAU,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,UAAU,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACvE,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/D,qBAAqB,EAAE,MAAM,CAAC;IAC9B,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,KAAK,eAAe,GAAG,IAAI,CACzB,oBAAoB,EACpB,gBAAgB,GAAG,gBAAgB,GAAG,QAAQ,GAAG,gBAAgB,CAClE,CAAC;AACF,KAAK,mBAAmB,GAAG,IAAI,CAC7B,wBAAwB,EACxB,kBAAkB,GAAG,mBAAmB,GAAG,gBAAgB,CAC5D,CAAC;AA6DF,MAAM,MAAM,wBAAwB,GAAG,CAAC,IAAI,EAAE;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,sBAAsB,CAAC;CACjC,KAAK,OAAO,CAAC,yBAAyB,CAAC,CAAC;AAEzC,eAAO,MAAM,8BAA8B,GAAI,cAAc;IAC3D,YAAY,EAAE,eAAe,CAAC;IAC9B,gBAAgB,EAAE,mBAAmB,CAAC;IACtC,WAAW,EAAE,4BAA4B,CAAC;IAC1C,eAAe,CAAC,EAAE,OAAO,oBAAoB,CAAC;CAC/C,KAAG,wBA6IH,CAAC"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
+
import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { BRANCH_COMPLETION_FILENAME, BRANCH_PLAN_FILENAME, readBranchCompletion } from './branch-run-record.js';
|
|
5
|
+
import { waitForHostedDraftRun } from './hosted-draft-run.js';
|
|
6
|
+
import { appendPrototypeGapSource } from './prototype-gap-source.js';
|
|
7
|
+
import { PROTOTYPE_DIRECTORY, PROTOTYPE_MANIFEST_FILENAME, runPrototypePipeline } from './prototype-runner.js';
|
|
8
|
+
import { preparePrototypeSourceOverlay } from './prototype-source.js';
|
|
9
|
+
export const REVIEW_PROTOTYPE_GAP_DRAFT_USD = 0.06;
|
|
10
|
+
export const REVIEW_PROTOTYPE_GAP_CONVERSION_USD = 0.45;
|
|
11
|
+
export const REVIEW_PROTOTYPE_GAP_BASE_USD = (REVIEW_PROTOTYPE_GAP_DRAFT_USD + REVIEW_PROTOTYPE_GAP_CONVERSION_USD);
|
|
12
|
+
export const REVIEW_PROTOTYPE_GAPS_DIRECTORY = 'prototype-gaps';
|
|
13
|
+
const sha256 = (bytes) => (createHash('sha256').update(bytes).digest('hex'));
|
|
14
|
+
const inside = (root, target) => {
|
|
15
|
+
const relative = path.relative(path.resolve(root), path.resolve(target));
|
|
16
|
+
return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
|
|
17
|
+
};
|
|
18
|
+
const imageMediaType = (file) => {
|
|
19
|
+
const extension = path.extname(file).toLowerCase();
|
|
20
|
+
if (extension === '.jpg' || extension === '.jpeg')
|
|
21
|
+
return 'image/jpeg';
|
|
22
|
+
if (extension === '.webp')
|
|
23
|
+
return 'image/webp';
|
|
24
|
+
return 'image/png';
|
|
25
|
+
};
|
|
26
|
+
const settledConversion = async (operation, client) => (operation.status === 'succeeded'
|
|
27
|
+
? operation
|
|
28
|
+
: client.waitForConversion(operation.id, {
|
|
29
|
+
expiresAt: operation.expires_at,
|
|
30
|
+
timeoutMs: 20 * 60_000,
|
|
31
|
+
}));
|
|
32
|
+
const writeStableFile = async (file, bytes) => {
|
|
33
|
+
const buffer = typeof bytes === 'string' ? Buffer.from(bytes) : bytes;
|
|
34
|
+
const existing = await readFile(file).catch(() => null);
|
|
35
|
+
if (existing) {
|
|
36
|
+
if (sha256(existing) !== sha256(buffer))
|
|
37
|
+
throw new Error(`Refusing to replace changed gap artifact ${file}`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
await mkdir(path.dirname(file), { recursive: true });
|
|
41
|
+
const temporary = path.join(path.dirname(file), `.${path.basename(file)}.${randomUUID()}.tmp`);
|
|
42
|
+
try {
|
|
43
|
+
await writeFile(temporary, buffer, { flag: 'wx', mode: 0o600 });
|
|
44
|
+
await rename(temporary, file);
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
await rm(temporary, { force: true });
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
const validAspect = (value) => (value === 'landscape' || value === 'portrait' || value === 'square');
|
|
51
|
+
const availableGapSlot = (identity, used) => {
|
|
52
|
+
const seed = Number.parseInt(identity.slice(0, 8), 16);
|
|
53
|
+
for (let offset = 0; offset < 26 * 26; offset += 1) {
|
|
54
|
+
const value = (seed + offset) % (26 * 26);
|
|
55
|
+
const slot = String.fromCharCode(97 + Math.floor(value / 26), 97 + (value % 26));
|
|
56
|
+
if (!used.has(slot))
|
|
57
|
+
return slot;
|
|
58
|
+
}
|
|
59
|
+
throw new Error('The prototype plan has no free create slot for a gap');
|
|
60
|
+
};
|
|
61
|
+
export const createReviewPrototypeGapRunner = (dependencies) => async (args) => {
|
|
62
|
+
const runRoot = path.resolve(args.runRoot);
|
|
63
|
+
const branchDir = path.resolve(args.branchDir);
|
|
64
|
+
if (!inside(runRoot, branchDir))
|
|
65
|
+
throw new Error('Prototype branch is outside the reviewed run');
|
|
66
|
+
if (!/^holding-[a-z0-9-]+$/u.test(args.holding.slug))
|
|
67
|
+
throw new Error('Prototype holding id is invalid');
|
|
68
|
+
const expectedHoldingPath = path.join(branchDir, PROTOTYPE_DIRECTORY, `${args.holding.slug}.html`);
|
|
69
|
+
if (path.resolve(args.holding.path) !== expectedHoldingPath) {
|
|
70
|
+
throw new Error('Prototype holding path does not match its manifest id');
|
|
71
|
+
}
|
|
72
|
+
const manifestPath = path.join(branchDir, PROTOTYPE_DIRECTORY, PROTOTYPE_MANIFEST_FILENAME);
|
|
73
|
+
const manifest = JSON.parse(await readFile(manifestPath, 'utf8'));
|
|
74
|
+
const holdings = Array.isArray(manifest.holdings) ? manifest.holdings : [];
|
|
75
|
+
const current = holdings.find((entry) => (Array.isArray(entry) && entry[0] === args.holding.slug && entry[1] === args.holding.title));
|
|
76
|
+
if (!current)
|
|
77
|
+
throw new Error('This prototype holding page no longer exists');
|
|
78
|
+
const completion = await readBranchCompletion(path.join(branchDir, BRANCH_COMPLETION_FILENAME));
|
|
79
|
+
if (!completion?.winner?.path) {
|
|
80
|
+
throw new Error('This branch has no stored winner image for a gap draft');
|
|
81
|
+
}
|
|
82
|
+
let winnerPath = completion.winner.path;
|
|
83
|
+
let storedWinner = inside(runRoot, winnerPath)
|
|
84
|
+
? await readFile(winnerPath).catch(() => null)
|
|
85
|
+
: null;
|
|
86
|
+
if (!storedWinner) {
|
|
87
|
+
winnerPath = path.join(branchDir, 'screens', path.basename(completion.winner.path));
|
|
88
|
+
storedWinner = inside(runRoot, winnerPath)
|
|
89
|
+
? await readFile(winnerPath).catch(() => null)
|
|
90
|
+
: null;
|
|
91
|
+
}
|
|
92
|
+
if (!storedWinner)
|
|
93
|
+
throw new Error('This branch has no stored winner image for a gap draft');
|
|
94
|
+
const winnerBytes = new Uint8Array(storedWinner);
|
|
95
|
+
if (sha256(winnerBytes) !== completion.winner.sha256) {
|
|
96
|
+
throw new Error('The stored winner image does not match its branch receipt');
|
|
97
|
+
}
|
|
98
|
+
const sourceDir = await preparePrototypeSourceOverlay(branchDir);
|
|
99
|
+
const plan = JSON.parse(await readFile(path.join(sourceDir, BRANCH_PLAN_FILENAME), 'utf8'));
|
|
100
|
+
const identity = sha256(JSON.stringify({
|
|
101
|
+
revision: 'review-prototype-gap-v1',
|
|
102
|
+
runId: completion.runId,
|
|
103
|
+
holding: current,
|
|
104
|
+
winnerSha256: completion.winner.sha256,
|
|
105
|
+
}));
|
|
106
|
+
const purpose = `Complete the ${args.holding.title} destination from the prototype navigation.`;
|
|
107
|
+
const existingPage = plan.pages?.find((page) => (page.title === args.holding.title && 'purpose' in page && page.purpose === purpose));
|
|
108
|
+
const existingSlot = existingPage
|
|
109
|
+
? plan.screens?.find((screen) => screen.pageIndex === existingPage.index)?.slot
|
|
110
|
+
: undefined;
|
|
111
|
+
const slot = existingSlot ?? availableGapSlot(identity, new Set(plan.screens?.map((screen) => screen.slot) ?? []));
|
|
112
|
+
const concept = [
|
|
113
|
+
completion.concept,
|
|
114
|
+
typeof plan.sitePurpose === 'string' ? plan.sitePurpose : '',
|
|
115
|
+
`Create the missing ${args.holding.title} screen. Match the supplied approved design's visual system and product shell.`,
|
|
116
|
+
].filter(Boolean).join('\n\n').slice(0, 1_200);
|
|
117
|
+
const direction = `Design the ${args.holding.title} screen in the same product and shell.`.slice(0, 120);
|
|
118
|
+
const claimed = await dependencies.branchClient.startCreateRun({
|
|
119
|
+
concept,
|
|
120
|
+
...(validAspect(plan.aspect) ? { aspect: plan.aspect } : {}),
|
|
121
|
+
mode: 'preserve-structure',
|
|
122
|
+
candidates: [{ slot, direction, useReferenceImage: true }],
|
|
123
|
+
referenceImage: {
|
|
124
|
+
data: Buffer.from(winnerBytes).toString('base64'),
|
|
125
|
+
mediaType: imageMediaType(winnerPath),
|
|
126
|
+
sha256: completion.winner.sha256,
|
|
127
|
+
},
|
|
128
|
+
}, `review-prototype-gap:v1:${identity}`);
|
|
129
|
+
let generated = claimed;
|
|
130
|
+
if (generated.candidates.find((candidate) => candidate.slot === slot)?.status === 'pending') {
|
|
131
|
+
generated = await dependencies.branchClient.dispatchScreen(generated.id, slot);
|
|
132
|
+
}
|
|
133
|
+
generated = await waitForHostedDraftRun({ client: dependencies.branchClient, run: generated });
|
|
134
|
+
const candidate = generated.candidates.find((entry) => entry.slot === slot);
|
|
135
|
+
if (candidate?.status !== 'succeeded') {
|
|
136
|
+
throw new Error(candidate?.error?.message ?? 'The gap draft did not succeed');
|
|
137
|
+
}
|
|
138
|
+
if (!Number.isFinite(candidate.width) || !Number.isFinite(candidate.height)) {
|
|
139
|
+
throw new Error('The gap draft has no usable dimensions');
|
|
140
|
+
}
|
|
141
|
+
const image = await dependencies.branchClient.downloadScreen(generated.id, slot);
|
|
142
|
+
if (sha256(image.bytes) !== image.sha256)
|
|
143
|
+
throw new Error('The gap draft failed its download digest check');
|
|
144
|
+
const artifactDir = path.join(branchDir, REVIEW_PROTOTYPE_GAPS_DIRECTORY, args.holding.slug, identity.slice(0, 16));
|
|
145
|
+
const imagePath = path.join(artifactDir, 'draft.png');
|
|
146
|
+
await writeStableFile(imagePath, image.bytes);
|
|
147
|
+
const created = await dependencies.conversionClient.createConversion({
|
|
148
|
+
bytes: image.bytes,
|
|
149
|
+
mediaType: 'image/png',
|
|
150
|
+
filename: `${args.holding.slug}.png`,
|
|
151
|
+
output: 'html',
|
|
152
|
+
model: 'standard',
|
|
153
|
+
idempotencyKey: `review-prototype-gap-convert:v1:${identity}`,
|
|
154
|
+
waitSeconds: 20,
|
|
155
|
+
});
|
|
156
|
+
const conversion = await settledConversion(created, dependencies.conversionClient);
|
|
157
|
+
const downloaded = await dependencies.conversionClient.downloadResult(conversion.id, 'html');
|
|
158
|
+
if (!downloaded.mediaType.toLowerCase().startsWith('text/html')) {
|
|
159
|
+
throw new Error(`Gap conversion returned ${downloaded.mediaType}, not HTML`);
|
|
160
|
+
}
|
|
161
|
+
const convertedPath = path.join(artifactDir, 'converted.html');
|
|
162
|
+
await writeStableFile(convertedPath, downloaded.bytes);
|
|
163
|
+
const appended = await appendPrototypeGapSource({
|
|
164
|
+
sourceDir,
|
|
165
|
+
slot,
|
|
166
|
+
title: args.holding.title,
|
|
167
|
+
purpose,
|
|
168
|
+
html: Buffer.from(downloaded.bytes).toString('utf8'),
|
|
169
|
+
width: candidate.width,
|
|
170
|
+
height: candidate.height,
|
|
171
|
+
});
|
|
172
|
+
const prototype = await (dependencies.prototypeRunner ?? runPrototypePipeline)({
|
|
173
|
+
branchDir,
|
|
174
|
+
labelClient: dependencies.labelClient,
|
|
175
|
+
});
|
|
176
|
+
const receipt = {
|
|
177
|
+
version: 1,
|
|
178
|
+
holding: { slug: args.holding.slug, title: args.holding.title },
|
|
179
|
+
create: { runId: generated.id, slot, sha256: image.sha256 },
|
|
180
|
+
conversion: { operationId: conversion.id, model: 'standard', output: 'html' },
|
|
181
|
+
source: {
|
|
182
|
+
pageId: appended.pageId,
|
|
183
|
+
path: path.relative(branchDir, appended.pagePath).split(path.sep).join('/'),
|
|
184
|
+
rewrittenIds: appended.rewrittenIds,
|
|
185
|
+
},
|
|
186
|
+
prototypeManifestPath: path.relative(branchDir, prototype.manifestPath).split(path.sep).join('/'),
|
|
187
|
+
quotedBaseUsd: REVIEW_PROTOTYPE_GAP_BASE_USD,
|
|
188
|
+
};
|
|
189
|
+
await writeStableFile(path.join(artifactDir, 'receipt.json'), `${JSON.stringify(receipt, null, 2)}\n`);
|
|
190
|
+
return receipt;
|
|
191
|
+
};
|
|
192
|
+
//# sourceMappingURL=review-prototype-gap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-prototype-gap.js","sourceRoot":"","sources":["../src/review-prototype-gap.ts"],"names":[],"mappings":"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"}
|