@12ui/design 0.2.28 → 0.2.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +69 -0
  2. package/SKILL.md +1 -1
  3. package/dist/cli-arguments.d.ts.map +1 -1
  4. package/dist/cli-arguments.js +1 -0
  5. package/dist/cli-arguments.js.map +1 -1
  6. package/dist/cli-capabilities.d.ts +6 -0
  7. package/dist/cli-capabilities.d.ts.map +1 -1
  8. package/dist/cli-capabilities.js +10 -0
  9. package/dist/cli-capabilities.js.map +1 -1
  10. package/dist/cli-help/design.d.ts +10 -0
  11. package/dist/cli-help/design.d.ts.map +1 -1
  12. package/dist/cli-help/design.js +21 -0
  13. package/dist/cli-help/design.js.map +1 -1
  14. package/dist/cli-help/index.d.ts +10 -0
  15. package/dist/cli-help/index.d.ts.map +1 -1
  16. package/dist/cli-review-command.d.ts +8 -0
  17. package/dist/cli-review-command.d.ts.map +1 -0
  18. package/dist/cli-review-command.js +71 -0
  19. package/dist/cli-review-command.js.map +1 -0
  20. package/dist/cli-run.d.ts.map +1 -1
  21. package/dist/cli-run.js +8 -0
  22. package/dist/cli-run.js.map +1 -1
  23. package/dist/cli-usage.d.ts.map +1 -1
  24. package/dist/cli-usage.js +2 -0
  25. package/dist/cli-usage.js.map +1 -1
  26. package/dist/conversion-client.d.ts.map +1 -1
  27. package/dist/conversion-client.js +8 -1
  28. package/dist/conversion-client.js.map +1 -1
  29. package/dist/next-wait-lease.d.ts +2 -1
  30. package/dist/next-wait-lease.d.ts.map +1 -1
  31. package/dist/next-wait-lease.js +73 -22
  32. package/dist/next-wait-lease.js.map +1 -1
  33. package/dist/next-wait-process.d.ts +17 -0
  34. package/dist/next-wait-process.d.ts.map +1 -0
  35. package/dist/next-wait-process.js +40 -0
  36. package/dist/next-wait-process.js.map +1 -0
  37. package/dist/review-discovery.d.ts +10 -0
  38. package/dist/review-discovery.d.ts.map +1 -0
  39. package/dist/review-discovery.js +381 -0
  40. package/dist/review-discovery.js.map +1 -0
  41. package/dist/review-edit-html.d.ts +6 -0
  42. package/dist/review-edit-html.d.ts.map +1 -0
  43. package/dist/review-edit-html.js +11 -0
  44. package/dist/review-edit-html.js.map +1 -0
  45. package/dist/review-edit-source.d.ts +22 -0
  46. package/dist/review-edit-source.d.ts.map +1 -0
  47. package/dist/review-edit-source.js +103 -0
  48. package/dist/review-edit-source.js.map +1 -0
  49. package/dist/review-edit.d.ts +15 -0
  50. package/dist/review-edit.d.ts.map +1 -0
  51. package/dist/review-edit.js +192 -0
  52. package/dist/review-edit.js.map +1 -0
  53. package/dist/review-layerdoc-diff.d.ts +7 -0
  54. package/dist/review-layerdoc-diff.d.ts.map +1 -0
  55. package/dist/review-layerdoc-diff.js +92 -0
  56. package/dist/review-layerdoc-diff.js.map +1 -0
  57. package/dist/review-page-assets.d.ts +3 -0
  58. package/dist/review-page-assets.d.ts.map +1 -0
  59. package/dist/review-page-assets.js +43 -0
  60. package/dist/review-page-assets.js.map +1 -0
  61. package/dist/review-page.d.ts +3 -0
  62. package/dist/review-page.d.ts.map +1 -0
  63. package/dist/review-page.js +237 -0
  64. package/dist/review-page.js.map +1 -0
  65. package/dist/review-pricing.d.ts +14 -0
  66. package/dist/review-pricing.d.ts.map +1 -0
  67. package/dist/review-pricing.js +23 -0
  68. package/dist/review-pricing.js.map +1 -0
  69. package/dist/review-server.d.ts +15 -0
  70. package/dist/review-server.d.ts.map +1 -0
  71. package/dist/review-server.js +204 -0
  72. package/dist/review-server.js.map +1 -0
  73. package/dist/review-store.d.ts +11 -0
  74. package/dist/review-store.d.ts.map +1 -0
  75. package/dist/review-store.js +96 -0
  76. package/dist/review-store.js.map +1 -0
  77. package/dist/review-types.d.ts +128 -0
  78. package/dist/review-types.d.ts.map +1 -0
  79. package/dist/review-types.js +2 -0
  80. package/dist/review-types.js.map +1 -0
  81. package/dist/run-journal-commands.d.ts.map +1 -1
  82. package/dist/run-journal-commands.js +6 -0
  83. package/dist/run-journal-commands.js.map +1 -1
  84. package/open-design.json +2 -2
  85. package/package.json +1 -1
