@12ui/design 0.2.13 → 0.2.15
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 +35 -9
- 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-client.d.ts +155 -0
- package/dist/branch-client.d.ts.map +1 -0
- package/dist/branch-client.js +179 -0
- package/dist/branch-client.js.map +1 -0
- package/dist/branch-completion.d.ts +37 -0
- package/dist/branch-completion.d.ts.map +1 -0
- package/dist/branch-completion.js +137 -0
- package/dist/branch-completion.js.map +1 -0
- package/dist/branch-dispatch-loop.d.ts +84 -0
- package/dist/branch-dispatch-loop.d.ts.map +1 -0
- package/dist/branch-dispatch-loop.js +206 -0
- package/dist/branch-dispatch-loop.js.map +1 -0
- package/dist/branch-downloads.d.ts +53 -0
- package/dist/branch-downloads.d.ts.map +1 -0
- package/dist/branch-downloads.js +114 -0
- package/dist/branch-downloads.js.map +1 -0
- package/dist/branch-execution-types.d.ts +54 -0
- package/dist/branch-execution-types.d.ts.map +1 -0
- package/dist/branch-execution-types.js +2 -0
- package/dist/branch-execution-types.js.map +1 -0
- package/dist/branch-execution.d.ts +20 -0
- package/dist/branch-execution.d.ts.map +1 -0
- package/dist/branch-execution.js +380 -0
- package/dist/branch-execution.js.map +1 -0
- package/dist/branch-identity.d.ts +71 -0
- package/dist/branch-identity.d.ts.map +1 -0
- package/dist/branch-identity.js +72 -0
- package/dist/branch-identity.js.map +1 -0
- package/dist/branch-materialize.d.ts +33 -0
- package/dist/branch-materialize.d.ts.map +1 -0
- package/dist/branch-materialize.js +64 -0
- package/dist/branch-materialize.js.map +1 -0
- package/dist/branch-page-conversion.d.ts +127 -0
- package/dist/branch-page-conversion.d.ts.map +1 -0
- package/dist/branch-page-conversion.js +382 -0
- package/dist/branch-page-conversion.js.map +1 -0
- package/dist/branch-plan.d.ts +63 -0
- package/dist/branch-plan.d.ts.map +1 -0
- package/dist/branch-plan.js +95 -0
- package/dist/branch-plan.js.map +1 -0
- package/dist/branch-progress.d.ts +99 -0
- package/dist/branch-progress.d.ts.map +1 -0
- package/dist/branch-progress.js +188 -0
- package/dist/branch-progress.js.map +1 -0
- package/dist/branch-run-record.d.ts +164 -0
- package/dist/branch-run-record.d.ts.map +1 -0
- package/dist/branch-run-record.js +94 -0
- package/dist/branch-run-record.js.map +1 -0
- package/dist/branch-schedule.d.ts +74 -0
- package/dist/branch-schedule.d.ts.map +1 -0
- package/dist/branch-schedule.js +130 -0
- package/dist/branch-schedule.js.map +1 -0
- package/dist/branch-status.d.ts +11 -0
- package/dist/branch-status.d.ts.map +1 -0
- package/dist/branch-status.js +118 -0
- package/dist/branch-status.js.map +1 -0
- package/dist/branch-viewport-normalization.d.ts +74 -0
- package/dist/branch-viewport-normalization.d.ts.map +1 -0
- package/dist/branch-viewport-normalization.js +120 -0
- package/dist/branch-viewport-normalization.js.map +1 -0
- package/dist/cli-arguments.d.ts.map +1 -1
- package/dist/cli-arguments.js +5 -0
- package/dist/cli-arguments.js.map +1 -1
- package/dist/cli-branch-command.d.ts +55 -0
- package/dist/cli-branch-command.d.ts.map +1 -0
- package/dist/cli-branch-command.js +475 -0
- package/dist/cli-branch-command.js.map +1 -0
- package/dist/cli-capabilities.d.ts +51 -0
- package/dist/cli-capabilities.d.ts.map +1 -1
- package/dist/cli-capabilities.js +52 -1
- package/dist/cli-capabilities.js.map +1 -1
- package/dist/cli-create-command.d.ts +21 -0
- package/dist/cli-create-command.d.ts.map +1 -0
- package/dist/cli-create-command.js +319 -0
- package/dist/cli-create-command.js.map +1 -0
- package/dist/cli-detach.d.ts +62 -0
- package/dist/cli-detach.d.ts.map +1 -0
- package/dist/cli-detach.js +123 -0
- package/dist/cli-detach.js.map +1 -0
- package/dist/cli-draft-command.d.ts +63 -0
- package/dist/cli-draft-command.d.ts.map +1 -0
- package/dist/cli-draft-command.js +220 -0
- package/dist/cli-draft-command.js.map +1 -0
- package/dist/cli-export-command.d.ts.map +1 -1
- package/dist/cli-export-command.js +2 -3
- package/dist/cli-export-command.js.map +1 -1
- package/dist/cli-image-batch-command.d.ts +21 -0
- package/dist/cli-image-batch-command.d.ts.map +1 -1
- package/dist/cli-image-batch-command.js +65 -4
- package/dist/cli-image-batch-command.js.map +1 -1
- package/dist/cli-image-batch-resume.d.ts +7 -0
- package/dist/cli-image-batch-resume.d.ts.map +1 -1
- package/dist/cli-image-batch-resume.js +19 -2
- package/dist/cli-image-batch-resume.js.map +1 -1
- package/dist/cli-package-command.d.ts +29 -0
- package/dist/cli-package-command.d.ts.map +1 -0
- package/dist/cli-package-command.js +128 -0
- package/dist/cli-package-command.js.map +1 -0
- package/dist/cli-progress.d.ts +137 -0
- package/dist/cli-progress.d.ts.map +1 -1
- package/dist/cli-progress.js +156 -0
- package/dist/cli-progress.js.map +1 -1
- package/dist/cli-select-command.d.ts +12 -0
- package/dist/cli-select-command.d.ts.map +1 -0
- package/dist/cli-select-command.js +66 -0
- package/dist/cli-select-command.js.map +1 -0
- package/dist/cli.js +150 -7
- package/dist/cli.js.map +1 -1
- package/dist/conversion-receipt.d.ts +127 -0
- package/dist/conversion-receipt.d.ts.map +1 -0
- package/dist/conversion-receipt.js +184 -0
- package/dist/conversion-receipt.js.map +1 -0
- package/dist/create-identity.d.ts +25 -0
- package/dist/create-identity.d.ts.map +1 -0
- package/dist/create-identity.js +0 -0
- package/dist/create-identity.js.map +1 -0
- package/dist/draft-identity.d.ts +30 -0
- package/dist/draft-identity.d.ts.map +1 -0
- package/dist/draft-identity.js +0 -0
- package/dist/draft-identity.js.map +1 -0
- package/dist/draft-prompts.d.ts +35 -0
- package/dist/draft-prompts.d.ts.map +1 -0
- package/dist/draft-prompts.js +51 -0
- package/dist/draft-prompts.js.map +1 -0
- package/dist/draft-run.d.ts +32 -0
- package/dist/draft-run.d.ts.map +1 -0
- package/dist/draft-run.js +152 -0
- package/dist/draft-run.js.map +1 -0
- package/dist/draft-workspace.d.ts +90 -0
- package/dist/draft-workspace.d.ts.map +1 -0
- package/dist/draft-workspace.js +64 -0
- package/dist/draft-workspace.js.map +1 -0
- package/dist/image-batch-status.d.ts +42 -0
- package/dist/image-batch-status.d.ts.map +1 -0
- package/dist/image-batch-status.js +142 -0
- package/dist/image-batch-status.js.map +1 -0
- package/dist/image-dimensions.d.ts +12 -0
- package/dist/image-dimensions.d.ts.map +1 -0
- package/dist/image-dimensions.js +14 -0
- package/dist/image-dimensions.js.map +1 -0
- package/dist/image-generation-resume.d.ts +13 -0
- package/dist/image-generation-resume.d.ts.map +1 -1
- package/dist/image-generation-resume.js +13 -0
- package/dist/image-generation-resume.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/legacy-skill-catalog.d.ts.map +1 -1
- package/dist/legacy-skill-catalog.js +140 -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-manifest-file.d.ts +21 -0
- package/dist/package-manifest-file.d.ts.map +1 -0
- package/dist/package-manifest-file.js +119 -0
- package/dist/package-manifest-file.js.map +1 -0
- package/dist/package-manifest-template.d.ts +23 -0
- package/dist/package-manifest-template.d.ts.map +1 -0
- package/dist/package-manifest-template.js +60 -0
- package/dist/package-manifest-template.js.map +1 -0
- 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 +134 -0
- package/dist/package-submission.d.ts.map +1 -0
- package/dist/package-submission.js +196 -0
- package/dist/package-submission.js.map +1 -0
- package/dist/selection-record.d.ts +95 -0
- package/dist/selection-record.d.ts.map +1 -0
- package/dist/selection-record.js +121 -0
- package/dist/selection-record.js.map +1 -0
- package/package.json +1 -1
- package/skills/design/SKILL.md +43 -266
- package/skills/design-branch/SKILL.md +37 -116
- package/skills/design-convert/SKILL.md +62 -148
- package/skills/design-draft/SKILL.md +71 -135
- package/skills/design-search/SKILL.md +29 -78
- package/skills/design/references/continuation-contract.md +0 -60
- package/skills/design/references/selection-contract.md +0 -112
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { BranchAspect } from './branch-client.js';
|
|
2
|
+
import type { BranchScope } from './branch-identity.js';
|
|
3
|
+
import type { BranchDispatchEvent } from './branch-dispatch-loop.js';
|
|
4
|
+
import type { BranchConversionSettings } from './branch-page-conversion.js';
|
|
5
|
+
import type { BranchProgressPhase, BranchProgressScreen } from './branch-progress.js';
|
|
6
|
+
import type { BranchCompletion } from './branch-run-record.js';
|
|
7
|
+
import type { PackageProgressEvent } from './package-submission.js';
|
|
8
|
+
/**
|
|
9
|
+
* The inputs and events of one branch run, in their own module so the phases
|
|
10
|
+
* that consume them — download, completion, the CLI — can import them without
|
|
11
|
+
* importing the orchestrator that drives them.
|
|
12
|
+
*/
|
|
13
|
+
export type BranchWinnerInput = {
|
|
14
|
+
kind: 'run';
|
|
15
|
+
runId: string;
|
|
16
|
+
slot: string;
|
|
17
|
+
} | {
|
|
18
|
+
kind: 'image';
|
|
19
|
+
imagePath: string;
|
|
20
|
+
bytes: Uint8Array;
|
|
21
|
+
mediaType: 'image/png' | 'image/jpeg' | 'image/webp';
|
|
22
|
+
sha256: string;
|
|
23
|
+
};
|
|
24
|
+
export type BranchExecutionInputs = {
|
|
25
|
+
outDir: string;
|
|
26
|
+
scope: BranchScope;
|
|
27
|
+
concept: string;
|
|
28
|
+
winner: BranchWinnerInput;
|
|
29
|
+
aspect?: BranchAspect;
|
|
30
|
+
maxScreens?: number;
|
|
31
|
+
convert?: BranchConversionSettings;
|
|
32
|
+
idempotencyKey?: string;
|
|
33
|
+
};
|
|
34
|
+
export type BranchExecutionEvent = BranchDispatchEvent | {
|
|
35
|
+
kind: 'phase';
|
|
36
|
+
phase: string;
|
|
37
|
+
detail?: string;
|
|
38
|
+
} | {
|
|
39
|
+
/** Published every loop turn so an observer always sees motion, not absence. */
|
|
40
|
+
kind: 'progress';
|
|
41
|
+
phase: BranchProgressPhase;
|
|
42
|
+
screens: BranchProgressScreen[];
|
|
43
|
+
} | {
|
|
44
|
+
kind: 'package';
|
|
45
|
+
pageId: string;
|
|
46
|
+
progress: PackageProgressEvent;
|
|
47
|
+
};
|
|
48
|
+
export type BranchExecutionResult = {
|
|
49
|
+
completion: BranchCompletion;
|
|
50
|
+
completionPath: string;
|
|
51
|
+
/** Non-null when the run must exit non-zero. A parked partial run does not. */
|
|
52
|
+
failure: Error | null;
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=branch-execution-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branch-execution-types.d.ts","sourceRoot":"","sources":["../src/branch-execution-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,KAAK,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACtF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAEpE;;;;GAIG;AAEH,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC5C;IACA,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,WAAW,GAAG,YAAY,GAAG,YAAY,CAAC;IACrD,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEJ,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,wBAAwB,CAAC;IACnC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAC5B,mBAAmB,GACnB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GACjD;IACA,gFAAgF;IAChF,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,mBAAmB,CAAC;IAC3B,OAAO,EAAE,oBAAoB,EAAE,CAAC;CACjC,GACC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,oBAAoB,CAAA;CAAE,CAAC;AAExE,MAAM,MAAM,qBAAqB,GAAG;IAClC,UAAU,EAAE,gBAAgB,CAAC;IAC7B,cAAc,EAAE,MAAM,CAAC;IACvB,+EAA+E;IAC/E,OAAO,EAAE,KAAK,GAAG,IAAI,CAAC;CACvB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branch-execution-types.js","sourceRoot":"","sources":["../src/branch-execution-types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type TwelveUiBranchClient } from './branch-client.js';
|
|
2
|
+
import { type BranchDispatchTuning } from './branch-dispatch-loop.js';
|
|
3
|
+
import type { TwelveUiConversionPackageClient } from './package-client.js';
|
|
4
|
+
import type { BranchExecutionEvent, BranchExecutionInputs, BranchExecutionResult } from './branch-execution-types.js';
|
|
5
|
+
export type { BranchExecutionEvent, BranchExecutionInputs, BranchExecutionResult, BranchWinnerInput, } from './branch-execution-types.js';
|
|
6
|
+
export declare const deriveBranchRunKey: (inputs: BranchExecutionInputs) => string;
|
|
7
|
+
export declare const executeBranchRun: (args: {
|
|
8
|
+
branchClient: TwelveUiBranchClient;
|
|
9
|
+
packageClient?: TwelveUiConversionPackageClient;
|
|
10
|
+
inputs: BranchExecutionInputs;
|
|
11
|
+
origin: string;
|
|
12
|
+
resume?: boolean;
|
|
13
|
+
onEvent?: (event: BranchExecutionEvent) => void;
|
|
14
|
+
dispatch?: BranchDispatchTuning;
|
|
15
|
+
packageTimeoutMs?: number;
|
|
16
|
+
/** Pages converting at once. The account's admission cap is the real limit. */
|
|
17
|
+
pageConcurrency?: number;
|
|
18
|
+
signal?: AbortSignal;
|
|
19
|
+
}) => Promise<BranchExecutionResult>;
|
|
20
|
+
//# sourceMappingURL=branch-execution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branch-execution.d.ts","sourceRoot":"","sources":["../src/branch-execution.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,oBAAoB,CAAC;AA2B5B,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,2BAA2B,CAAC;AAgBnC,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,qBAAqB,CAAC;AAC3E,OAAO,KAAK,EACV,oBAAoB,EACpB,qBAAqB,EACrB,qBAAqB,EACtB,MAAM,6BAA6B,CAAC;AAErC,YAAY,EACV,oBAAoB,EACpB,qBAAqB,EACrB,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,6BAA6B,CAAC;AAiBrC,eAAO,MAAM,kBAAkB,GAAI,QAAQ,qBAAqB,KAAG,MAQlE,CAAC;AAkCF,eAAO,MAAM,gBAAgB,GAAU,MAAM;IAC3C,YAAY,EAAE,oBAAoB,CAAC;IACnC,aAAa,CAAC,EAAE,+BAA+B,CAAC;IAChD,MAAM,EAAE,qBAAqB,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAChD,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,+EAA+E;IAC/E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,KAAG,OAAO,CAAC,qBAAqB,CAwVhC,CAAC"}
|
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { BranchApiError, } from './branch-client.js';
|
|
3
|
+
import { branchConceptDigest, branchRunKey } from './branch-identity.js';
|
|
4
|
+
import { buildCompletion, terminalFailure } from './branch-completion.js';
|
|
5
|
+
import { createRunMaterializer } from './branch-materialize.js';
|
|
6
|
+
import { branchScreenPath } from './branch-downloads.js';
|
|
7
|
+
import { createBranchPageConversions } from './branch-page-conversion.js';
|
|
8
|
+
import { invalidateConversionReceipts, readConversionReceipts, writeConversionReceipts, } from './conversion-receipt.js';
|
|
9
|
+
import { BRANCH_PAGE_CONCURRENCY_DEFAULT } from './cli-progress.js';
|
|
10
|
+
import { applyBranchEnvelope, normalizeBranchPlan, } from './branch-plan.js';
|
|
11
|
+
import { branchProgressPath, branchProgressScreens, writeBranchProgress, } from './branch-progress.js';
|
|
12
|
+
import { runBranchDispatch, } from './branch-dispatch-loop.js';
|
|
13
|
+
import { BRANCH_ATTEMPT_FILENAME, BRANCH_PAGES_DIRECTORY, BRANCH_SCREENS_DIRECTORY, branchAttemptPath, branchCompletionPath, branchPlanPath, readBranchAttempt, readBranchCompletion, writeBranchAttempt, writeBranchCompletion, writeBranchPlanRecord, } from './branch-run-record.js';
|
|
14
|
+
/**
|
|
15
|
+
* The whole branch choreography: claim, plan, dependency-ordered dispatch,
|
|
16
|
+
* download, per-page package conversion, sentinel. Everything mechanical lives
|
|
17
|
+
* here so the model's job collapses to choosing the winner, writing the
|
|
18
|
+
* concept, and picking the scope.
|
|
19
|
+
*
|
|
20
|
+
* The two halves overlap on purpose. A page's package depends on ITS OWN
|
|
21
|
+
* screens and nothing else, so a page whose screens land in the first wave
|
|
22
|
+
* starts converting while the rest of the run is still generating, and pages
|
|
23
|
+
* convert several at a time. Measured serially, the conversion half was 8m36 of
|
|
24
|
+
* a 12m25 four-page run while the account's admission slots sat idle.
|
|
25
|
+
*/
|
|
26
|
+
const BUILD_PLAN_RETRIES = 3;
|
|
27
|
+
export const deriveBranchRunKey = (inputs) => (inputs.idempotencyKey ?? branchRunKey({
|
|
28
|
+
winner: inputs.winner.kind === 'run'
|
|
29
|
+
? { runId: inputs.winner.runId, slot: inputs.winner.slot }
|
|
30
|
+
: { imageSha256: inputs.winner.sha256 },
|
|
31
|
+
concept: inputs.concept,
|
|
32
|
+
scope: inputs.scope,
|
|
33
|
+
}));
|
|
34
|
+
const claimBuildRun = async (args) => {
|
|
35
|
+
let lastError;
|
|
36
|
+
for (let attempt = 1; attempt <= BUILD_PLAN_RETRIES; attempt += 1) {
|
|
37
|
+
try {
|
|
38
|
+
return await args.client.startBuildRun({
|
|
39
|
+
concept: args.inputs.concept,
|
|
40
|
+
...(args.inputs.aspect ? { aspect: args.inputs.aspect } : {}),
|
|
41
|
+
...(args.inputs.winner.kind === 'run'
|
|
42
|
+
? { winner: { createRunId: args.inputs.winner.runId, slot: args.inputs.winner.slot } }
|
|
43
|
+
: {
|
|
44
|
+
referenceImage: {
|
|
45
|
+
data: Buffer.from(args.inputs.winner.bytes).toString('base64'),
|
|
46
|
+
mediaType: args.inputs.winner.mediaType,
|
|
47
|
+
sha256: args.inputs.winner.sha256,
|
|
48
|
+
},
|
|
49
|
+
}),
|
|
50
|
+
}, args.runKey, args.signal);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
lastError = error;
|
|
54
|
+
// Planning failed before any image spend, so the same key may replay.
|
|
55
|
+
const retryable = error instanceof BranchApiError && error.code === 'build_plan_failed';
|
|
56
|
+
if (!retryable || attempt === BUILD_PLAN_RETRIES)
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
throw lastError;
|
|
61
|
+
};
|
|
62
|
+
export const executeBranchRun = async (args) => {
|
|
63
|
+
const emit = args.onEvent ?? (() => undefined);
|
|
64
|
+
const { inputs } = args;
|
|
65
|
+
const outDir = path.resolve(inputs.outDir);
|
|
66
|
+
const attemptFile = branchAttemptPath(outDir);
|
|
67
|
+
const completionFile = branchCompletionPath(outDir);
|
|
68
|
+
const screensDirectory = path.join(outDir, BRANCH_SCREENS_DIRECTORY);
|
|
69
|
+
const pagesDirectory = path.join(outDir, BRANCH_PAGES_DIRECTORY);
|
|
70
|
+
const runKey = deriveBranchRunKey(inputs);
|
|
71
|
+
const startedAt = new Date().toISOString();
|
|
72
|
+
const progressFile = branchProgressPath(outDir);
|
|
73
|
+
// Progress writes are serialized AND coalesced: the file is the one thing
|
|
74
|
+
// another session polls, so it must never be observed half-written, and a
|
|
75
|
+
// fast loop must not queue an unbounded backlog of stale snapshots. Only the
|
|
76
|
+
// newest pending snapshot is ever written.
|
|
77
|
+
let pendingProgress = null;
|
|
78
|
+
let progressWrites = Promise.resolve();
|
|
79
|
+
let progressWriting = false;
|
|
80
|
+
const drainProgress = () => {
|
|
81
|
+
if (progressWriting || !pendingProgress)
|
|
82
|
+
return;
|
|
83
|
+
progressWriting = true;
|
|
84
|
+
const record = pendingProgress;
|
|
85
|
+
pendingProgress = null;
|
|
86
|
+
progressWrites = writeBranchProgress(progressFile, record)
|
|
87
|
+
.catch(() => undefined)
|
|
88
|
+
.finally(() => {
|
|
89
|
+
progressWriting = false;
|
|
90
|
+
drainProgress();
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
// The record is assembled from the run's current state rather than from each
|
|
94
|
+
// caller's arguments, because two different things move it — the screens and
|
|
95
|
+
// the packages — and a writer that knew only its own half would erase the
|
|
96
|
+
// other's.
|
|
97
|
+
const packageProgress = new Map();
|
|
98
|
+
let progressPhase = 'claiming';
|
|
99
|
+
let progressRunId = '';
|
|
100
|
+
let progressScreens = [];
|
|
101
|
+
const publish = () => {
|
|
102
|
+
pendingProgress = {
|
|
103
|
+
version: 1,
|
|
104
|
+
runId: progressRunId,
|
|
105
|
+
phase: progressPhase,
|
|
106
|
+
startedAt,
|
|
107
|
+
updatedAt: new Date().toISOString(),
|
|
108
|
+
screens: progressScreens,
|
|
109
|
+
...(packageProgress.size > 0 ? { packages: [...packageProgress.values()] } : {}),
|
|
110
|
+
};
|
|
111
|
+
drainProgress();
|
|
112
|
+
};
|
|
113
|
+
const publishProgress = (phase, runId, screens) => {
|
|
114
|
+
emit({ kind: 'progress', phase, screens });
|
|
115
|
+
progressPhase = phase;
|
|
116
|
+
progressRunId = runId;
|
|
117
|
+
progressScreens = screens;
|
|
118
|
+
publish();
|
|
119
|
+
};
|
|
120
|
+
const finished = await readBranchCompletion(completionFile);
|
|
121
|
+
if (finished) {
|
|
122
|
+
throw new Error(`This branch run already completed: ${completionFile} names run ${finished.runId},`
|
|
123
|
+
+ ` ${finished.succeededCount} succeeded screen(s), and every page's conversion. Read it`
|
|
124
|
+
+ ' rather than running the branch again, or choose a new --out-dir to start a new run.');
|
|
125
|
+
}
|
|
126
|
+
const existing = await readBranchAttempt(attemptFile);
|
|
127
|
+
if (existing && !args.resume) {
|
|
128
|
+
throw new Error(`Branch attempt evidence already exists at ${attemptFile} for run`
|
|
129
|
+
+ ` ${existing.runId ?? '(unclaimed)'}. Re-run the identical command with --resume to`
|
|
130
|
+
+ ' continue it: a resume replays every settled screen for free and re-dispatches only'
|
|
131
|
+
+ ' what is still pending. It can never buy a screen twice.');
|
|
132
|
+
}
|
|
133
|
+
if (!existing && args.resume) {
|
|
134
|
+
// Never started, so nothing failed. This answers in a different register
|
|
135
|
+
// from a recovery report on purpose: a caller told "0 recovered" about work
|
|
136
|
+
// it never asked for concludes the service is broken and gives up.
|
|
137
|
+
throw new Error(`This branch run has never been started — there is nothing to resume, and nothing has`
|
|
138
|
+
+ ` failed. There is no ${BRANCH_ATTEMPT_FILENAME} in ${outDir}. Run the same command`
|
|
139
|
+
+ ' without --resume to start it; it blocks for the whole run and streams progress.');
|
|
140
|
+
}
|
|
141
|
+
if (existing && existing.runKey !== runKey) {
|
|
142
|
+
throw new Error(`Refusing to resume: ${outDir} holds run key ${existing.runKey} but these inputs derive`
|
|
143
|
+
+ ` ${runKey}. A resume must replay the same winner, concept, and scope.`);
|
|
144
|
+
}
|
|
145
|
+
const attempt = existing ?? {
|
|
146
|
+
version: 1,
|
|
147
|
+
status: 'claiming',
|
|
148
|
+
runKey,
|
|
149
|
+
origin: args.origin,
|
|
150
|
+
scope: inputs.scope,
|
|
151
|
+
concept: inputs.concept,
|
|
152
|
+
conceptSha256: branchConceptDigest(inputs.concept),
|
|
153
|
+
winner: inputs.winner.kind === 'run'
|
|
154
|
+
? { kind: 'run', runId: inputs.winner.runId, slot: inputs.winner.slot }
|
|
155
|
+
: {
|
|
156
|
+
kind: 'image',
|
|
157
|
+
imagePath: inputs.winner.imagePath,
|
|
158
|
+
sha256: inputs.winner.sha256,
|
|
159
|
+
mediaType: inputs.winner.mediaType,
|
|
160
|
+
},
|
|
161
|
+
...(inputs.aspect ? { aspect: inputs.aspect } : {}),
|
|
162
|
+
...(inputs.maxScreens === undefined ? {} : { maxScreens: inputs.maxScreens }),
|
|
163
|
+
...(inputs.convert
|
|
164
|
+
? {
|
|
165
|
+
convert: {
|
|
166
|
+
output: inputs.convert.output,
|
|
167
|
+
model: inputs.convert.model ?? 'standard',
|
|
168
|
+
...(inputs.convert.responsiveQuality
|
|
169
|
+
? { responsiveQuality: inputs.convert.responsiveQuality }
|
|
170
|
+
: {}),
|
|
171
|
+
},
|
|
172
|
+
}
|
|
173
|
+
: {}),
|
|
174
|
+
...(inputs.convert?.sourceConversionId
|
|
175
|
+
? { sourceConversionId: inputs.convert.sourceConversionId }
|
|
176
|
+
: {}),
|
|
177
|
+
createdAt: startedAt,
|
|
178
|
+
};
|
|
179
|
+
if (existing) {
|
|
180
|
+
attempt.resumedAt = [...(attempt.resumedAt ?? []), startedAt];
|
|
181
|
+
await writeBranchAttempt(attemptFile, attempt);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
await writeBranchAttempt(attemptFile, attempt, true);
|
|
185
|
+
}
|
|
186
|
+
emit({ kind: 'phase', phase: 'claim', detail: 'planning the screens (10-20s, buys no image)' });
|
|
187
|
+
const envelope = attempt.runId
|
|
188
|
+
? await args.branchClient.getRun(attempt.runId, args.signal)
|
|
189
|
+
: await claimBuildRun({
|
|
190
|
+
client: args.branchClient,
|
|
191
|
+
inputs,
|
|
192
|
+
runKey,
|
|
193
|
+
...(args.signal ? { signal: args.signal } : {}),
|
|
194
|
+
});
|
|
195
|
+
attempt.runId = envelope.id;
|
|
196
|
+
attempt.status = 'dispatching';
|
|
197
|
+
await writeBranchAttempt(attemptFile, attempt);
|
|
198
|
+
let plan = normalizeBranchPlan(envelope, {
|
|
199
|
+
scope: inputs.scope,
|
|
200
|
+
...(inputs.maxScreens === undefined ? {} : { maxScreens: inputs.maxScreens }),
|
|
201
|
+
});
|
|
202
|
+
await writeBranchPlanRecord(branchPlanPath(outDir), plan);
|
|
203
|
+
emit({
|
|
204
|
+
kind: 'phase',
|
|
205
|
+
phase: 'plan',
|
|
206
|
+
detail: `${plan.pages.length} page(s), ${plan.screens.length} screen(s) to generate`,
|
|
207
|
+
});
|
|
208
|
+
const convert = inputs.convert;
|
|
209
|
+
const packageClient = args.packageClient;
|
|
210
|
+
// Refused before the run buys anything rather than after every screen is paid
|
|
211
|
+
// for: a run that cannot convert should never have generated.
|
|
212
|
+
if (convert && !packageClient)
|
|
213
|
+
throw new Error('A conversion package client is required for --convert');
|
|
214
|
+
const needsWinner = Boolean(convert) && plan.pages.some((page) => page.startsFromWinner);
|
|
215
|
+
const materializer = createRunMaterializer({
|
|
216
|
+
client: args.branchClient,
|
|
217
|
+
runId: envelope.id,
|
|
218
|
+
inputs,
|
|
219
|
+
screensDirectory,
|
|
220
|
+
...(args.signal ? { signal: args.signal } : {}),
|
|
221
|
+
});
|
|
222
|
+
// The approved design is gated by nothing the run generates, so its bytes are
|
|
223
|
+
// fetched alongside dispatch instead of after it. The rejection is handled
|
|
224
|
+
// where it is awaited — as the source page's own conversion failure.
|
|
225
|
+
const winnerBytes = needsWinner ? materializer.winner() : null;
|
|
226
|
+
winnerBytes?.catch(() => undefined);
|
|
227
|
+
const winnerReceiptTargets = [
|
|
228
|
+
branchScreenPath(screensDirectory, 'winner'),
|
|
229
|
+
...(inputs.winner.kind === 'image' ? [inputs.winner.imagePath] : []),
|
|
230
|
+
];
|
|
231
|
+
const winnerReceipts = convert ? await readConversionReceipts(winnerReceiptTargets) : [];
|
|
232
|
+
/**
|
|
233
|
+
* Receipt work runs one at a time. Withdrawing a disproven receipt and
|
|
234
|
+
* writing the receipt for the conversion bought in its place touch the same
|
|
235
|
+
* file, so their order is what decides whether the run ends holding the proof
|
|
236
|
+
* it just paid for or holding nothing. Serializing costs nothing — these are
|
|
237
|
+
* two small writes per run — and removes the question.
|
|
238
|
+
*/
|
|
239
|
+
const receiptWrites = [];
|
|
240
|
+
const queueReceiptWork = (work) => {
|
|
241
|
+
const previous = receiptWrites[receiptWrites.length - 1] ?? Promise.resolve();
|
|
242
|
+
receiptWrites.push(previous.then(work, work));
|
|
243
|
+
};
|
|
244
|
+
const pages = convert && packageClient
|
|
245
|
+
? createBranchPageConversions({
|
|
246
|
+
client: packageClient,
|
|
247
|
+
settings: convert,
|
|
248
|
+
pagesDirectory,
|
|
249
|
+
winnerReceipts,
|
|
250
|
+
concurrency: args.pageConcurrency ?? BRANCH_PAGE_CONCURRENCY_DEFAULT,
|
|
251
|
+
...(args.packageTimeoutMs === undefined ? {} : { timeoutMs: args.packageTimeoutMs }),
|
|
252
|
+
prepare: async (page, livePlan) => {
|
|
253
|
+
const delivered = await materializer.ensure(livePlan.screens
|
|
254
|
+
.filter((screen) => page.slots.includes(screen.slot) && screen.status === 'succeeded')
|
|
255
|
+
.map((screen) => screen.slot));
|
|
256
|
+
const winner = page.startsFromWinner && winnerBytes ? await winnerBytes : undefined;
|
|
257
|
+
return { screens: delivered, ...(winner ? { winner } : {}) };
|
|
258
|
+
},
|
|
259
|
+
onProgress: (pageId, progress) => {
|
|
260
|
+
emit({ kind: 'package', pageId, progress });
|
|
261
|
+
packageProgress.set(pageId, {
|
|
262
|
+
pageId,
|
|
263
|
+
...progress,
|
|
264
|
+
updatedAt: new Date().toISOString(),
|
|
265
|
+
});
|
|
266
|
+
publish();
|
|
267
|
+
},
|
|
268
|
+
// The server read the referenced conversion's durable evidence and
|
|
269
|
+
// refused the claim, so the receipt it came from is no longer proof of
|
|
270
|
+
// anything. Withdrawing it here is what keeps the next run from paying
|
|
271
|
+
// the same refused-then-retried round trip.
|
|
272
|
+
onReuseDisproven: (disproof) => {
|
|
273
|
+
emit({
|
|
274
|
+
kind: 'phase',
|
|
275
|
+
phase: 'convert',
|
|
276
|
+
detail: `the recorded conversion ${disproof.conversionId} is no longer attachable`
|
|
277
|
+
+ ` (${disproof.detail}); converting that screen again and forgetting the receipt`,
|
|
278
|
+
});
|
|
279
|
+
queueReceiptWork(async () => await invalidateConversionReceipts(winnerReceiptTargets, disproof.conversionId));
|
|
280
|
+
},
|
|
281
|
+
onWinnerConversion: (conversion) => {
|
|
282
|
+
const createdAt = new Date().toISOString();
|
|
283
|
+
queueReceiptWork(async () => await writeConversionReceipts(winnerReceiptTargets, {
|
|
284
|
+
version: 1,
|
|
285
|
+
sha256: conversion.sha256,
|
|
286
|
+
conversionId: conversion.conversionId,
|
|
287
|
+
model: conversion.model,
|
|
288
|
+
boughtBy: envelope.id,
|
|
289
|
+
expiresAt: conversion.expiresAt,
|
|
290
|
+
createdAt,
|
|
291
|
+
}));
|
|
292
|
+
},
|
|
293
|
+
...(args.signal ? { signal: args.signal } : {}),
|
|
294
|
+
})
|
|
295
|
+
: null;
|
|
296
|
+
/** A page converts the moment ITS OWN screens have all landed. */
|
|
297
|
+
const convertWholePages = (livePlan) => {
|
|
298
|
+
for (const page of livePlan.pages) {
|
|
299
|
+
const own = livePlan.screens.filter((screen) => page.slots.includes(screen.slot));
|
|
300
|
+
if (own.length === 0 || !own.every((screen) => screen.status === 'succeeded'))
|
|
301
|
+
continue;
|
|
302
|
+
pages?.start(livePlan, page);
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
let stopped = null;
|
|
306
|
+
publishProgress('dispatching', envelope.id, branchProgressScreens(plan, {}));
|
|
307
|
+
if (plan.screens.length > 0) {
|
|
308
|
+
const dispatched = await runBranchDispatch({
|
|
309
|
+
client: args.branchClient,
|
|
310
|
+
plan,
|
|
311
|
+
onEvent: emit,
|
|
312
|
+
onSnapshot: (snapshot) => {
|
|
313
|
+
publishProgress('dispatching', envelope.id, branchProgressScreens(snapshot.plan, snapshot.dispatchedAt));
|
|
314
|
+
convertWholePages(snapshot.plan);
|
|
315
|
+
},
|
|
316
|
+
...(args.signal ? { signal: args.signal } : {}),
|
|
317
|
+
...(args.dispatch ?? {}),
|
|
318
|
+
});
|
|
319
|
+
plan = dispatched.plan;
|
|
320
|
+
stopped = dispatched.stopped;
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
plan = applyBranchEnvelope(plan, envelope);
|
|
324
|
+
}
|
|
325
|
+
attempt.status = 'downloading';
|
|
326
|
+
publishProgress('downloading', envelope.id, branchProgressScreens(plan, {}));
|
|
327
|
+
await writeBranchAttempt(attemptFile, attempt);
|
|
328
|
+
const screens = await materializer.ensure(plan.screens
|
|
329
|
+
.filter((screen) => screen.status === 'succeeded')
|
|
330
|
+
.map((screen) => screen.slot));
|
|
331
|
+
// The winner's staged bytes have to be in hand before the atomic pass, or the
|
|
332
|
+
// pass would leave them undelivered under a path the completion names.
|
|
333
|
+
if (winnerBytes)
|
|
334
|
+
await winnerBytes.catch(() => undefined);
|
|
335
|
+
await materializer.finish();
|
|
336
|
+
emit({ kind: 'phase', phase: 'download', detail: `${screens.size} screen(s) on disk` });
|
|
337
|
+
if (convert && !stopped) {
|
|
338
|
+
attempt.status = 'converting';
|
|
339
|
+
publishProgress('converting', envelope.id, branchProgressScreens(plan, {}));
|
|
340
|
+
await writeBranchAttempt(attemptFile, attempt);
|
|
341
|
+
emit({
|
|
342
|
+
kind: 'phase',
|
|
343
|
+
phase: 'convert',
|
|
344
|
+
detail: `one package conversion per whole page, up to ${args.pageConcurrency ?? BRANCH_PAGE_CONCURRENCY_DEFAULT} at a time`,
|
|
345
|
+
});
|
|
346
|
+
for (const page of plan.pages)
|
|
347
|
+
pages?.start(plan, page);
|
|
348
|
+
}
|
|
349
|
+
// Every page settles, including any that started while screens were still
|
|
350
|
+
// generating: paid work in flight is never abandoned.
|
|
351
|
+
const conversions = await pages?.settled() ?? new Map();
|
|
352
|
+
await Promise.allSettled(receiptWrites);
|
|
353
|
+
const winner = winnerBytes ? await winnerBytes.catch(() => undefined) : undefined;
|
|
354
|
+
const completion = buildCompletion({
|
|
355
|
+
plan,
|
|
356
|
+
inputs,
|
|
357
|
+
runKey,
|
|
358
|
+
origin: args.origin,
|
|
359
|
+
outDir,
|
|
360
|
+
attemptFile,
|
|
361
|
+
startedAt,
|
|
362
|
+
screens,
|
|
363
|
+
...(winner ? { winner } : {}),
|
|
364
|
+
conversions,
|
|
365
|
+
stopped,
|
|
366
|
+
});
|
|
367
|
+
publishProgress('terminal', envelope.id, branchProgressScreens(plan, {}));
|
|
368
|
+
await progressWrites;
|
|
369
|
+
await writeBranchCompletion(completionFile, completion);
|
|
370
|
+
attempt.status = completion.status;
|
|
371
|
+
attempt.completedAt = completion.completedAt;
|
|
372
|
+
attempt.completionPath = completionFile;
|
|
373
|
+
await writeBranchAttempt(attemptFile, attempt);
|
|
374
|
+
return {
|
|
375
|
+
completion,
|
|
376
|
+
completionPath: completionFile,
|
|
377
|
+
failure: terminalFailure({ completion, stopped, completionFile, convert: Boolean(inputs.convert) }),
|
|
378
|
+
};
|
|
379
|
+
};
|
|
380
|
+
//# sourceMappingURL=branch-execution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branch-execution.js","sourceRoot":"","sources":["../src/branch-execution.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every identity a branch run needs, derived from its inputs rather than
|
|
3
|
+
* authored. Free-text keys are load-bearing in both directions here: the same
|
|
4
|
+
* key with a changed body wedges the claim with `409 idempotency_conflict`, and
|
|
5
|
+
* a NEW key on a settled slot buys another image. Deriving them removes both
|
|
6
|
+
* failure modes from the agent's hands.
|
|
7
|
+
*
|
|
8
|
+
* Digests are truncated because `Idempotency-Key` is capped at 128 printable
|
|
9
|
+
* characters and a run id alone is 44 of them. 16 hex characters is 64 bits of
|
|
10
|
+
* collision resistance over inputs that are already scoped by run id, which is
|
|
11
|
+
* far more than the number of runs any account will ever hold.
|
|
12
|
+
*/
|
|
13
|
+
export declare const BRANCH_WORKFLOW_REVISION = "branch-execute-v1";
|
|
14
|
+
export type BranchScope = 'page' | 'site';
|
|
15
|
+
export declare const branchConceptDigest: (concept: string) => string;
|
|
16
|
+
/**
|
|
17
|
+
* Same inputs -> same run, so an interrupted claim replays instead of starting
|
|
18
|
+
* a second one. A changed concept is a different design problem and therefore a
|
|
19
|
+
* different run, so it derives a new key rather than wedging the old one.
|
|
20
|
+
*/
|
|
21
|
+
export declare const branchRunKey: (args: {
|
|
22
|
+
winner: {
|
|
23
|
+
runId: string;
|
|
24
|
+
slot: string;
|
|
25
|
+
} | {
|
|
26
|
+
imageSha256: string;
|
|
27
|
+
};
|
|
28
|
+
concept: string;
|
|
29
|
+
scope: BranchScope;
|
|
30
|
+
}) => string;
|
|
31
|
+
/**
|
|
32
|
+
* The ONLY keyed dispatch. Automatic dispatch is unkeyed so every replay is
|
|
33
|
+
* free; a redraw is an explicit request for one further paid attempt and needs
|
|
34
|
+
* a key the settled slot has never seen.
|
|
35
|
+
*/
|
|
36
|
+
export declare const branchRedrawKey: (args: {
|
|
37
|
+
runId: string;
|
|
38
|
+
slot: string;
|
|
39
|
+
attempt: number;
|
|
40
|
+
}) => string;
|
|
41
|
+
/**
|
|
42
|
+
* Stable under retry and distinct per page. Keying on the ordered viewport
|
|
43
|
+
* hashes means a resumed run that downloaded the same bytes replays the same
|
|
44
|
+
* package rather than buying a second one, while a redrawn screen produces a
|
|
45
|
+
* genuinely different page and therefore a genuinely different key.
|
|
46
|
+
*/
|
|
47
|
+
export declare const branchPackageKey: (args: {
|
|
48
|
+
runId: string;
|
|
49
|
+
pageIndex: number;
|
|
50
|
+
viewportSha256s: readonly string[];
|
|
51
|
+
output: string;
|
|
52
|
+
model?: string;
|
|
53
|
+
responsiveQuality?: string;
|
|
54
|
+
}) => string;
|
|
55
|
+
/** Standalone `convert package` runs derive from the manifest they were given. */
|
|
56
|
+
export declare const conversionPackageKey: (args: {
|
|
57
|
+
manifestSha256: string;
|
|
58
|
+
output: string;
|
|
59
|
+
}) => string;
|
|
60
|
+
/**
|
|
61
|
+
* Standalone `export` runs derive from the conversion they re-render. The
|
|
62
|
+
* export command appends the output and a digest of the request body to this
|
|
63
|
+
* base, so the base only has to pin the source: exporting the same conversion
|
|
64
|
+
* to the same format twice is the same paid work and must replay rather than
|
|
65
|
+
* buy it again, while a different format or profile lands on a different key
|
|
66
|
+
* through the suffix.
|
|
67
|
+
*/
|
|
68
|
+
export declare const conversionExportKey: (args: {
|
|
69
|
+
sourceConversionId: string;
|
|
70
|
+
}) => string;
|
|
71
|
+
//# sourceMappingURL=branch-identity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branch-identity.d.ts","sourceRoot":"","sources":["../src/branch-identity.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,eAAO,MAAM,wBAAwB,sBAAsB,CAAC;AAE5D,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,CAAC;AAM1C,eAAO,MAAM,mBAAmB,GAAI,SAAS,MAAM,KAAG,MAErD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM;IACjC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAClE,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,WAAW,CAAC;CACpB,KAAG,MAYH,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB,KAAG,MAAoE,CAAC;AAEzE;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,MAAM;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,KAAG,MAaO,CAAC;AAEZ,kFAAkF;AAClF,eAAO,MAAM,oBAAoB,GAAI,MAAM;IACzC,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB,KAAG,MAAiF,CAAC;AAEtF;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,GAAI,MAAM;IACxC,kBAAkB,EAAE,MAAM,CAAC;CAC5B,KAAG,MAAwD,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
/**
|
|
3
|
+
* Every identity a branch run needs, derived from its inputs rather than
|
|
4
|
+
* authored. Free-text keys are load-bearing in both directions here: the same
|
|
5
|
+
* key with a changed body wedges the claim with `409 idempotency_conflict`, and
|
|
6
|
+
* a NEW key on a settled slot buys another image. Deriving them removes both
|
|
7
|
+
* failure modes from the agent's hands.
|
|
8
|
+
*
|
|
9
|
+
* Digests are truncated because `Idempotency-Key` is capped at 128 printable
|
|
10
|
+
* characters and a run id alone is 44 of them. 16 hex characters is 64 bits of
|
|
11
|
+
* collision resistance over inputs that are already scoped by run id, which is
|
|
12
|
+
* far more than the number of runs any account will ever hold.
|
|
13
|
+
*/
|
|
14
|
+
export const BRANCH_WORKFLOW_REVISION = 'branch-execute-v1';
|
|
15
|
+
const shortDigest = (value, characters = 16) => (createHash('sha256').update(value).digest('hex').slice(0, characters));
|
|
16
|
+
export const branchConceptDigest = (concept) => (createHash('sha256').update(concept).digest('hex'));
|
|
17
|
+
/**
|
|
18
|
+
* Same inputs -> same run, so an interrupted claim replays instead of starting
|
|
19
|
+
* a second one. A changed concept is a different design problem and therefore a
|
|
20
|
+
* different run, so it derives a new key rather than wedging the old one.
|
|
21
|
+
*/
|
|
22
|
+
export const branchRunKey = (args) => {
|
|
23
|
+
const origin = 'runId' in args.winner
|
|
24
|
+
? `${args.winner.runId}:${args.winner.slot}`
|
|
25
|
+
: `img-${args.winner.imageSha256.slice(0, 32)}:-`;
|
|
26
|
+
return [
|
|
27
|
+
'branch',
|
|
28
|
+
'v1',
|
|
29
|
+
origin,
|
|
30
|
+
shortDigest(args.concept),
|
|
31
|
+
args.scope,
|
|
32
|
+
BRANCH_WORKFLOW_REVISION,
|
|
33
|
+
].join(':');
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* The ONLY keyed dispatch. Automatic dispatch is unkeyed so every replay is
|
|
37
|
+
* free; a redraw is an explicit request for one further paid attempt and needs
|
|
38
|
+
* a key the settled slot has never seen.
|
|
39
|
+
*/
|
|
40
|
+
export const branchRedrawKey = (args) => `branch-screen:${args.runId}:${args.slot}:${args.attempt}`;
|
|
41
|
+
/**
|
|
42
|
+
* Stable under retry and distinct per page. Keying on the ordered viewport
|
|
43
|
+
* hashes means a resumed run that downloaded the same bytes replays the same
|
|
44
|
+
* package rather than buying a second one, while a redrawn screen produces a
|
|
45
|
+
* genuinely different page and therefore a genuinely different key.
|
|
46
|
+
*/
|
|
47
|
+
export const branchPackageKey = (args) => [
|
|
48
|
+
'branch-package',
|
|
49
|
+
'v1',
|
|
50
|
+
args.runId,
|
|
51
|
+
String(args.pageIndex),
|
|
52
|
+
shortDigest(args.viewportSha256s.join('.'), 32),
|
|
53
|
+
args.output,
|
|
54
|
+
// Everything that changes the request body has to be in the key. Model and
|
|
55
|
+
// quality are body fields, so leaving them out turns a deliberate change of
|
|
56
|
+
// model into `409 idempotency_conflict` on a page that was never bought —
|
|
57
|
+
// measured against production while smoke-testing this command.
|
|
58
|
+
args.model ?? 'standard',
|
|
59
|
+
args.responsiveQuality ?? 'default',
|
|
60
|
+
].join(':');
|
|
61
|
+
/** Standalone `convert package` runs derive from the manifest they were given. */
|
|
62
|
+
export const conversionPackageKey = (args) => `convert-package:v1:${args.manifestSha256.slice(0, 32)}:${args.output}`;
|
|
63
|
+
/**
|
|
64
|
+
* Standalone `export` runs derive from the conversion they re-render. The
|
|
65
|
+
* export command appends the output and a digest of the request body to this
|
|
66
|
+
* base, so the base only has to pin the source: exporting the same conversion
|
|
67
|
+
* to the same format twice is the same paid work and must replay rather than
|
|
68
|
+
* buy it again, while a different format or profile lands on a different key
|
|
69
|
+
* through the suffix.
|
|
70
|
+
*/
|
|
71
|
+
export const conversionExportKey = (args) => `convert-export:v1:${args.sourceConversionId}`;
|
|
72
|
+
//# sourceMappingURL=branch-identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branch-identity.js","sourceRoot":"","sources":["../src/branch-identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;;;;;;;GAWG;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAAG,mBAAmB,CAAC;AAI5D,MAAM,WAAW,GAAG,CAAC,KAAa,EAAE,UAAU,GAAG,EAAE,EAAU,EAAE,CAAC,CAC9D,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CACtE,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,OAAe,EAAU,EAAE,CAAC,CAC9D,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CACnD,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,IAI5B,EAAU,EAAE;IACX,MAAM,MAAM,GAAG,OAAO,IAAI,IAAI,CAAC,MAAM;QACnC,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;QAC5C,CAAC,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC;IACpD,OAAO;QACL,QAAQ;QACR,IAAI;QACJ,MAAM;QACN,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC;QACzB,IAAI,CAAC,KAAK;QACV,wBAAwB;KACzB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,IAI/B,EAAU,EAAE,CAAC,iBAAiB,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;AAEzE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAOhC,EAAU,EAAE,CAAC;IACZ,gBAAgB;IAChB,IAAI;IACJ,IAAI,CAAC,KAAK;IACV,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;IACtB,WAAW,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;IAC/C,IAAI,CAAC,MAAM;IACX,2EAA2E;IAC3E,4EAA4E;IAC5E,0EAA0E;IAC1E,gEAAgE;IAChE,IAAI,CAAC,KAAK,IAAI,UAAU;IACxB,IAAI,CAAC,iBAAiB,IAAI,SAAS;CACpC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,kFAAkF;AAClF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,IAGpC,EAAU,EAAE,CAAC,sBAAsB,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;AAEtF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,IAEnC,EAAU,EAAE,CAAC,qBAAqB,IAAI,CAAC,kBAAkB,EAAE,CAAC"}
|