@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.
Files changed (188) hide show
  1. package/README.md +35 -9
  2. package/dist/bounded-concurrency.d.ts +13 -0
  3. package/dist/bounded-concurrency.d.ts.map +1 -0
  4. package/dist/bounded-concurrency.js +43 -0
  5. package/dist/bounded-concurrency.js.map +1 -0
  6. package/dist/branch-client.d.ts +155 -0
  7. package/dist/branch-client.d.ts.map +1 -0
  8. package/dist/branch-client.js +179 -0
  9. package/dist/branch-client.js.map +1 -0
  10. package/dist/branch-completion.d.ts +37 -0
  11. package/dist/branch-completion.d.ts.map +1 -0
  12. package/dist/branch-completion.js +137 -0
  13. package/dist/branch-completion.js.map +1 -0
  14. package/dist/branch-dispatch-loop.d.ts +84 -0
  15. package/dist/branch-dispatch-loop.d.ts.map +1 -0
  16. package/dist/branch-dispatch-loop.js +206 -0
  17. package/dist/branch-dispatch-loop.js.map +1 -0
  18. package/dist/branch-downloads.d.ts +53 -0
  19. package/dist/branch-downloads.d.ts.map +1 -0
  20. package/dist/branch-downloads.js +114 -0
  21. package/dist/branch-downloads.js.map +1 -0
  22. package/dist/branch-execution-types.d.ts +54 -0
  23. package/dist/branch-execution-types.d.ts.map +1 -0
  24. package/dist/branch-execution-types.js +2 -0
  25. package/dist/branch-execution-types.js.map +1 -0
  26. package/dist/branch-execution.d.ts +20 -0
  27. package/dist/branch-execution.d.ts.map +1 -0
  28. package/dist/branch-execution.js +380 -0
  29. package/dist/branch-execution.js.map +1 -0
  30. package/dist/branch-identity.d.ts +71 -0
  31. package/dist/branch-identity.d.ts.map +1 -0
  32. package/dist/branch-identity.js +72 -0
  33. package/dist/branch-identity.js.map +1 -0
  34. package/dist/branch-materialize.d.ts +33 -0
  35. package/dist/branch-materialize.d.ts.map +1 -0
  36. package/dist/branch-materialize.js +64 -0
  37. package/dist/branch-materialize.js.map +1 -0
  38. package/dist/branch-page-conversion.d.ts +127 -0
  39. package/dist/branch-page-conversion.d.ts.map +1 -0
  40. package/dist/branch-page-conversion.js +382 -0
  41. package/dist/branch-page-conversion.js.map +1 -0
  42. package/dist/branch-plan.d.ts +63 -0
  43. package/dist/branch-plan.d.ts.map +1 -0
  44. package/dist/branch-plan.js +95 -0
  45. package/dist/branch-plan.js.map +1 -0
  46. package/dist/branch-progress.d.ts +99 -0
  47. package/dist/branch-progress.d.ts.map +1 -0
  48. package/dist/branch-progress.js +188 -0
  49. package/dist/branch-progress.js.map +1 -0
  50. package/dist/branch-run-record.d.ts +164 -0
  51. package/dist/branch-run-record.d.ts.map +1 -0
  52. package/dist/branch-run-record.js +94 -0
  53. package/dist/branch-run-record.js.map +1 -0
  54. package/dist/branch-schedule.d.ts +74 -0
  55. package/dist/branch-schedule.d.ts.map +1 -0
  56. package/dist/branch-schedule.js +130 -0
  57. package/dist/branch-schedule.js.map +1 -0
  58. package/dist/branch-status.d.ts +11 -0
  59. package/dist/branch-status.d.ts.map +1 -0
  60. package/dist/branch-status.js +118 -0
  61. package/dist/branch-status.js.map +1 -0
  62. package/dist/branch-viewport-normalization.d.ts +74 -0
  63. package/dist/branch-viewport-normalization.d.ts.map +1 -0
  64. package/dist/branch-viewport-normalization.js +120 -0
  65. package/dist/branch-viewport-normalization.js.map +1 -0
  66. package/dist/cli-arguments.d.ts.map +1 -1
  67. package/dist/cli-arguments.js +5 -0
  68. package/dist/cli-arguments.js.map +1 -1
  69. package/dist/cli-branch-command.d.ts +55 -0
  70. package/dist/cli-branch-command.d.ts.map +1 -0
  71. package/dist/cli-branch-command.js +475 -0
  72. package/dist/cli-branch-command.js.map +1 -0
  73. package/dist/cli-capabilities.d.ts +51 -0
  74. package/dist/cli-capabilities.d.ts.map +1 -1
  75. package/dist/cli-capabilities.js +52 -1
  76. package/dist/cli-capabilities.js.map +1 -1
  77. package/dist/cli-create-command.d.ts +21 -0
  78. package/dist/cli-create-command.d.ts.map +1 -0
  79. package/dist/cli-create-command.js +319 -0
  80. package/dist/cli-create-command.js.map +1 -0
  81. package/dist/cli-detach.d.ts +62 -0
  82. package/dist/cli-detach.d.ts.map +1 -0
  83. package/dist/cli-detach.js +123 -0
  84. package/dist/cli-detach.js.map +1 -0
  85. package/dist/cli-draft-command.d.ts +63 -0
  86. package/dist/cli-draft-command.d.ts.map +1 -0
  87. package/dist/cli-draft-command.js +220 -0
  88. package/dist/cli-draft-command.js.map +1 -0
  89. package/dist/cli-export-command.d.ts.map +1 -1
  90. package/dist/cli-export-command.js +2 -3
  91. package/dist/cli-export-command.js.map +1 -1
  92. package/dist/cli-image-batch-command.d.ts +21 -0
  93. package/dist/cli-image-batch-command.d.ts.map +1 -1
  94. package/dist/cli-image-batch-command.js +65 -4
  95. package/dist/cli-image-batch-command.js.map +1 -1
  96. package/dist/cli-image-batch-resume.d.ts +7 -0
  97. package/dist/cli-image-batch-resume.d.ts.map +1 -1
  98. package/dist/cli-image-batch-resume.js +19 -2
  99. package/dist/cli-image-batch-resume.js.map +1 -1
  100. package/dist/cli-package-command.d.ts +29 -0
  101. package/dist/cli-package-command.d.ts.map +1 -0
  102. package/dist/cli-package-command.js +128 -0
  103. package/dist/cli-package-command.js.map +1 -0
  104. package/dist/cli-progress.d.ts +137 -0
  105. package/dist/cli-progress.d.ts.map +1 -1
  106. package/dist/cli-progress.js +156 -0
  107. package/dist/cli-progress.js.map +1 -1
  108. package/dist/cli-select-command.d.ts +12 -0
  109. package/dist/cli-select-command.d.ts.map +1 -0
  110. package/dist/cli-select-command.js +66 -0
  111. package/dist/cli-select-command.js.map +1 -0
  112. package/dist/cli.js +150 -7
  113. package/dist/cli.js.map +1 -1
  114. package/dist/conversion-receipt.d.ts +127 -0
  115. package/dist/conversion-receipt.d.ts.map +1 -0
  116. package/dist/conversion-receipt.js +184 -0
  117. package/dist/conversion-receipt.js.map +1 -0
  118. package/dist/create-identity.d.ts +25 -0
  119. package/dist/create-identity.d.ts.map +1 -0
  120. package/dist/create-identity.js +0 -0
  121. package/dist/create-identity.js.map +1 -0
  122. package/dist/draft-identity.d.ts +30 -0
  123. package/dist/draft-identity.d.ts.map +1 -0
  124. package/dist/draft-identity.js +0 -0
  125. package/dist/draft-identity.js.map +1 -0
  126. package/dist/draft-prompts.d.ts +35 -0
  127. package/dist/draft-prompts.d.ts.map +1 -0
  128. package/dist/draft-prompts.js +51 -0
  129. package/dist/draft-prompts.js.map +1 -0
  130. package/dist/draft-run.d.ts +32 -0
  131. package/dist/draft-run.d.ts.map +1 -0
  132. package/dist/draft-run.js +152 -0
  133. package/dist/draft-run.js.map +1 -0
  134. package/dist/draft-workspace.d.ts +90 -0
  135. package/dist/draft-workspace.d.ts.map +1 -0
  136. package/dist/draft-workspace.js +64 -0
  137. package/dist/draft-workspace.js.map +1 -0
  138. package/dist/image-batch-status.d.ts +42 -0
  139. package/dist/image-batch-status.d.ts.map +1 -0
  140. package/dist/image-batch-status.js +142 -0
  141. package/dist/image-batch-status.js.map +1 -0
  142. package/dist/image-dimensions.d.ts +12 -0
  143. package/dist/image-dimensions.d.ts.map +1 -0
  144. package/dist/image-dimensions.js +14 -0
  145. package/dist/image-dimensions.js.map +1 -0
  146. package/dist/image-generation-resume.d.ts +13 -0
  147. package/dist/image-generation-resume.d.ts.map +1 -1
  148. package/dist/image-generation-resume.js +13 -0
  149. package/dist/image-generation-resume.js.map +1 -1
  150. package/dist/index.d.ts +6 -1
  151. package/dist/index.d.ts.map +1 -1
  152. package/dist/index.js +5 -1
  153. package/dist/index.js.map +1 -1
  154. package/dist/legacy-skill-catalog.d.ts.map +1 -1
  155. package/dist/legacy-skill-catalog.js +140 -0
  156. package/dist/legacy-skill-catalog.js.map +1 -1
  157. package/dist/package-client.d.ts +28 -0
  158. package/dist/package-client.d.ts.map +1 -1
  159. package/dist/package-client.js +21 -1
  160. package/dist/package-client.js.map +1 -1
  161. package/dist/package-manifest-file.d.ts +21 -0
  162. package/dist/package-manifest-file.d.ts.map +1 -0
  163. package/dist/package-manifest-file.js +119 -0
  164. package/dist/package-manifest-file.js.map +1 -0
  165. package/dist/package-manifest-template.d.ts +23 -0
  166. package/dist/package-manifest-template.d.ts.map +1 -0
  167. package/dist/package-manifest-template.js +60 -0
  168. package/dist/package-manifest-template.js.map +1 -0
  169. package/dist/package-source-refusal.d.ts +17 -0
  170. package/dist/package-source-refusal.d.ts.map +1 -0
  171. package/dist/package-source-refusal.js +61 -0
  172. package/dist/package-source-refusal.js.map +1 -0
  173. package/dist/package-submission.d.ts +134 -0
  174. package/dist/package-submission.d.ts.map +1 -0
  175. package/dist/package-submission.js +196 -0
  176. package/dist/package-submission.js.map +1 -0
  177. package/dist/selection-record.d.ts +95 -0
  178. package/dist/selection-record.d.ts.map +1 -0
  179. package/dist/selection-record.js +121 -0
  180. package/dist/selection-record.js.map +1 -0
  181. package/package.json +1 -1
  182. package/skills/design/SKILL.md +43 -266
  183. package/skills/design-branch/SKILL.md +37 -116
  184. package/skills/design-convert/SKILL.md +62 -148
  185. package/skills/design-draft/SKILL.md +71 -135
  186. package/skills/design-search/SKILL.md +29 -78
  187. package/skills/design/references/continuation-contract.md +0 -60
  188. 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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=branch-execution-types.js.map
@@ -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"}