@@ -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 { stackedReviewHtml } from './review-edit-html.js';
5
+ import { resolveReviewEditSource, } from './review-edit-source.js';
6
+ import { changedLayerDocRegions } from './review-layerdoc-diff.js';
7
+ import { reviewEditCost } from './review-pricing.js';
8
+ import { updateReviewRecord } from './review-store.js';
9
+ export const REVIEW_EDITS_DIRECTORY = 'review/edits';
10
+ const sha256 = (bytes) => (createHash('sha256').update(bytes).digest('hex'));
11
+ const relativeToRun = (root, file) => {
12
+ const relative = path.relative(path.resolve(root), path.resolve(file));
13
+ if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) {
14
+ throw new Error(`Review edit artifact is outside its run directory: ${file}`);
15
+ }
16
+ return relative.split(path.sep).join('/');
17
+ };
18
+ const safeItemName = (itemId) => (itemId.replace(/[^a-z0-9._-]/giu, '-').slice(0, 80) || 'item');
19
+ const writeStableFile = async (file, bytes) => {
20
+ await mkdir(path.dirname(file), { recursive: true });
21
+ const existing = await readFile(file).catch(() => null);
22
+ if (existing) {
23
+ if (sha256(existing) !== sha256(bytes)) {
24
+ throw new Error(`Refusing to replace changed review edit artifact ${file}`);
25
+ }
26
+ return;
27
+ }
28
+ const temporary = path.join(path.dirname(file), `.${randomUUID()}.review-edit.tmp`);
29
+ try {
30
+ await writeFile(temporary, bytes, { flag: 'wx', mode: 0o600 });
31
+ await rename(temporary, file);
32
+ }
33
+ finally {
34
+ await rm(temporary, { force: true });
35
+ }
36
+ };
37
+ const settled = async (args) => (args.operation.status === 'succeeded'
38
+ ? args.operation
39
+ : args.wait(args.operation.id, {
40
+ expiresAt: args.operation.expires_at,
41
+ timeoutMs: 20 * 60_000,
42
+ }));
43
+ const renderLayerDoc = async (args) => {
44
+ const created = await args.client.createConversion({
45
+ layerdoc: args.layerdoc,
46
+ filename: args.filename,
47
+ output: 'html_fixed',
48
+ idempotencyKey: args.idempotencyKey,
49
+ waitSeconds: 20,
50
+ });
51
+ const operation = await settled({
52
+ operation: created,
53
+ wait: (id, options) => args.client.waitForConversion(id, options),
54
+ });
55
+ const downloaded = await args.client.downloadResult(operation.id, 'html_fixed');
56
+ return { operationId: operation.id, html: downloaded.bytes };
57
+ };
58
+ const editDocument = async (args) => {
59
+ const suffix = `v${args.ordinal + 1}`;
60
+ const renderedOriginal = await renderLayerDoc({
61
+ client: args.client,
62
+ layerdoc: args.document.bytes,
63
+ filename: args.document.filename,
64
+ idempotencyKey: `review-original-v1-${sha256(args.document.bytes).slice(0, 64)}`,
65
+ });
66
+ const original = path.join(args.directory, `${args.stem}-${suffix}-original.html`);
67
+ await writeStableFile(original, renderedOriginal.html);
68
+ const requestDigest = sha256(Buffer.concat([
69
+ Buffer.from(args.document.bytes),
70
+ Buffer.from('\n'),
71
+ Buffer.from(args.prompt),
72
+ ]));
73
+ const created = await args.client.createEdit({
74
+ layerdoc: args.document.bytes,
75
+ filename: args.document.filename,
76
+ output: 'layerdoc',
77
+ prompt: args.prompt,
78
+ idempotencyKey: `review-edit-v1-${requestDigest}`,
79
+ waitSeconds: 20,
80
+ });
81
+ const edited = await settled({
82
+ operation: created,
83
+ wait: (id, options) => args.client.waitForEdit(id, options),
84
+ });
85
+ const editedLayerDoc = await args.client.downloadEditResult(edited.id, 'layerdoc');
86
+ const editedLayerDocPath = path.join(args.directory, `${args.stem}-${suffix}.layerdoc.json`);
87
+ await writeStableFile(editedLayerDocPath, editedLayerDoc.bytes);
88
+ const rendered = await renderLayerDoc({
89
+ client: args.client,
90
+ layerdoc: editedLayerDoc.bytes,
91
+ filename: path.basename(editedLayerDocPath),
92
+ idempotencyKey: `review-render-v1-${sha256(editedLayerDoc.bytes)}`,
93
+ });
94
+ const editedHtmlPath = path.join(args.directory, `${args.stem}-${suffix}.html`);
95
+ await writeStableFile(editedHtmlPath, rendered.html);
96
+ return {
97
+ editOperationId: edited.id,
98
+ renderOperationId: rendered.operationId,
99
+ originalRenderOperationId: renderedOriginal.operationId,
100
+ original,
101
+ edited: editedHtmlPath,
102
+ layerdoc: editedLayerDocPath,
103
+ changedRegions: changedLayerDocRegions({
104
+ before: args.document.bytes,
105
+ after: editedLayerDoc.bytes,
106
+ viewport: args.document.label,
107
+ }),
108
+ };
109
+ };
110
+ export const createReviewEditRunner = (dependencies) => (async (args) => {
111
+ const runRoot = path.resolve(args.runRoot);
112
+ const prompt = args.prompt.trim();
113
+ if (!prompt)
114
+ throw new Error('Write an edit instruction first');
115
+ if (new TextEncoder().encode(prompt).byteLength > 8 * 1024) {
116
+ throw new Error('Edit instruction must be 8 KiB or smaller');
117
+ }
118
+ const source = await resolveReviewEditSource({
119
+ runRoot,
120
+ itemId: args.itemId,
121
+ source: args.source,
122
+ conversionClient: dependencies.conversionClient,
123
+ packageClient: dependencies.packageClient,
124
+ });
125
+ const requestDigest = sha256(Buffer.concat([
126
+ ...source.documents.flatMap((document) => [Buffer.from(document.bytes), Buffer.from('\n')]),
127
+ Buffer.from(prompt),
128
+ ]));
129
+ const editId = requestDigest.slice(0, 16);
130
+ const directory = path.join(runRoot, REVIEW_EDITS_DIRECTORY);
131
+ const stem = `${safeItemName(args.itemId)}-${editId}`;
132
+ const documents = [];
133
+ for (let index = 0; index < source.documents.length; index += 1) {
134
+ documents.push(await editDocument({
135
+ client: dependencies.conversionClient,
136
+ document: source.documents[index],
137
+ prompt,
138
+ directory,
139
+ stem,
140
+ ordinal: index,
141
+ }));
142
+ }
143
+ let original = documents[0].original;
144
+ let editedHtmlPath = documents[0].edited;
145
+ if (documents.length > 1) {
146
+ original = path.join(directory, `${stem}-original.html`);
147
+ editedHtmlPath = path.join(directory, `${stem}.html`);
148
+ await writeStableFile(original, stackedReviewHtml(documents.map((document, index) => ({
149
+ file: path.basename(document.original),
150
+ label: `${source.documents[index].label}, original`,
151
+ height: source.documents[index].height,
152
+ }))));
153
+ await writeStableFile(editedHtmlPath, stackedReviewHtml(documents.map((document, index) => ({
154
+ file: path.basename(document.edited),
155
+ label: `${source.documents[index].label}, edited`,
156
+ height: source.documents[index].height,
157
+ }))));
158
+ }
159
+ const result = {
160
+ id: editId,
161
+ prompt,
162
+ createdAt: new Date().toISOString(),
163
+ editOperationId: documents[0].editOperationId,
164
+ renderOperationId: documents[0].renderOperationId,
165
+ editOperationIds: documents.map((document) => document.editOperationId),
166
+ renderOperationIds: documents.map((document) => document.renderOperationId),
167
+ originalRenderOperationIds: documents.map((document) => document.originalRenderOperationId),
168
+ ...(source.conversionOperationId
169
+ ? { conversionOperationId: source.conversionOperationId }
170
+ : {}),
171
+ original: relativeToRun(runRoot, original),
172
+ layerdoc: relativeToRun(runRoot, documents[0].layerdoc),
173
+ layerdocs: documents.map((document) => relativeToRun(runRoot, document.layerdoc)),
174
+ html: relativeToRun(runRoot, editedHtmlPath),
175
+ resultPath: relativeToRun(runRoot, editedHtmlPath),
176
+ cost: reviewEditCost(source.quote),
177
+ changedRegions: documents.flatMap((document) => document.changedRegions ?? []),
178
+ };
179
+ await updateReviewRecord(runRoot, (record) => {
180
+ const item = record.items[args.itemId] ?? {};
181
+ const edits = item.edits ?? [];
182
+ const existing = edits.findIndex((entry) => entry.id === result.id);
183
+ record.items[args.itemId] = {
184
+ ...item,
185
+ edits: existing < 0
186
+ ? [...edits, result]
187
+ : edits.map((entry, index) => index === existing ? result : entry),
188
+ };
189
+ });
190
+ return result;
191
+ });
192
+ //# sourceMappingURL=review-edit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-edit.js","sourceRoot":"","sources":["../src/review-edit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { ReviewEditRegion } from './review-types.js';
2
+ export declare const changedLayerDocRegions: (args: {
3
+ before: Uint8Array;
4
+ after: Uint8Array;
5
+ viewport: string;
6
+ }) => ReviewEditRegion[];
7
+ //# sourceMappingURL=review-layerdoc-diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-layerdoc-diff.d.ts","sourceRoot":"","sources":["../src/review-layerdoc-diff.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAyE1D,eAAO,MAAM,sBAAsB,GAAI,MAAM;IAC3C,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,UAAU,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB,KAAG,gBAAgB,EA8BnB,CAAC"}
@@ -0,0 +1,92 @@
1
+ const MEANINGFUL_FIELDS = [
2
+ 'kind',
3
+ 'content',
4
+ 'box',
5
+ 'hidden',
6
+ 'fontSizePx',
7
+ 'fittedFontSizePx',
8
+ 'fontWeight',
9
+ 'googleFontFamily',
10
+ 'color',
11
+ 'align',
12
+ 'opacity',
13
+ 'rotationDeg',
14
+ 'textRotationDeg',
15
+ 'textSlantDeg',
16
+ 'style',
17
+ ];
18
+ const isRecord = (value) => (Boolean(value) && typeof value === 'object' && !Array.isArray(value));
19
+ const flatten = (value) => {
20
+ if (!isRecord(value) || !Array.isArray(value.layers))
21
+ return [];
22
+ const output = [];
23
+ const visit = (nodes) => {
24
+ for (const node of nodes) {
25
+ if (!isRecord(node))
26
+ continue;
27
+ if (node.kind === 'group' && Array.isArray(node.children))
28
+ visit(node.children);
29
+ else
30
+ output.push(node);
31
+ }
32
+ };
33
+ visit(value.layers);
34
+ return output;
35
+ };
36
+ const identity = (layer, index) => {
37
+ if (typeof layer.extractionIndex === 'number')
38
+ return `extraction:${layer.extractionIndex}`;
39
+ if (typeof layer.z === 'number')
40
+ return `z:${layer.z}`;
41
+ return `ordinal:${index}`;
42
+ };
43
+ const same = (left, right) => (JSON.stringify(left) === JSON.stringify(right));
44
+ const boxOf = (layer) => {
45
+ const box = layer?.box;
46
+ return Array.isArray(box)
47
+ && box.length === 4
48
+ && box.every((value) => typeof value === 'number' && Number.isFinite(value))
49
+ ? box
50
+ : undefined;
51
+ };
52
+ const concise = (value) => {
53
+ if (typeof value !== 'string')
54
+ return undefined;
55
+ const compact = value.replace(/\s+/gu, ' ').trim();
56
+ if (!compact)
57
+ return undefined;
58
+ return compact.length <= 120 ? compact : `${compact.slice(0, 119)}…`;
59
+ };
60
+ export const changedLayerDocRegions = (args) => {
61
+ const decode = (bytes) => JSON.parse(new TextDecoder().decode(bytes));
62
+ const beforeLayers = flatten(decode(args.before));
63
+ const afterLayers = flatten(decode(args.after));
64
+ const beforeById = new Map(beforeLayers.map((layer, index) => [identity(layer, index), layer]));
65
+ const afterById = new Map(afterLayers.map((layer, index) => [identity(layer, index), layer]));
66
+ const ids = [...new Set([...beforeById.keys(), ...afterById.keys()])];
67
+ const regions = [];
68
+ for (const id of ids) {
69
+ const before = beforeById.get(id);
70
+ const after = afterById.get(id);
71
+ const fields = before && after
72
+ ? MEANINGFUL_FIELDS.filter((field) => !same(before[field], after[field]))
73
+ : [before ? 'removed' : 'added'];
74
+ if (fields.length === 0)
75
+ continue;
76
+ const layer = after ?? before;
77
+ const kind = typeof layer.kind === 'string' ? layer.kind : 'layer';
78
+ const ordinal = typeof layer.extractionIndex === 'number'
79
+ ? ` ${layer.extractionIndex}`
80
+ : typeof layer.z === 'number' ? ` ${layer.z}` : '';
81
+ regions.push({
82
+ viewport: args.viewport,
83
+ label: `${kind}${ordinal}`,
84
+ fields: [...fields],
85
+ ...(boxOf(after ?? before) ? { box: boxOf(after ?? before) } : {}),
86
+ ...(concise(before?.content) ? { before: concise(before?.content) } : {}),
87
+ ...(concise(after?.content) ? { after: concise(after?.content) } : {}),
88
+ });
89
+ }
90
+ return regions;
91
+ };
92
+ //# sourceMappingURL=review-layerdoc-diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-layerdoc-diff.js","sourceRoot":"","sources":["../src/review-layerdoc-diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare const REVIEW_PAGE_STYLES = "\n :root{color-scheme:light;--paper:#f7f3ed;--panel:#fffdf8;--ink:#143b33;--text:#202523;--muted:#6a706c;--line:#d9d4ca;--signal:#ef6b22;--soft:#e8eee9;--shadow:0 18px 50px rgba(31,45,39,.08)}\n *{box-sizing:border-box}html{background:var(--paper);scroll-behavior:smooth}body{margin:0;color:var(--text);font:15px/1.45 Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif;background:radial-gradient(circle at 8% 16%,rgba(239,107,34,.08),transparent 24rem),var(--paper)}\n button,textarea{font:inherit}button,a{touch-action:manipulation}.mast{padding:28px clamp(20px,4vw,64px);border-bottom:1px solid var(--line);background:rgba(247,243,237,.92);backdrop-filter:blur(12px);position:sticky;top:0;z-index:20;display:flex;align-items:flex-end;justify-content:space-between;gap:24px}.brand{display:flex;align-items:center;gap:14px}.brand-mark{width:42px;height:42px;border-radius:50%;background:var(--ink);color:var(--paper);display:grid;place-items:center;font:700 18px Georgia,serif}.mast h1,.run h2{font-family:Georgia,\"Times New Roman\",serif;color:var(--ink);margin:0;font-weight:500}.mast h1{font-size:clamp(28px,4vw,46px);line-height:1}.mast p{margin:6px 0 0;color:var(--muted)}.summary{display:flex;gap:8px;flex-wrap:wrap;justify-content:flex-end}.summary span,.count,.mark-chip,.edit-mode{border:1px solid var(--line);border-radius:999px;padding:7px 11px;background:var(--panel);white-space:nowrap}.mark-chip{text-transform:capitalize;color:var(--ink);border-color:#9fb5a8;background:var(--soft);font-size:12px}.shell{width:min(1760px,100%);margin:0 auto;padding:36px clamp(16px,3vw,48px) 100px}.empty{max-width:680px;margin:14vh auto;padding:48px;border:1px solid var(--line);border-radius:22px;background:var(--panel);box-shadow:var(--shadow)}.empty h2{font:500 38px/1.1 Georgia,serif;color:var(--ink);margin:0 0 12px}.run{margin-bottom:64px}.run-head{display:flex;justify-content:space-between;align-items:flex-start;gap:24px;padding:0 4px 20px;border-bottom:1px solid var(--ink)}.run h2{font-size:clamp(28px,3vw,42px);line-height:1.05;max-width:1080px}.run-head p{margin:8px 0 0;color:var(--muted);overflow-wrap:anywhere}.run-purpose{max-width:920px;color:var(--text)!important}.eyebrow{margin:0 0 7px!important;color:var(--signal)!important;letter-spacing:.08em;font-size:11px;font-weight:800}.site-nav{display:flex;gap:8px;overflow:auto;padding:14px 2px 0}.site-nav a{flex:0 0 auto;color:var(--ink);text-decoration:none;border:1px solid var(--line);border-radius:999px;padding:7px 12px;background:var(--panel);font-size:12px;font-weight:750}.group{padding-top:26px}.group>h3{font:500 22px Georgia,serif;color:var(--ink);margin:0 0 14px}.items{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,360px),1fr));gap:18px}.group--pages .items,.group--conversions .items{grid-template-columns:repeat(auto-fit,minmax(min(100%,580px),1fr))}.group--branch-pages .items{display:grid;grid-template-columns:1fr;gap:28px}.item{min-width:0;border:1px solid var(--line);border-radius:18px;background:rgba(255,253,248,.92);overflow:hidden;box-shadow:0 6px 24px rgba(31,45,39,.04);scroll-margin-top:130px}.item-head{min-height:80px;padding:18px 20px 14px;display:flex;justify-content:space-between;gap:14px;align-items:flex-start}.item-head h4{font:500 21px/1.15 Georgia,serif;color:var(--ink);margin:0}.item-head p{margin:6px 0 0;color:var(--muted);font-size:13px}.item-badges{display:flex;align-items:center;gap:7px;flex-wrap:wrap;justify-content:flex-end}.edit-mode{padding:5px 9px;font-size:11px;color:var(--muted)}.preview{position:relative;display:block;width:100%;background:#e7e4dc;border-block:1px solid var(--line)}.preview--image{aspect-ratio:16/10;overflow:hidden}.preview--image img{display:block;width:100%;height:100%;object-fit:contain}.preview--html{height:520px;min-height:280px;max-height:1100px;resize:vertical;overflow:auto}.preview--html iframe{display:block;width:100%;height:100%;border:0;background:white}.open{position:absolute;right:10px;top:10px;border:1px solid rgba(20,59,51,.28);border-radius:999px;padding:7px 12px;background:rgba(255,253,248,.93);color:var(--ink);text-decoration:none;font-size:12px;font-weight:700}.preview--layerdoc{min-height:250px;display:flex;flex-direction:column;align-items:center;justify-content:center;color:var(--muted);gap:8px}.preview--layerdoc strong{font:500 24px Georgia,serif;color:var(--ink)}.layerdoc-mark{font:500 38px Georgia,serif;color:var(--signal)}.published-page>p{padding:12px 16px;margin:0!important;background:#f3f0e9}.screen-sequence{padding:18px 0;border-block:1px solid var(--line);background:#f0eee8}.screen-sequence>p{padding:0 20px}.sequence-track{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(min(82vw,420px),1fr);gap:14px;overflow-x:auto;padding:0 20px 8px;scroll-snap-type:x proximity}.screen{margin:0;border:1px solid var(--line);border-radius:13px;overflow:hidden;background:var(--panel);scroll-snap-align:start}.screen .preview{border-top:0}.screen figcaption{padding:13px 15px 15px}.screen h5{font:500 17px/1.2 Georgia,serif;margin:0;color:var(--ink)}.screen figcaption p{font-size:12px;color:var(--muted);margin:7px 0 0}.comparison{display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--line);border-block:1px solid var(--line)}.comparison section{background:var(--panel);min-width:0}.comparison .eyebrow{padding:10px 14px;margin:0!important}.comparison .preview{border-bottom:0}.edit-receipt{padding:10px 18px;margin:0;color:var(--muted);font-size:12px;border-bottom:1px solid var(--line)}.diff-strip{display:flex;gap:10px;overflow-x:auto;padding:12px 18px;border-bottom:1px solid var(--line);background:#fff8ef}.diff-region{flex:0 0 min(340px,82vw);border-left:3px solid var(--signal);padding:8px 10px;background:var(--panel)}.diff-region strong{display:block;color:var(--ink);font-size:12px}.diff-region span{display:block;color:var(--muted);font-size:11px;margin-top:3px}.diff-region del,.diff-region ins{display:block;font-size:12px;text-decoration:none;margin-top:5px}.diff-region del{color:#8f3a2f}.diff-region ins{color:#1f6955}.controls{display:grid;grid-template-columns:minmax(0,1fr);gap:0}.feedback,.edit{padding:18px 20px}.edit{border-top:1px solid var(--line);background:#f3f4ef}.edit--disabled p,.edit-note{margin:0;color:var(--muted)}label{display:grid;gap:7px;color:var(--ink);font-weight:700;font-size:13px}textarea{width:100%;min-height:82px;resize:vertical;border:1px solid #bbb9b1;border-radius:10px;padding:11px 12px;background:#fff;color:var(--text);outline:none}textarea:focus{border-color:var(--ink);box-shadow:0 0 0 3px rgba(20,59,51,.12)}.mark-row,.save-row{display:flex;align-items:center;gap:8px}.mark-row{margin-bottom:14px;flex-wrap:wrap}.mark-row button,.save,.apply{border:1px solid var(--ink);border-radius:999px;background:transparent;color:var(--ink);padding:8px 13px;font-weight:750;cursor:pointer}.mark-row button.active,.save,.apply{background:var(--ink);color:white}.mark-row .clear{border-color:transparent;color:var(--muted)}.save-row{margin-top:11px;min-height:36px}.save,.apply{border-radius:9px;padding:9px 18px}.apply{background:var(--signal);border-color:var(--signal)}button:disabled{cursor:wait;opacity:.55}.status{font-size:12px;color:var(--muted)}.cost{margin:10px 0 0;color:var(--muted);font-size:12px}.cost strong{color:var(--signal)}.history{border-top:1px solid var(--line);padding:12px 20px}.history summary{cursor:pointer;color:var(--ink);font-weight:750}.history ol{margin:10px 0 0;padding-left:22px}.history li{padding:5px 0;color:var(--muted);font-size:12px}.history a{color:var(--ink)}code{font:12px ui-monospace,SFMono-Regular,Menlo,monospace;background:#e9e5dc;padding:2px 5px;border-radius:4px}\n @media(max-width:760px){.mast{position:static;align-items:flex-start;flex-direction:column}.summary{justify-content:flex-start}.shell{padding-top:24px}.run-head{flex-direction:column}.comparison{grid-template-columns:1fr}.preview--html{height:400px}.item-head{min-height:0}.screen{flex-basis:86vw}}\n";
2
+ export declare const REVIEW_PAGE_SCRIPT = "\n const post = async (url, body) => {\n const response = await fetch(url, {method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify(body)});\n const payload = await response.json().catch(() => ({error:'The server returned no detail.'}));\n if (!response.ok) throw new Error(payload.error || 'The request failed.');\n return payload;\n };\n for (const form of document.querySelectorAll('[data-feedback]')) {\n const status = form.querySelector('.status');\n const save = async () => {\n status.textContent = 'Saving\u2026';\n try {\n await post('/api/feedback', {runId:form.dataset.run,itemId:form.dataset.item,note:form.elements.note.value,mark:form.dataset.mark || null});\n status.textContent = 'Saved';\n } catch (error) { status.textContent = error.message; }\n };\n form.addEventListener('submit', (event) => { event.preventDefault(); save(); });\n for (const button of form.querySelectorAll('[data-mark]')) button.addEventListener('click', () => {\n form.dataset.mark = button.dataset.mark;\n for (const peer of form.querySelectorAll('[data-mark]')) {\n const active = Boolean(peer.dataset.mark) && peer.dataset.mark === form.dataset.mark;\n peer.classList.toggle('active', active); peer.setAttribute('aria-pressed', String(active));\n }\n save();\n });\n }\n for (const form of document.querySelectorAll('[data-edit]')) form.addEventListener('submit', async (event) => {\n event.preventDefault();\n const button = form.querySelector('.apply'); const status = form.querySelector('.status');\n button.disabled = true; status.textContent = form.dataset.mode === 'convert-then-edit' ? 'Converting, then editing\u2026' : 'Applying\u2026';\n try {\n await post('/api/edit', {runId:form.dataset.run,itemId:form.dataset.item,prompt:form.elements.prompt.value});\n status.textContent = 'Applied'; window.location.reload();\n } catch (error) { status.textContent = error.message; button.disabled = false; }\n });\n";
3
+ //# sourceMappingURL=review-page-assets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-page-assets.d.ts","sourceRoot":"","sources":["../src/review-page-assets.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,g2PAK9B,CAAC;AAEF,eAAO,MAAM,kBAAkB,8gEAmC9B,CAAC"}
@@ -0,0 +1,43 @@
1
+ export const REVIEW_PAGE_STYLES = `
2
+ :root{color-scheme:light;--paper:#f7f3ed;--panel:#fffdf8;--ink:#143b33;--text:#202523;--muted:#6a706c;--line:#d9d4ca;--signal:#ef6b22;--soft:#e8eee9;--shadow:0 18px 50px rgba(31,45,39,.08)}
3
+ *{box-sizing:border-box}html{background:var(--paper);scroll-behavior:smooth}body{margin:0;color:var(--text);font:15px/1.45 Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;background:radial-gradient(circle at 8% 16%,rgba(239,107,34,.08),transparent 24rem),var(--paper)}
4
+ button,textarea{font:inherit}button,a{touch-action:manipulation}.mast{padding:28px clamp(20px,4vw,64px);border-bottom:1px solid var(--line);background:rgba(247,243,237,.92);backdrop-filter:blur(12px);position:sticky;top:0;z-index:20;display:flex;align-items:flex-end;justify-content:space-between;gap:24px}.brand{display:flex;align-items:center;gap:14px}.brand-mark{width:42px;height:42px;border-radius:50%;background:var(--ink);color:var(--paper);display:grid;place-items:center;font:700 18px Georgia,serif}.mast h1,.run h2{font-family:Georgia,"Times New Roman",serif;color:var(--ink);margin:0;font-weight:500}.mast h1{font-size:clamp(28px,4vw,46px);line-height:1}.mast p{margin:6px 0 0;color:var(--muted)}.summary{display:flex;gap:8px;flex-wrap:wrap;justify-content:flex-end}.summary span,.count,.mark-chip,.edit-mode{border:1px solid var(--line);border-radius:999px;padding:7px 11px;background:var(--panel);white-space:nowrap}.mark-chip{text-transform:capitalize;color:var(--ink);border-color:#9fb5a8;background:var(--soft);font-size:12px}.shell{width:min(1760px,100%);margin:0 auto;padding:36px clamp(16px,3vw,48px) 100px}.empty{max-width:680px;margin:14vh auto;padding:48px;border:1px solid var(--line);border-radius:22px;background:var(--panel);box-shadow:var(--shadow)}.empty h2{font:500 38px/1.1 Georgia,serif;color:var(--ink);margin:0 0 12px}.run{margin-bottom:64px}.run-head{display:flex;justify-content:space-between;align-items:flex-start;gap:24px;padding:0 4px 20px;border-bottom:1px solid var(--ink)}.run h2{font-size:clamp(28px,3vw,42px);line-height:1.05;max-width:1080px}.run-head p{margin:8px 0 0;color:var(--muted);overflow-wrap:anywhere}.run-purpose{max-width:920px;color:var(--text)!important}.eyebrow{margin:0 0 7px!important;color:var(--signal)!important;letter-spacing:.08em;font-size:11px;font-weight:800}.site-nav{display:flex;gap:8px;overflow:auto;padding:14px 2px 0}.site-nav a{flex:0 0 auto;color:var(--ink);text-decoration:none;border:1px solid var(--line);border-radius:999px;padding:7px 12px;background:var(--panel);font-size:12px;font-weight:750}.group{padding-top:26px}.group>h3{font:500 22px Georgia,serif;color:var(--ink);margin:0 0 14px}.items{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,360px),1fr));gap:18px}.group--pages .items,.group--conversions .items{grid-template-columns:repeat(auto-fit,minmax(min(100%,580px),1fr))}.group--branch-pages .items{display:grid;grid-template-columns:1fr;gap:28px}.item{min-width:0;border:1px solid var(--line);border-radius:18px;background:rgba(255,253,248,.92);overflow:hidden;box-shadow:0 6px 24px rgba(31,45,39,.04);scroll-margin-top:130px}.item-head{min-height:80px;padding:18px 20px 14px;display:flex;justify-content:space-between;gap:14px;align-items:flex-start}.item-head h4{font:500 21px/1.15 Georgia,serif;color:var(--ink);margin:0}.item-head p{margin:6px 0 0;color:var(--muted);font-size:13px}.item-badges{display:flex;align-items:center;gap:7px;flex-wrap:wrap;justify-content:flex-end}.edit-mode{padding:5px 9px;font-size:11px;color:var(--muted)}.preview{position:relative;display:block;width:100%;background:#e7e4dc;border-block:1px solid var(--line)}.preview--image{aspect-ratio:16/10;overflow:hidden}.preview--image img{display:block;width:100%;height:100%;object-fit:contain}.preview--html{height:520px;min-height:280px;max-height:1100px;resize:vertical;overflow:auto}.preview--html iframe{display:block;width:100%;height:100%;border:0;background:white}.open{position:absolute;right:10px;top:10px;border:1px solid rgba(20,59,51,.28);border-radius:999px;padding:7px 12px;background:rgba(255,253,248,.93);color:var(--ink);text-decoration:none;font-size:12px;font-weight:700}.preview--layerdoc{min-height:250px;display:flex;flex-direction:column;align-items:center;justify-content:center;color:var(--muted);gap:8px}.preview--layerdoc strong{font:500 24px Georgia,serif;color:var(--ink)}.layerdoc-mark{font:500 38px Georgia,serif;color:var(--signal)}.published-page>p{padding:12px 16px;margin:0!important;background:#f3f0e9}.screen-sequence{padding:18px 0;border-block:1px solid var(--line);background:#f0eee8}.screen-sequence>p{padding:0 20px}.sequence-track{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(min(82vw,420px),1fr);gap:14px;overflow-x:auto;padding:0 20px 8px;scroll-snap-type:x proximity}.screen{margin:0;border:1px solid var(--line);border-radius:13px;overflow:hidden;background:var(--panel);scroll-snap-align:start}.screen .preview{border-top:0}.screen figcaption{padding:13px 15px 15px}.screen h5{font:500 17px/1.2 Georgia,serif;margin:0;color:var(--ink)}.screen figcaption p{font-size:12px;color:var(--muted);margin:7px 0 0}.comparison{display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--line);border-block:1px solid var(--line)}.comparison section{background:var(--panel);min-width:0}.comparison .eyebrow{padding:10px 14px;margin:0!important}.comparison .preview{border-bottom:0}.edit-receipt{padding:10px 18px;margin:0;color:var(--muted);font-size:12px;border-bottom:1px solid var(--line)}.diff-strip{display:flex;gap:10px;overflow-x:auto;padding:12px 18px;border-bottom:1px solid var(--line);background:#fff8ef}.diff-region{flex:0 0 min(340px,82vw);border-left:3px solid var(--signal);padding:8px 10px;background:var(--panel)}.diff-region strong{display:block;color:var(--ink);font-size:12px}.diff-region span{display:block;color:var(--muted);font-size:11px;margin-top:3px}.diff-region del,.diff-region ins{display:block;font-size:12px;text-decoration:none;margin-top:5px}.diff-region del{color:#8f3a2f}.diff-region ins{color:#1f6955}.controls{display:grid;grid-template-columns:minmax(0,1fr);gap:0}.feedback,.edit{padding:18px 20px}.edit{border-top:1px solid var(--line);background:#f3f4ef}.edit--disabled p,.edit-note{margin:0;color:var(--muted)}label{display:grid;gap:7px;color:var(--ink);font-weight:700;font-size:13px}textarea{width:100%;min-height:82px;resize:vertical;border:1px solid #bbb9b1;border-radius:10px;padding:11px 12px;background:#fff;color:var(--text);outline:none}textarea:focus{border-color:var(--ink);box-shadow:0 0 0 3px rgba(20,59,51,.12)}.mark-row,.save-row{display:flex;align-items:center;gap:8px}.mark-row{margin-bottom:14px;flex-wrap:wrap}.mark-row button,.save,.apply{border:1px solid var(--ink);border-radius:999px;background:transparent;color:var(--ink);padding:8px 13px;font-weight:750;cursor:pointer}.mark-row button.active,.save,.apply{background:var(--ink);color:white}.mark-row .clear{border-color:transparent;color:var(--muted)}.save-row{margin-top:11px;min-height:36px}.save,.apply{border-radius:9px;padding:9px 18px}.apply{background:var(--signal);border-color:var(--signal)}button:disabled{cursor:wait;opacity:.55}.status{font-size:12px;color:var(--muted)}.cost{margin:10px 0 0;color:var(--muted);font-size:12px}.cost strong{color:var(--signal)}.history{border-top:1px solid var(--line);padding:12px 20px}.history summary{cursor:pointer;color:var(--ink);font-weight:750}.history ol{margin:10px 0 0;padding-left:22px}.history li{padding:5px 0;color:var(--muted);font-size:12px}.history a{color:var(--ink)}code{font:12px ui-monospace,SFMono-Regular,Menlo,monospace;background:#e9e5dc;padding:2px 5px;border-radius:4px}
5
+ @media(max-width:760px){.mast{position:static;align-items:flex-start;flex-direction:column}.summary{justify-content:flex-start}.shell{padding-top:24px}.run-head{flex-direction:column}.comparison{grid-template-columns:1fr}.preview--html{height:400px}.item-head{min-height:0}.screen{flex-basis:86vw}}
6
+ `;
7
+ export const REVIEW_PAGE_SCRIPT = `
8
+ const post = async (url, body) => {
9
+ const response = await fetch(url, {method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify(body)});
10
+ const payload = await response.json().catch(() => ({error:'The server returned no detail.'}));
11
+ if (!response.ok) throw new Error(payload.error || 'The request failed.');
12
+ return payload;
13
+ };
14
+ for (const form of document.querySelectorAll('[data-feedback]')) {
15
+ const status = form.querySelector('.status');
16
+ const save = async () => {
17
+ status.textContent = 'Saving…';
18
+ try {
19
+ await post('/api/feedback', {runId:form.dataset.run,itemId:form.dataset.item,note:form.elements.note.value,mark:form.dataset.mark || null});
20
+ status.textContent = 'Saved';
21
+ } catch (error) { status.textContent = error.message; }
22
+ };
23
+ form.addEventListener('submit', (event) => { event.preventDefault(); save(); });
24
+ for (const button of form.querySelectorAll('[data-mark]')) button.addEventListener('click', () => {
25
+ form.dataset.mark = button.dataset.mark;
26
+ for (const peer of form.querySelectorAll('[data-mark]')) {
27
+ const active = Boolean(peer.dataset.mark) && peer.dataset.mark === form.dataset.mark;
28
+ peer.classList.toggle('active', active); peer.setAttribute('aria-pressed', String(active));
29
+ }
30
+ save();
31
+ });
32
+ }
33
+ for (const form of document.querySelectorAll('[data-edit]')) form.addEventListener('submit', async (event) => {
34
+ event.preventDefault();
35
+ const button = form.querySelector('.apply'); const status = form.querySelector('.status');
36
+ button.disabled = true; status.textContent = form.dataset.mode === 'convert-then-edit' ? 'Converting, then editing…' : 'Applying…';
37
+ try {
38
+ await post('/api/edit', {runId:form.dataset.run,itemId:form.dataset.item,prompt:form.elements.prompt.value});
39
+ status.textContent = 'Applied'; window.location.reload();
40
+ } catch (error) { status.textContent = error.message; button.disabled = false; }
41
+ });
42
+ `;
43
+ //# sourceMappingURL=review-page-assets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-page-assets.js","sourceRoot":"","sources":["../src/review-page-assets.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,kBAAkB,GAAG;;;;;CAKjC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCjC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ReviewModel } from './review-types.js';
2
+ export declare const renderReviewPage: (model: ReviewModel) => string;
3
+ //# sourceMappingURL=review-page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-page.d.ts","sourceRoot":"","sources":["../src/review-page.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAIV,WAAW,EAEZ,MAAM,mBAAmB,CAAC;AAmO3B,eAAO,MAAM,gBAAgB,GAAI,OAAO,WAAW,KAAG,MAoBrD,CAAC"}