@12ui/design 0.2.14 → 0.2.16
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 +21 -1
- package/dist/bounded-concurrency.d.ts +13 -0
- package/dist/bounded-concurrency.d.ts.map +1 -0
- package/dist/bounded-concurrency.js +43 -0
- package/dist/bounded-concurrency.js.map +1 -0
- package/dist/branch-downloads.d.ts +10 -0
- package/dist/branch-downloads.d.ts.map +1 -1
- package/dist/branch-downloads.js +20 -0
- package/dist/branch-downloads.js.map +1 -1
- package/dist/branch-execution.d.ts +7 -0
- package/dist/branch-execution.d.ts.map +1 -1
- package/dist/branch-execution.js +175 -38
- package/dist/branch-execution.js.map +1 -1
- package/dist/branch-materialize.d.ts +23 -12
- package/dist/branch-materialize.d.ts.map +1 -1
- package/dist/branch-materialize.js +55 -38
- package/dist/branch-materialize.js.map +1 -1
- package/dist/branch-page-conversion.d.ts +109 -5
- package/dist/branch-page-conversion.d.ts.map +1 -1
- package/dist/branch-page-conversion.js +375 -179
- package/dist/branch-page-conversion.js.map +1 -1
- package/dist/branch-progress.d.ts +24 -0
- package/dist/branch-progress.d.ts.map +1 -1
- package/dist/branch-progress.js +35 -6
- package/dist/branch-progress.js.map +1 -1
- package/dist/branch-run-record.d.ts +14 -0
- package/dist/branch-run-record.d.ts.map +1 -1
- package/dist/branch-run-record.js.map +1 -1
- package/dist/branch-status.d.ts.map +1 -1
- package/dist/branch-status.js +3 -0
- package/dist/branch-status.js.map +1 -1
- package/dist/cli-arguments.d.ts.map +1 -1
- package/dist/cli-arguments.js +1 -0
- package/dist/cli-arguments.js.map +1 -1
- package/dist/cli-branch-command.d.ts +10 -1
- package/dist/cli-branch-command.d.ts.map +1 -1
- package/dist/cli-branch-command.js +60 -11
- package/dist/cli-branch-command.js.map +1 -1
- package/dist/cli-capabilities.d.ts +35 -2
- package/dist/cli-capabilities.d.ts.map +1 -1
- package/dist/cli-capabilities.js +38 -1
- package/dist/cli-capabilities.js.map +1 -1
- package/dist/cli-draft-command.d.ts +2 -0
- package/dist/cli-draft-command.d.ts.map +1 -1
- package/dist/cli-draft-command.js +22 -4
- package/dist/cli-draft-command.js.map +1 -1
- package/dist/cli-package-command.d.ts +13 -0
- package/dist/cli-package-command.d.ts.map +1 -1
- package/dist/cli-package-command.js +35 -8
- package/dist/cli-package-command.js.map +1 -1
- package/dist/cli-progress.d.ts +81 -5
- package/dist/cli-progress.d.ts.map +1 -1
- package/dist/cli-progress.js +108 -5
- package/dist/cli-progress.js.map +1 -1
- package/dist/cli-skill-command.d.ts.map +1 -1
- package/dist/cli-skill-command.js +27 -12
- package/dist/cli-skill-command.js.map +1 -1
- package/dist/cli.js +20 -10
- package/dist/cli.js.map +1 -1
- package/dist/conversion-receipt-store.d.ts +75 -0
- package/dist/conversion-receipt-store.d.ts.map +1 -0
- package/dist/conversion-receipt-store.js +143 -0
- package/dist/conversion-receipt-store.js.map +1 -0
- package/dist/conversion-receipt.d.ts +223 -0
- package/dist/conversion-receipt.d.ts.map +1 -0
- package/dist/conversion-receipt.js +352 -0
- package/dist/conversion-receipt.js.map +1 -0
- package/dist/draft-adoption.d.ts +48 -0
- package/dist/draft-adoption.d.ts.map +1 -0
- package/dist/draft-adoption.js +237 -0
- package/dist/draft-adoption.js.map +1 -0
- package/dist/draft-run.d.ts +10 -0
- package/dist/draft-run.d.ts.map +1 -1
- package/dist/draft-run.js +16 -4
- package/dist/draft-run.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/legacy-skill-catalog.d.ts.map +1 -1
- package/dist/legacy-skill-catalog.js +65 -0
- package/dist/legacy-skill-catalog.js.map +1 -1
- package/dist/package-client.d.ts +28 -0
- package/dist/package-client.d.ts.map +1 -1
- package/dist/package-client.js +21 -1
- package/dist/package-client.js.map +1 -1
- package/dist/package-source-refusal.d.ts +17 -0
- package/dist/package-source-refusal.d.ts.map +1 -0
- package/dist/package-source-refusal.js +61 -0
- package/dist/package-source-refusal.js.map +1 -0
- package/dist/package-submission.d.ts +43 -1
- package/dist/package-submission.d.ts.map +1 -1
- package/dist/package-submission.js +32 -7
- package/dist/package-submission.js.map +1 -1
- package/dist/skill-clients.d.ts +39 -0
- package/dist/skill-clients.d.ts.map +1 -0
- package/dist/skill-clients.js +156 -0
- package/dist/skill-clients.js.map +1 -0
- package/dist/skill-installer.d.ts +2 -3
- package/dist/skill-installer.d.ts.map +1 -1
- package/dist/skill-installer.js +9 -101
- package/dist/skill-installer.js.map +1 -1
- package/package.json +1 -1
- package/skills/design/SKILL.md +6 -3
- package/skills/design-branch/SKILL.md +6 -5
- package/skills/design-convert/SKILL.md +3 -3
- package/skills/design-draft/SKILL.md +3 -3
- package/skills/design-search/SKILL.md +3 -3
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import type { ConversionOperation } from './conversion-client.js';
|
|
2
|
+
import type { ConversionOutput } from './conversion-outputs.js';
|
|
3
|
+
import { type ConversionReceiptKey } from './conversion-receipt-store.js';
|
|
4
|
+
import type { PackageSubmissionResult } from './package-submission.js';
|
|
5
|
+
/**
|
|
6
|
+
* The single owner of "an image's conversion was already bought, and here is
|
|
7
|
+
* the proof".
|
|
8
|
+
*
|
|
9
|
+
* A branch run's approved design is viewport 1 of its first page, and the
|
|
10
|
+
* common flow converts that same design on its own first
|
|
11
|
+
* (`12ui convert <winner>.png --output layerdoc --export html`), so without a
|
|
12
|
+
* receipt every branch run buys an image-to-LayerDoc conversion of bytes the
|
|
13
|
+
* account has already paid to convert. The package accepts a finished
|
|
14
|
+
* conversion for a viewport (`source_conversion_id`), and the server proves the
|
|
15
|
+
* claim against the referenced conversion's admitted evidence before it skips
|
|
16
|
+
* the upload — so a false claim is a failed page, not a cheap win.
|
|
17
|
+
*
|
|
18
|
+
* This is therefore a receipt of a proved fact, not a cache: it records the
|
|
19
|
+
* digest of the exact bytes a succeeded conversion was admitted with. A later
|
|
20
|
+
* run reuses it only when the bytes it is about to submit hash identically.
|
|
21
|
+
* Absent proof it converts fresh.
|
|
22
|
+
*
|
|
23
|
+
* The records live in the per-user store (`conversion-receipt-store.ts`), keyed
|
|
24
|
+
* by that digest and the model, because the fact is about bytes and not about
|
|
25
|
+
* where a copy of them happens to sit. `12ui convert`, `12ui convert package`,
|
|
26
|
+
* and `12ui branch execute --convert` write them, `12ui branch execute
|
|
27
|
+
* --convert` reads them, and only this module decides what counts as proof.
|
|
28
|
+
*
|
|
29
|
+
* SUNSET — legacy sidecars. Receipts shipped in 0.2.15 as
|
|
30
|
+
* `<image>.conversion.json` written beside the input image. Those files are
|
|
31
|
+
* still READ beside a winner image for one release cycle and migrated into the
|
|
32
|
+
* store the first time they are seen, so an upgrade never re-buys a conversion
|
|
33
|
+
* a 0.2.15 convert already paid for. Nothing writes them any more. Delete the
|
|
34
|
+
* legacy read path — `LEGACY_CONVERSION_RECEIPT_SUFFIX`,
|
|
35
|
+
* `legacyConversionReceiptPath`, `readLegacyConversionReceipts`, and the
|
|
36
|
+
* `legacyImagePaths` argument of `invalidateConversionReceipts` — one release
|
|
37
|
+
* after 0.2.16; by then every receipt a 0.2.15 convert wrote has long outlived
|
|
38
|
+
* the ~24h conversion it names.
|
|
39
|
+
*/
|
|
40
|
+
export declare const LEGACY_CONVERSION_RECEIPT_SUFFIX = ".conversion.json";
|
|
41
|
+
export type { ConversionReceiptKey } from './conversion-receipt-store.js';
|
|
42
|
+
export { resolveConversionReceiptStore } from './conversion-receipt-store.js';
|
|
43
|
+
/**
|
|
44
|
+
* The output an attachable conversion must have produced. A package converts
|
|
45
|
+
* every viewport to a LayerDoc and buys the page export separately, so the
|
|
46
|
+
* server (`PACKAGE_VIEWPORT_CHILD_OUTPUT`) refuses any attached conversion
|
|
47
|
+
* whose own output is `html` or any other rendered document.
|
|
48
|
+
*/
|
|
49
|
+
export declare const REUSABLE_CONVERSION_OUTPUT: ConversionOutput;
|
|
50
|
+
/**
|
|
51
|
+
* How much life the referenced conversion must have left. The server refuses an
|
|
52
|
+
* attachment expiring within this window (`PACKAGE_SOURCE_MINIMUM_REMAINING_MS`)
|
|
53
|
+
* because composition reads the source run at the END of a package drive, and
|
|
54
|
+
* that refusal fails the page after its screens are already paid for.
|
|
55
|
+
* Conversions live 24h while a stored receipt sits in the user's home
|
|
56
|
+
* indefinitely, so an expiry that is not checked here is a page failure waiting
|
|
57
|
+
* for day two.
|
|
58
|
+
*/
|
|
59
|
+
export declare const CONVERSION_REUSE_MINIMUM_REMAINING_MS: number;
|
|
60
|
+
export type ConversionReceipt = {
|
|
61
|
+
version: 1;
|
|
62
|
+
/** Digest of the EXACT bytes the conversion was admitted with. */
|
|
63
|
+
sha256: string;
|
|
64
|
+
conversionId: string;
|
|
65
|
+
/** A reused conversion must have run the model the package declares. */
|
|
66
|
+
model: string;
|
|
67
|
+
/**
|
|
68
|
+
* The operation that bought it: a branch run id, a package id, or for
|
|
69
|
+
* `12ui convert` the conversion's own id. An operation never reuses its own
|
|
70
|
+
* receipt — a branch package key is derived per run and page, so attaching a
|
|
71
|
+
* reuse on a resume would change the request body under a key the server
|
|
72
|
+
* already settled, which is `409 idempotency_conflict` on a page that was
|
|
73
|
+
* already paid for.
|
|
74
|
+
*/
|
|
75
|
+
boughtBy: string;
|
|
76
|
+
/** When the referenced conversion stops being attachable at all. */
|
|
77
|
+
expiresAt: string;
|
|
78
|
+
createdAt: string;
|
|
79
|
+
};
|
|
80
|
+
export type ConversionReceiptWrite = {
|
|
81
|
+
/** Where the record landed, or null when nothing was written. */
|
|
82
|
+
path: string | null;
|
|
83
|
+
failure?: {
|
|
84
|
+
path: string;
|
|
85
|
+
detail: string;
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
/** Where 0.2.15 wrote a receipt. Read for one release cycle, never written. */
|
|
89
|
+
export declare const legacyConversionReceiptPath: (imagePath: string) => string;
|
|
90
|
+
export declare const conversionReceiptKey: (receipt: ConversionReceipt) => ConversionReceiptKey;
|
|
91
|
+
/**
|
|
92
|
+
* The stored record for exactly these bytes and this model, or nothing.
|
|
93
|
+
*
|
|
94
|
+
* An expired record is removed as it is read: it is the one expired record this
|
|
95
|
+
* invocation is certain about, and leaving it would have the next run read it
|
|
96
|
+
* again to reach the same conclusion.
|
|
97
|
+
*/
|
|
98
|
+
export declare const readStoredConversionReceipt: (key: ConversionReceiptKey, options?: {
|
|
99
|
+
store?: string;
|
|
100
|
+
now?: Date;
|
|
101
|
+
}) => Promise<ConversionReceipt | undefined>;
|
|
102
|
+
/**
|
|
103
|
+
* Record a proved conversion. A write that fails is not a command failure: the
|
|
104
|
+
* receipt is an optimisation, and its absence only costs one conversion.
|
|
105
|
+
* Callers that can say so report the failure; the rest ignore it.
|
|
106
|
+
*/
|
|
107
|
+
export declare const recordConversionReceipt: (receipt: ConversionReceipt, options?: {
|
|
108
|
+
store?: string;
|
|
109
|
+
now?: Date;
|
|
110
|
+
}) => Promise<ConversionReceiptWrite>;
|
|
111
|
+
/**
|
|
112
|
+
* The 0.2.15 sidecars beside these images, carried forward.
|
|
113
|
+
*
|
|
114
|
+
* Every one that is still live is copied into the store the moment it is seen,
|
|
115
|
+
* so the upgrade costs nothing and the next run finds the proof by digest no
|
|
116
|
+
* matter which copy of the image it starts from. An existing store record wins:
|
|
117
|
+
* it was written by a later command about the same bytes, and overwriting it
|
|
118
|
+
* with the sidecar would replace a fresher expiry with an older one. Migration
|
|
119
|
+
* is best-effort — the receipt is still honoured this run either way.
|
|
120
|
+
*/
|
|
121
|
+
export declare const readLegacyConversionReceipts: (imagePaths: readonly string[], options?: {
|
|
122
|
+
store?: string;
|
|
123
|
+
now?: Date;
|
|
124
|
+
}) => Promise<ConversionReceipt[]>;
|
|
125
|
+
/**
|
|
126
|
+
* The proof gate. Every condition is a fact about the bytes in hand, never an
|
|
127
|
+
* assumption about what an earlier command probably did.
|
|
128
|
+
*/
|
|
129
|
+
export declare const reusableConversionId: (args: {
|
|
130
|
+
receipts: readonly ConversionReceipt[];
|
|
131
|
+
/** Digest of the bytes this package is about to submit for the winner. */
|
|
132
|
+
sha256: string;
|
|
133
|
+
model: string;
|
|
134
|
+
/** The operation about to submit: its own receipt is never proof for it. */
|
|
135
|
+
boughtBy: string;
|
|
136
|
+
now?: Date;
|
|
137
|
+
}) => string | undefined;
|
|
138
|
+
/**
|
|
139
|
+
* The gate, over the store and over whatever the caller already holds.
|
|
140
|
+
*
|
|
141
|
+
* The store is consulted first because it is the record every command writes;
|
|
142
|
+
* the in-hand receipts are the 0.2.15 sidecars this run read beside the winner,
|
|
143
|
+
* which stay proof for one release cycle even if their migration failed.
|
|
144
|
+
*/
|
|
145
|
+
export declare const findReusableConversionId: (args: {
|
|
146
|
+
sha256: string;
|
|
147
|
+
model: string;
|
|
148
|
+
boughtBy: string;
|
|
149
|
+
receipts?: readonly ConversionReceipt[];
|
|
150
|
+
store?: string;
|
|
151
|
+
now?: Date;
|
|
152
|
+
}) => Promise<string | undefined>;
|
|
153
|
+
/**
|
|
154
|
+
* Withdraw a receipt the SERVER disproved, so the next run does not repeat the
|
|
155
|
+
* dance the last one already paid a retry for.
|
|
156
|
+
*
|
|
157
|
+
* The bar is deliberately narrow: only an explicit refusal of the attachment at
|
|
158
|
+
* admission — the server having read the referenced conversion's durable
|
|
159
|
+
* evidence and rejected the claim — is proof that this receipt is no longer
|
|
160
|
+
* proof of anything. A network error, a timeout, or any other transient failure
|
|
161
|
+
* says nothing about the referenced conversion, and deleting on one of those
|
|
162
|
+
* would throw away a live receipt and buy its conversion again for nothing.
|
|
163
|
+
*
|
|
164
|
+
* Only records naming the disproven conversion are withdrawn: a newer record
|
|
165
|
+
* under the same key describes different work and is untouched. Removal is
|
|
166
|
+
* best-effort, because a receipt that cannot be deleted only costs the next run
|
|
167
|
+
* one refused attachment and one retry — the same price this run paid.
|
|
168
|
+
*/
|
|
169
|
+
export declare const invalidateConversionReceipts: (args: {
|
|
170
|
+
conversionId: string;
|
|
171
|
+
/** The keys the disproven claim could have come from. */
|
|
172
|
+
keys?: readonly ConversionReceiptKey[];
|
|
173
|
+
/** Sunset: 0.2.15 sidecars beside these images, if they name it. */
|
|
174
|
+
legacyImagePaths?: readonly string[];
|
|
175
|
+
store?: string;
|
|
176
|
+
}) => Promise<string[]>;
|
|
177
|
+
/**
|
|
178
|
+
* What `12ui convert` leaves behind for the branch run that follows it.
|
|
179
|
+
*
|
|
180
|
+
* Only a succeeded image-to-LayerDoc conversion can stand in for a package
|
|
181
|
+
* viewport, so anything else records nothing at all: a receipt for an `html`
|
|
182
|
+
* conversion would be a claim the server refuses, and the refusal costs a whole
|
|
183
|
+
* page. The digest is of the bytes actually submitted, which is what `--width`
|
|
184
|
+
* normalization changes and what the server admitted the run with.
|
|
185
|
+
*/
|
|
186
|
+
export declare const recordConvertedImageReceipt: (args: {
|
|
187
|
+
/** The EXACT bytes submitted, after any `--width` normalization. */
|
|
188
|
+
bytes: Uint8Array;
|
|
189
|
+
operation: Pick<ConversionOperation, "id" | "status" | "output" | "model" | "expires_at" | "input_kind">;
|
|
190
|
+
store?: string;
|
|
191
|
+
warn?: (message: string) => void;
|
|
192
|
+
now?: Date;
|
|
193
|
+
}) => Promise<ConversionReceipt | undefined>;
|
|
194
|
+
/**
|
|
195
|
+
* What `12ui convert package` leaves behind: one receipt per viewport whose own
|
|
196
|
+
* child conversion the package bought.
|
|
197
|
+
*
|
|
198
|
+
* A package converts each viewport to a LayerDoc and composes the page from
|
|
199
|
+
* those children, so every viewport of a submitted page is exactly the artifact
|
|
200
|
+
* a later package can attach instead of buying — the same fact the branch path
|
|
201
|
+
* records for the winner, for every screenshot the user named.
|
|
202
|
+
*
|
|
203
|
+
* A viewport that ATTACHED a conversion bought nothing, so it records nothing.
|
|
204
|
+
* The expiry reported is the package's own, which its children cannot outlive
|
|
205
|
+
* backwards, and the model is the one the server says it ran; without either
|
|
206
|
+
* fact nothing here proves a conversion is still attachable, so nothing is
|
|
207
|
+
* recorded and the caller is told once.
|
|
208
|
+
*/
|
|
209
|
+
export declare const recordPackageConversionReceipts: (args: {
|
|
210
|
+
pages: readonly {
|
|
211
|
+
id: string;
|
|
212
|
+
viewports: readonly {
|
|
213
|
+
id: string;
|
|
214
|
+
bytes: Uint8Array;
|
|
215
|
+
sourceConversionId?: string;
|
|
216
|
+
}[];
|
|
217
|
+
}[];
|
|
218
|
+
result: Pick<PackageSubmissionResult, "packageId" | "model" | "expiresAt" | "pages">;
|
|
219
|
+
store?: string;
|
|
220
|
+
warn?: (message: string) => void;
|
|
221
|
+
now?: Date;
|
|
222
|
+
}) => Promise<ConversionReceipt[]>;
|
|
223
|
+
//# sourceMappingURL=conversion-receipt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversion-receipt.d.ts","sourceRoot":"","sources":["../src/conversion-receipt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { readFile, rm } from 'node:fs/promises';
|
|
3
|
+
import { conversionReceiptRecordPath, pruneConversionReceiptRecords, readConversionReceiptRecord, removeConversionReceiptRecord, resolveConversionReceiptStore, writeConversionReceiptRecord, } from './conversion-receipt-store.js';
|
|
4
|
+
/**
|
|
5
|
+
* The single owner of "an image's conversion was already bought, and here is
|
|
6
|
+
* the proof".
|
|
7
|
+
*
|
|
8
|
+
* A branch run's approved design is viewport 1 of its first page, and the
|
|
9
|
+
* common flow converts that same design on its own first
|
|
10
|
+
* (`12ui convert <winner>.png --output layerdoc --export html`), so without a
|
|
11
|
+
* receipt every branch run buys an image-to-LayerDoc conversion of bytes the
|
|
12
|
+
* account has already paid to convert. The package accepts a finished
|
|
13
|
+
* conversion for a viewport (`source_conversion_id`), and the server proves the
|
|
14
|
+
* claim against the referenced conversion's admitted evidence before it skips
|
|
15
|
+
* the upload — so a false claim is a failed page, not a cheap win.
|
|
16
|
+
*
|
|
17
|
+
* This is therefore a receipt of a proved fact, not a cache: it records the
|
|
18
|
+
* digest of the exact bytes a succeeded conversion was admitted with. A later
|
|
19
|
+
* run reuses it only when the bytes it is about to submit hash identically.
|
|
20
|
+
* Absent proof it converts fresh.
|
|
21
|
+
*
|
|
22
|
+
* The records live in the per-user store (`conversion-receipt-store.ts`), keyed
|
|
23
|
+
* by that digest and the model, because the fact is about bytes and not about
|
|
24
|
+
* where a copy of them happens to sit. `12ui convert`, `12ui convert package`,
|
|
25
|
+
* and `12ui branch execute --convert` write them, `12ui branch execute
|
|
26
|
+
* --convert` reads them, and only this module decides what counts as proof.
|
|
27
|
+
*
|
|
28
|
+
* SUNSET — legacy sidecars. Receipts shipped in 0.2.15 as
|
|
29
|
+
* `<image>.conversion.json` written beside the input image. Those files are
|
|
30
|
+
* still READ beside a winner image for one release cycle and migrated into the
|
|
31
|
+
* store the first time they are seen, so an upgrade never re-buys a conversion
|
|
32
|
+
* a 0.2.15 convert already paid for. Nothing writes them any more. Delete the
|
|
33
|
+
* legacy read path — `LEGACY_CONVERSION_RECEIPT_SUFFIX`,
|
|
34
|
+
* `legacyConversionReceiptPath`, `readLegacyConversionReceipts`, and the
|
|
35
|
+
* `legacyImagePaths` argument of `invalidateConversionReceipts` — one release
|
|
36
|
+
* after 0.2.16; by then every receipt a 0.2.15 convert wrote has long outlived
|
|
37
|
+
* the ~24h conversion it names.
|
|
38
|
+
*/
|
|
39
|
+
export const LEGACY_CONVERSION_RECEIPT_SUFFIX = '.conversion.json';
|
|
40
|
+
export { resolveConversionReceiptStore } from './conversion-receipt-store.js';
|
|
41
|
+
/**
|
|
42
|
+
* The output an attachable conversion must have produced. A package converts
|
|
43
|
+
* every viewport to a LayerDoc and buys the page export separately, so the
|
|
44
|
+
* server (`PACKAGE_VIEWPORT_CHILD_OUTPUT`) refuses any attached conversion
|
|
45
|
+
* whose own output is `html` or any other rendered document.
|
|
46
|
+
*/
|
|
47
|
+
export const REUSABLE_CONVERSION_OUTPUT = 'layerdoc';
|
|
48
|
+
/**
|
|
49
|
+
* How much life the referenced conversion must have left. The server refuses an
|
|
50
|
+
* attachment expiring within this window (`PACKAGE_SOURCE_MINIMUM_REMAINING_MS`)
|
|
51
|
+
* because composition reads the source run at the END of a package drive, and
|
|
52
|
+
* that refusal fails the page after its screens are already paid for.
|
|
53
|
+
* Conversions live 24h while a stored receipt sits in the user's home
|
|
54
|
+
* indefinitely, so an expiry that is not checked here is a page failure waiting
|
|
55
|
+
* for day two.
|
|
56
|
+
*/
|
|
57
|
+
export const CONVERSION_REUSE_MINIMUM_REMAINING_MS = 60 * 60_000;
|
|
58
|
+
/** Where 0.2.15 wrote a receipt. Read for one release cycle, never written. */
|
|
59
|
+
export const legacyConversionReceiptPath = (imagePath) => (`${imagePath}${LEGACY_CONVERSION_RECEIPT_SUFFIX}`);
|
|
60
|
+
const isReceipt = (value) => {
|
|
61
|
+
if (!value || typeof value !== 'object')
|
|
62
|
+
return false;
|
|
63
|
+
const record = value;
|
|
64
|
+
return record.version === 1
|
|
65
|
+
&& typeof record.sha256 === 'string'
|
|
66
|
+
&& /^[a-f0-9]{64}$/u.test(record.sha256)
|
|
67
|
+
&& typeof record.conversionId === 'string'
|
|
68
|
+
&& record.conversionId.length > 0
|
|
69
|
+
&& typeof record.model === 'string'
|
|
70
|
+
&& record.model.length > 0
|
|
71
|
+
&& typeof record.boughtBy === 'string'
|
|
72
|
+
&& record.boughtBy.length > 0
|
|
73
|
+
&& typeof record.expiresAt === 'string'
|
|
74
|
+
&& Number.isFinite(Date.parse(record.expiresAt));
|
|
75
|
+
};
|
|
76
|
+
export const conversionReceiptKey = (receipt) => ({
|
|
77
|
+
sha256: receipt.sha256,
|
|
78
|
+
model: receipt.model,
|
|
79
|
+
});
|
|
80
|
+
const storeOf = (store) => store ?? resolveConversionReceiptStore();
|
|
81
|
+
const expiredReceipt = (receipt, now) => (Date.parse(receipt.expiresAt) <= now.getTime());
|
|
82
|
+
/**
|
|
83
|
+
* Expiry hygiene, paid for by the invocations that already write to the store.
|
|
84
|
+
*
|
|
85
|
+
* Bounded on purpose: a user who converts every day accumulates a record per
|
|
86
|
+
* distinct image, and a full sweep on a hot path would make the cheapest
|
|
87
|
+
* command the one that reads the most files. A rotating sample covers the whole
|
|
88
|
+
* store across invocations, and a record that survives one pass costs nothing
|
|
89
|
+
* but its own inode until the next.
|
|
90
|
+
*/
|
|
91
|
+
const pruneExpired = async (store, now) => (await pruneConversionReceiptRecords({
|
|
92
|
+
store,
|
|
93
|
+
expired: (record) => isReceipt(record) && expiredReceipt(record, now),
|
|
94
|
+
}));
|
|
95
|
+
/**
|
|
96
|
+
* The stored record for exactly these bytes and this model, or nothing.
|
|
97
|
+
*
|
|
98
|
+
* An expired record is removed as it is read: it is the one expired record this
|
|
99
|
+
* invocation is certain about, and leaving it would have the next run read it
|
|
100
|
+
* again to reach the same conclusion.
|
|
101
|
+
*/
|
|
102
|
+
export const readStoredConversionReceipt = async (key, options = {}) => {
|
|
103
|
+
const store = storeOf(options.store);
|
|
104
|
+
const record = await readConversionReceiptRecord(store, key);
|
|
105
|
+
if (!isReceipt(record))
|
|
106
|
+
return undefined;
|
|
107
|
+
if (expiredReceipt(record, options.now ?? new Date())) {
|
|
108
|
+
await removeConversionReceiptRecord(store, key).catch(() => null);
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
return record;
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Record a proved conversion. A write that fails is not a command failure: the
|
|
115
|
+
* receipt is an optimisation, and its absence only costs one conversion.
|
|
116
|
+
* Callers that can say so report the failure; the rest ignore it.
|
|
117
|
+
*/
|
|
118
|
+
export const recordConversionReceipt = async (receipt, options = {}) => {
|
|
119
|
+
const store = storeOf(options.store);
|
|
120
|
+
// Never leave behind something that cannot be read back as proof: a record
|
|
121
|
+
// that fails the gate is indistinguishable from a corrupt file later.
|
|
122
|
+
if (!isReceipt(receipt)) {
|
|
123
|
+
return {
|
|
124
|
+
path: null,
|
|
125
|
+
failure: {
|
|
126
|
+
path: store,
|
|
127
|
+
detail: 'the conversion did not report the digest, id, model, and expiry a receipt proves',
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
const key = conversionReceiptKey(receipt);
|
|
132
|
+
try {
|
|
133
|
+
const written = await writeConversionReceiptRecord(store, key, receipt);
|
|
134
|
+
await pruneExpired(store, options.now ?? new Date());
|
|
135
|
+
return { path: written };
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
return {
|
|
139
|
+
path: null,
|
|
140
|
+
failure: {
|
|
141
|
+
path: conversionReceiptRecordPath(store, key),
|
|
142
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
const readLegacyConversionReceipt = async (imagePath) => {
|
|
148
|
+
try {
|
|
149
|
+
const parsed = JSON.parse(await readFile(legacyConversionReceiptPath(imagePath), 'utf8'));
|
|
150
|
+
return isReceipt(parsed) ? parsed : undefined;
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* The 0.2.15 sidecars beside these images, carried forward.
|
|
158
|
+
*
|
|
159
|
+
* Every one that is still live is copied into the store the moment it is seen,
|
|
160
|
+
* so the upgrade costs nothing and the next run finds the proof by digest no
|
|
161
|
+
* matter which copy of the image it starts from. An existing store record wins:
|
|
162
|
+
* it was written by a later command about the same bytes, and overwriting it
|
|
163
|
+
* with the sidecar would replace a fresher expiry with an older one. Migration
|
|
164
|
+
* is best-effort — the receipt is still honoured this run either way.
|
|
165
|
+
*/
|
|
166
|
+
export const readLegacyConversionReceipts = async (imagePaths, options = {}) => {
|
|
167
|
+
const now = options.now ?? new Date();
|
|
168
|
+
const found = await Promise.all(imagePaths.map(readLegacyConversionReceipt));
|
|
169
|
+
const receipts = found.filter((receipt) => (receipt !== undefined && !expiredReceipt(receipt, now)));
|
|
170
|
+
const store = storeOf(options.store);
|
|
171
|
+
const migrated = new Set();
|
|
172
|
+
for (const receipt of receipts) {
|
|
173
|
+
const key = conversionReceiptKey(receipt);
|
|
174
|
+
const name = `${key.sha256}/${key.model}`;
|
|
175
|
+
if (migrated.has(name))
|
|
176
|
+
continue;
|
|
177
|
+
migrated.add(name);
|
|
178
|
+
const existing = await readStoredConversionReceipt(key, { store, now });
|
|
179
|
+
if (existing)
|
|
180
|
+
continue;
|
|
181
|
+
await writeConversionReceiptRecord(store, key, receipt).catch(() => null);
|
|
182
|
+
}
|
|
183
|
+
return receipts;
|
|
184
|
+
};
|
|
185
|
+
/**
|
|
186
|
+
* The proof gate. Every condition is a fact about the bytes in hand, never an
|
|
187
|
+
* assumption about what an earlier command probably did.
|
|
188
|
+
*/
|
|
189
|
+
export const reusableConversionId = (args) => {
|
|
190
|
+
const deadline = (args.now ?? new Date()).getTime() + CONVERSION_REUSE_MINIMUM_REMAINING_MS;
|
|
191
|
+
return args.receipts.find((receipt) => (receipt.sha256 === args.sha256
|
|
192
|
+
&& receipt.model === args.model
|
|
193
|
+
&& receipt.boughtBy !== args.boughtBy
|
|
194
|
+
&& Date.parse(receipt.expiresAt) > deadline))?.conversionId;
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* The gate, over the store and over whatever the caller already holds.
|
|
198
|
+
*
|
|
199
|
+
* The store is consulted first because it is the record every command writes;
|
|
200
|
+
* the in-hand receipts are the 0.2.15 sidecars this run read beside the winner,
|
|
201
|
+
* which stay proof for one release cycle even if their migration failed.
|
|
202
|
+
*/
|
|
203
|
+
export const findReusableConversionId = async (args) => {
|
|
204
|
+
const now = args.now ?? new Date();
|
|
205
|
+
const stored = await readStoredConversionReceipt({ sha256: args.sha256, model: args.model }, { ...(args.store ? { store: args.store } : {}), now });
|
|
206
|
+
return reusableConversionId({
|
|
207
|
+
receipts: [...(stored ? [stored] : []), ...(args.receipts ?? [])],
|
|
208
|
+
sha256: args.sha256,
|
|
209
|
+
model: args.model,
|
|
210
|
+
boughtBy: args.boughtBy,
|
|
211
|
+
now,
|
|
212
|
+
});
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* Withdraw a receipt the SERVER disproved, so the next run does not repeat the
|
|
216
|
+
* dance the last one already paid a retry for.
|
|
217
|
+
*
|
|
218
|
+
* The bar is deliberately narrow: only an explicit refusal of the attachment at
|
|
219
|
+
* admission — the server having read the referenced conversion's durable
|
|
220
|
+
* evidence and rejected the claim — is proof that this receipt is no longer
|
|
221
|
+
* proof of anything. A network error, a timeout, or any other transient failure
|
|
222
|
+
* says nothing about the referenced conversion, and deleting on one of those
|
|
223
|
+
* would throw away a live receipt and buy its conversion again for nothing.
|
|
224
|
+
*
|
|
225
|
+
* Only records naming the disproven conversion are withdrawn: a newer record
|
|
226
|
+
* under the same key describes different work and is untouched. Removal is
|
|
227
|
+
* best-effort, because a receipt that cannot be deleted only costs the next run
|
|
228
|
+
* one refused attachment and one retry — the same price this run paid.
|
|
229
|
+
*/
|
|
230
|
+
export const invalidateConversionReceipts = async (args) => {
|
|
231
|
+
const store = storeOf(args.store);
|
|
232
|
+
const fromStore = await Promise.all((args.keys ?? []).map(async (key) => {
|
|
233
|
+
const record = await readConversionReceiptRecord(store, key);
|
|
234
|
+
if (!isReceipt(record) || record.conversionId !== args.conversionId)
|
|
235
|
+
return null;
|
|
236
|
+
return await removeConversionReceiptRecord(store, key);
|
|
237
|
+
}));
|
|
238
|
+
const fromSidecars = await Promise.all((args.legacyImagePaths ?? []).map(async (imagePath) => {
|
|
239
|
+
const receipt = await readLegacyConversionReceipt(imagePath);
|
|
240
|
+
if (receipt?.conversionId !== args.conversionId)
|
|
241
|
+
return null;
|
|
242
|
+
const receiptPath = legacyConversionReceiptPath(imagePath);
|
|
243
|
+
try {
|
|
244
|
+
await rm(receiptPath, { force: true });
|
|
245
|
+
return receiptPath;
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
}));
|
|
251
|
+
return [...fromStore, ...fromSidecars].filter((entry) => entry !== null);
|
|
252
|
+
};
|
|
253
|
+
/**
|
|
254
|
+
* What `12ui convert` leaves behind for the branch run that follows it.
|
|
255
|
+
*
|
|
256
|
+
* Only a succeeded image-to-LayerDoc conversion can stand in for a package
|
|
257
|
+
* viewport, so anything else records nothing at all: a receipt for an `html`
|
|
258
|
+
* conversion would be a claim the server refuses, and the refusal costs a whole
|
|
259
|
+
* page. The digest is of the bytes actually submitted, which is what `--width`
|
|
260
|
+
* normalization changes and what the server admitted the run with.
|
|
261
|
+
*/
|
|
262
|
+
export const recordConvertedImageReceipt = async (args) => {
|
|
263
|
+
const { operation } = args;
|
|
264
|
+
if (operation.status !== 'succeeded'
|
|
265
|
+
|| operation.output !== REUSABLE_CONVERSION_OUTPUT
|
|
266
|
+
// The caller submitted image bytes; an absent input_kind (a legacy cached
|
|
267
|
+
// payload) does not contradict that, while a declared `layerdoc` does.
|
|
268
|
+
|| operation.input_kind === 'layerdoc') {
|
|
269
|
+
return undefined;
|
|
270
|
+
}
|
|
271
|
+
const now = args.now ?? new Date();
|
|
272
|
+
const receipt = {
|
|
273
|
+
version: 1,
|
|
274
|
+
sha256: createHash('sha256').update(args.bytes).digest('hex'),
|
|
275
|
+
conversionId: operation.id,
|
|
276
|
+
model: operation.model,
|
|
277
|
+
boughtBy: operation.id,
|
|
278
|
+
expiresAt: operation.expires_at,
|
|
279
|
+
createdAt: now.toISOString(),
|
|
280
|
+
};
|
|
281
|
+
const write = await recordConversionReceipt(receipt, {
|
|
282
|
+
...(args.store ? { store: args.store } : {}),
|
|
283
|
+
now,
|
|
284
|
+
});
|
|
285
|
+
if (!write.failure)
|
|
286
|
+
return receipt;
|
|
287
|
+
args.warn?.(`12ui convert: could not record the conversion receipt in ${write.failure.path}`
|
|
288
|
+
+ ` (${write.failure.detail}). The conversion is unaffected; a later`
|
|
289
|
+
+ ' `12ui branch execute` from this image will buy its conversion again.');
|
|
290
|
+
return undefined;
|
|
291
|
+
};
|
|
292
|
+
/**
|
|
293
|
+
* What `12ui convert package` leaves behind: one receipt per viewport whose own
|
|
294
|
+
* child conversion the package bought.
|
|
295
|
+
*
|
|
296
|
+
* A package converts each viewport to a LayerDoc and composes the page from
|
|
297
|
+
* those children, so every viewport of a submitted page is exactly the artifact
|
|
298
|
+
* a later package can attach instead of buying — the same fact the branch path
|
|
299
|
+
* records for the winner, for every screenshot the user named.
|
|
300
|
+
*
|
|
301
|
+
* A viewport that ATTACHED a conversion bought nothing, so it records nothing.
|
|
302
|
+
* The expiry reported is the package's own, which its children cannot outlive
|
|
303
|
+
* backwards, and the model is the one the server says it ran; without either
|
|
304
|
+
* fact nothing here proves a conversion is still attachable, so nothing is
|
|
305
|
+
* recorded and the caller is told once.
|
|
306
|
+
*/
|
|
307
|
+
export const recordPackageConversionReceipts = async (args) => {
|
|
308
|
+
const { result } = args;
|
|
309
|
+
if (!result.model || !result.expiresAt) {
|
|
310
|
+
args.warn?.(`12ui convert package: package ${result.packageId} answered without a`
|
|
311
|
+
+ ` ${result.model ? 'viewport expiry' : 'model'}, so nothing here proves its viewport`
|
|
312
|
+
+ ' conversions are still attachable. They were bought and the pages are unaffected; a'
|
|
313
|
+
+ ' later run from the same screenshots will buy them again.');
|
|
314
|
+
return [];
|
|
315
|
+
}
|
|
316
|
+
const now = args.now ?? new Date();
|
|
317
|
+
const submitted = new Map(args.pages.map((page) => [page.id, page]));
|
|
318
|
+
const recorded = [];
|
|
319
|
+
for (const page of result.pages) {
|
|
320
|
+
for (const viewport of page.viewports ?? []) {
|
|
321
|
+
if (viewport.status !== 'succeeded' || !viewport.conversionId)
|
|
322
|
+
continue;
|
|
323
|
+
const source = submitted.get(page.id)?.viewports
|
|
324
|
+
.find((entry) => entry.id === viewport.id);
|
|
325
|
+
// Attached work was already proved by the receipt that named it.
|
|
326
|
+
if (!source || source.sourceConversionId)
|
|
327
|
+
continue;
|
|
328
|
+
const receipt = {
|
|
329
|
+
version: 1,
|
|
330
|
+
sha256: createHash('sha256').update(source.bytes).digest('hex'),
|
|
331
|
+
conversionId: viewport.conversionId,
|
|
332
|
+
model: result.model,
|
|
333
|
+
boughtBy: result.packageId,
|
|
334
|
+
expiresAt: result.expiresAt,
|
|
335
|
+
createdAt: now.toISOString(),
|
|
336
|
+
};
|
|
337
|
+
const write = await recordConversionReceipt(receipt, {
|
|
338
|
+
...(args.store ? { store: args.store } : {}),
|
|
339
|
+
now,
|
|
340
|
+
});
|
|
341
|
+
if (write.failure) {
|
|
342
|
+
args.warn?.(`12ui convert package: could not record the conversion receipt for ${page.id}/`
|
|
343
|
+
+ `${viewport.id} in ${write.failure.path} (${write.failure.detail}). The package is`
|
|
344
|
+
+ ' unaffected; a later run from this screenshot will buy its conversion again.');
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
recorded.push(receipt);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return recorded;
|
|
351
|
+
};
|
|
352
|
+
//# sourceMappingURL=conversion-receipt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversion-receipt.js","sourceRoot":"","sources":["../src/conversion-receipt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type DraftPaths } from './draft-workspace.js';
|
|
2
|
+
/**
|
|
3
|
+
* Which directory a `12ui draft` run continues in.
|
|
4
|
+
*
|
|
5
|
+
* MEASURED overnight 2026-08-10: a draft whose corpus search died left
|
|
6
|
+
* `…-CPcNkH` holding nothing but `references/inspire-attempt.json`, and the
|
|
7
|
+
* retry opened a NEW same-slug sibling `…-hOnLBB`. Two same-slug directories
|
|
8
|
+
* then held genuinely different candidates, so every tool that resolves a run
|
|
9
|
+
* by slug glob (`ls -dt …`) silently switched between them. The derived corpus
|
|
10
|
+
* key already stops the retry from buying the search twice, so this is a
|
|
11
|
+
* tooling-confusion hazard rather than a cost one — and the fix is to continue
|
|
12
|
+
* the stranded directory instead of stranding it.
|
|
13
|
+
*
|
|
14
|
+
* Adoption is decided on the DERIVED corpus key, never on the slug: two
|
|
15
|
+
* different design problems whose first four words match share a slug, and
|
|
16
|
+
* they must keep separate directories.
|
|
17
|
+
*/
|
|
18
|
+
export declare const DRAFT_CLAIM_FILENAME = "draft-claim.json";
|
|
19
|
+
/**
|
|
20
|
+
* The owner marker. It is created O_EXCL the moment a run directory is created
|
|
21
|
+
* or adopted, so exactly one process can ever own a directory, and it records
|
|
22
|
+
* the derived corpus key so a run that died BEFORE writing its corpus attempt
|
|
23
|
+
* record is still adoptable on its key.
|
|
24
|
+
*/
|
|
25
|
+
export type DraftRunClaim = {
|
|
26
|
+
version: 1;
|
|
27
|
+
corpusKey: string;
|
|
28
|
+
pid: number;
|
|
29
|
+
hostname: string;
|
|
30
|
+
claimedAt: string;
|
|
31
|
+
};
|
|
32
|
+
export type AcquiredDraftRun = {
|
|
33
|
+
paths: DraftPaths;
|
|
34
|
+
/** True when this run continues an incomplete previous directory in place. */
|
|
35
|
+
adopted: boolean;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* The run directory `12ui draft` continues in: an incomplete previous run for
|
|
39
|
+
* the same derived corpus key, adopted in place, or a fresh unique sibling.
|
|
40
|
+
*/
|
|
41
|
+
export declare const acquireDraftRunDirectory: (args: {
|
|
42
|
+
query: string;
|
|
43
|
+
corpusKey: string;
|
|
44
|
+
/** Overridden only by tests; production always uses the system temp root. */
|
|
45
|
+
root?: string;
|
|
46
|
+
now?: () => Date;
|
|
47
|
+
}) => Promise<AcquiredDraftRun>;
|
|
48
|
+
//# sourceMappingURL=draft-adoption.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"draft-adoption.d.ts","sourceRoot":"","sources":["../src/draft-adoption.ts"],"names":[],"mappings":"AAOA,OAAO,EAIL,KAAK,UAAU,EAChB,MAAM,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;GAeG;AAEH,eAAO,MAAM,oBAAoB,qBAAqB,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,UAAU,CAAC;IAClB,8EAA8E;IAC9E,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAkNF;;;GAGG;AACH,eAAO,MAAM,wBAAwB,GAAU,MAAM;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB,KAAG,OAAO,CAAC,gBAAgB,CAiB3B,CAAC"}
|