harnery 0.12.2 → 0.14.0

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 (54) hide show
  1. package/README.md +2 -1
  2. package/dist/commander.d.ts.map +1 -1
  3. package/dist/commander.js +2 -0
  4. package/dist/commands/work.d.ts +4 -0
  5. package/dist/commands/work.d.ts.map +1 -0
  6. package/dist/commands/work.js +281 -0
  7. package/dist/commands/workflow.d.ts.map +1 -1
  8. package/dist/commands/workflow.js +193 -0
  9. package/dist/core/policy/types.d.ts +1 -1
  10. package/dist/core/policy/types.d.ts.map +1 -1
  11. package/dist/core/work/index.d.ts +3 -0
  12. package/dist/core/work/index.d.ts.map +1 -0
  13. package/dist/core/work/index.js +2 -0
  14. package/dist/core/work/read.d.ts +2 -0
  15. package/dist/core/work/read.d.ts.map +1 -0
  16. package/dist/core/work/read.js +1 -0
  17. package/dist/core/work/runner.d.ts +10 -0
  18. package/dist/core/work/runner.d.ts.map +1 -0
  19. package/dist/core/work/runner.js +63 -0
  20. package/dist/core/work/state.d.ts +109 -0
  21. package/dist/core/work/state.d.ts.map +1 -0
  22. package/dist/core/work/state.js +698 -0
  23. package/dist/core/workflow/approvals.d.ts +71 -0
  24. package/dist/core/workflow/approvals.d.ts.map +1 -0
  25. package/dist/core/workflow/approvals.js +288 -0
  26. package/dist/core/workflow/engine.d.ts +6 -0
  27. package/dist/core/workflow/engine.d.ts.map +1 -1
  28. package/dist/core/workflow/engine.js +243 -43
  29. package/dist/core/workflow/index.d.ts +6 -2
  30. package/dist/core/workflow/index.d.ts.map +1 -1
  31. package/dist/core/workflow/index.js +3 -1
  32. package/dist/core/workflow/proof.d.ts +1 -0
  33. package/dist/core/workflow/proof.d.ts.map +1 -1
  34. package/dist/core/workflow/proof.js +1 -0
  35. package/dist/core/workflow/run-state.d.ts +44 -0
  36. package/dist/core/workflow/run-state.d.ts.map +1 -0
  37. package/dist/core/workflow/run-state.js +233 -0
  38. package/dist/core/workflow/types.d.ts +16 -0
  39. package/dist/core/workflow/types.d.ts.map +1 -1
  40. package/package.json +11 -1
  41. package/src/commander.ts +2 -0
  42. package/src/commands/work.ts +367 -0
  43. package/src/commands/workflow.ts +226 -0
  44. package/src/core/policy/types.ts +1 -1
  45. package/src/core/work/index.ts +24 -0
  46. package/src/core/work/read.ts +15 -0
  47. package/src/core/work/runner.ts +81 -0
  48. package/src/core/work/state.ts +900 -0
  49. package/src/core/workflow/approvals.ts +393 -0
  50. package/src/core/workflow/engine.ts +288 -44
  51. package/src/core/workflow/index.ts +31 -1
  52. package/src/core/workflow/proof.ts +2 -0
  53. package/src/core/workflow/run-state.ts +290 -0
  54. package/src/core/workflow/types.ts +16 -0
@@ -30,8 +30,10 @@ import { isAbsolute, join, resolve } from "node:path";
30
30
  import { pathToFileURL } from "node:url";
31
31
  import { snapshotRepo } from "../context/index.js";
32
32
  import { evaluatePolicy, normalizePolicy, PolicyDeniedError, policyDigest, summarizePolicyRequest, } from "../policy/index.js";
33
+ import { assertWorkflowRunId, createWorkflowApproval } from "./approvals.js";
33
34
  import { probeBilling } from "./billing.js";
34
35
  import { buildWorkflowProof, createEvidenceRecord, digestResult, normalizeWorkflowMeta, writeWorkflowProof, } from "./proof.js";
36
+ import { acquireWorkflowResumeLease, assertWorkflowRunResumable, assertWorkflowScriptUnchanged, workflowScriptDigest, writeWorkflowRunManifest, } from "./run-state.js";
35
37
  import { WORKFLOW_PROOF_SCHEMA_VERSION } from "./types.js";
36
38
  import { parseStageOutput, validateAgainstSchema } from "./validate.js";
37
39
  const DEFAULT_MAX_AGENTS = 50;
@@ -51,8 +53,61 @@ export class WorkflowRunError extends Error {
51
53
  this.proofPath = proofPath;
52
54
  }
53
55
  }
56
+ export class WorkflowParkedError extends Error {
57
+ runId;
58
+ approvalId;
59
+ journalPath;
60
+ constructor(message, runId, approvalId, journalPath) {
61
+ super(message);
62
+ this.name = "WorkflowParkedError";
63
+ this.runId = runId;
64
+ this.approvalId = approvalId;
65
+ this.journalPath = journalPath;
66
+ }
67
+ }
54
68
  export async function runWorkflow(scriptPath, opts) {
69
+ if (opts.runId && opts.resumeRunId) {
70
+ throw new Error("runId and resumeRunId are mutually exclusive");
71
+ }
72
+ if (opts.runId)
73
+ assertWorkflowRunId(opts.runId);
74
+ if (opts.workItemId && !/^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$/.test(opts.workItemId)) {
75
+ throw new Error(`invalid work item id ${JSON.stringify(opts.workItemId)}`);
76
+ }
77
+ if (opts.resumeRunId && opts.resumeFrom) {
78
+ throw new Error("resumeRunId and resumeFrom are mutually exclusive");
79
+ }
80
+ const resumeState = opts.resumeRunId
81
+ ? assertWorkflowRunResumable(opts.coordRoot, opts.resumeRunId)
82
+ : undefined;
83
+ if (resumeState !== undefined &&
84
+ opts.workItemId !== undefined &&
85
+ resumeState.manifest.work_item_id !== opts.workItemId) {
86
+ throw new Error(`workflow run ${opts.resumeRunId} belongs to a different work item`);
87
+ }
55
88
  const absScript = isAbsolute(scriptPath) ? scriptPath : resolve(process.cwd(), scriptPath);
89
+ if (resumeState) {
90
+ if (resolve(resumeState.manifest.script.path) !== resolve(absScript)) {
91
+ throw new Error(`workflow run ${opts.resumeRunId} belongs to a different script`);
92
+ }
93
+ assertWorkflowScriptUnchanged(resumeState.manifest);
94
+ }
95
+ const releaseResumeLease = opts.resumeRunId
96
+ ? acquireWorkflowResumeLease(opts.coordRoot, opts.resumeRunId)
97
+ : undefined;
98
+ try {
99
+ if (resumeState) {
100
+ // Recheck under the exclusive lease. Another process may have completed
101
+ // the run between the optimistic read and lease acquisition.
102
+ assertWorkflowRunResumable(opts.coordRoot, resumeState.manifest.run_id);
103
+ }
104
+ return await executeWorkflow(scriptPath, absScript, opts, resumeState);
105
+ }
106
+ finally {
107
+ releaseResumeLease?.();
108
+ }
109
+ }
110
+ async function executeWorkflow(scriptPath, absScript, opts, resumeState) {
56
111
  const mod = (await import(__rewriteRelativeImportExtension(pathToFileURL(absScript).href)));
57
112
  if (typeof mod.default !== "function") {
58
113
  throw new Error(`${scriptPath}: workflow script must \`export default async (ctx) => …\``);
@@ -60,20 +115,58 @@ export async function runWorkflow(scriptPath, opts) {
60
115
  const fallbackName = scriptPath.replace(/^.*\//, "").replace(/\.[cm]?js$/, "");
61
116
  const meta = normalizeWorkflowMeta(mod.meta, fallbackName);
62
117
  const name = meta.name;
63
- const runId = `wf-${new Date().toISOString().replace(/[:.]/g, "-")}-${randomBytes(3).toString("hex")}`;
118
+ const runId = opts.resumeRunId ??
119
+ opts.runId ??
120
+ `wf-${new Date().toISOString().replace(/[:.]/g, "-")}-${randomBytes(3).toString("hex")}`;
64
121
  const runDir = join(opts.coordRoot, ".harnery", "workflows", runId);
65
122
  mkdirSync(runDir, { recursive: true });
66
123
  const journalPath = join(runDir, "journal.jsonl");
67
124
  const proofPath = join(runDir, "proof.json");
68
- const maxAgents = opts.maxAgents ?? DEFAULT_MAX_AGENTS;
69
- const concurrency = opts.concurrency ?? DEFAULT_CONCURRENCY;
70
- const cwd = opts.cwd ?? opts.coordRoot;
125
+ const frozen = resumeState?.manifest.execution;
126
+ const maxAgents = frozen?.max_agents ?? opts.maxAgents ?? DEFAULT_MAX_AGENTS;
127
+ const concurrency = frozen?.concurrency ?? opts.concurrency ?? DEFAULT_CONCURRENCY;
128
+ assertPositiveWorkflowBound(maxAgents, "maxAgents");
129
+ assertPositiveWorkflowBound(concurrency, "concurrency");
130
+ const cwd = frozen?.cwd ?? opts.cwd ?? opts.coordRoot;
71
131
  const log = opts.onLog ?? ((line) => process.stderr.write(`${line}\n`));
72
- const defaultHarness = opts.defaultHarness ?? "claude-code";
73
- const isolation = opts.isolation ?? "shared";
74
- const networkAccess = opts.networkAccess ?? "unknown";
75
- const policy = opts.policy ? normalizePolicy(opts.policy, { baseDir: cwd }) : undefined;
76
- const repoBefore = snapshotRepo(cwd);
132
+ const defaultHarness = frozen?.default_harness ?? opts.defaultHarness ?? "claude-code";
133
+ const isolation = frozen?.isolation ?? opts.isolation ?? "shared";
134
+ const networkAccess = frozen?.network_access ?? opts.networkAccess ?? "unknown";
135
+ const policy = frozen?.policy ?? (opts.policy ? normalizePolicy(opts.policy, { baseDir: cwd }) : undefined);
136
+ const approvalMode = frozen?.approval_mode ?? opts.approvalMode ?? "deny";
137
+ const approvalAddressee = frozen?.approval_addressee ?? opts.approvalAddressee ?? "operator";
138
+ const subscriptionOnly = frozen?.subscription_only ?? Boolean(opts.subscriptionOnly);
139
+ const allowApiBilling = frozen?.allow_api_billing ?? Boolean(opts.allowApiBilling);
140
+ const repoBefore = resumeState?.manifest.repository_before ?? snapshotRepo(cwd);
141
+ const startedAt = resumeState?.manifest.started_at ?? new Date().toISOString();
142
+ const t0 = resumeState ? Date.parse(startedAt) : Date.now();
143
+ if (!resumeState) {
144
+ writeWorkflowRunManifest({
145
+ coordRoot: opts.coordRoot,
146
+ manifest: {
147
+ schema_version: 1,
148
+ run_id: runId,
149
+ work_item_id: opts.workItemId,
150
+ name,
151
+ started_at: startedAt,
152
+ script: { path: absScript, sha256: workflowScriptDigest(absScript) },
153
+ repository_before: repoBefore,
154
+ execution: {
155
+ cwd,
156
+ default_harness: defaultHarness,
157
+ max_agents: maxAgents,
158
+ concurrency,
159
+ subscription_only: subscriptionOnly,
160
+ allow_api_billing: allowApiBilling,
161
+ approval_mode: approvalMode,
162
+ approval_addressee: approvalAddressee,
163
+ isolation,
164
+ network_access: networkAccess,
165
+ policy: policy ? policy : undefined,
166
+ },
167
+ },
168
+ });
169
+ }
77
170
  // Per-child fixed context overhead: children spawn in `cwd` and load its
78
171
  // repo-instructions file into their system prompt, cache-writing it once
79
172
  // per child. A fan-out multiplies this, so surface it BEFORE the burn.
@@ -83,12 +176,14 @@ export async function runWorkflow(scriptPath, opts) {
83
176
  `instructions from ${cwd}; a fan-out multiplies this per agent`);
84
177
  }
85
178
  // Resume: journaled results of a prior run, keyed by agent-call identity.
86
- const resumeCache = opts.resumeFrom
87
- ? loadResumeCache(opts.coordRoot, opts.resumeFrom)
179
+ const resumeSource = opts.resumeRunId ?? opts.resumeFrom;
180
+ const resumeCache = resumeSource
181
+ ? loadResumeCache(opts.coordRoot, resumeSource)
88
182
  : new Map();
89
- let agentsSpawned = 0;
183
+ const history = opts.resumeRunId ? loadRunHistory(journalPath) : undefined;
184
+ let agentsSpawned = history?.agentsSpawned ?? 0;
90
185
  let agentsCached = 0;
91
- let costUsd = 0;
186
+ let costUsd = history?.costUsd ?? 0;
92
187
  let reservedCostUsd = 0;
93
188
  let currentStage = "";
94
189
  let agentSeq = 0;
@@ -97,7 +192,7 @@ export async function runWorkflow(scriptPath, opts) {
97
192
  const billingProbed = new Map();
98
193
  const agentProofs = new Map();
99
194
  const evidenceRecords = [];
100
- const policyDecisions = [];
195
+ const policyDecisions = new Map(history?.policyDecisions.map((decision) => [decision.id, decision]));
101
196
  const acceptanceIds = new Set(meta.acceptance.map((criterion) => criterion.id));
102
197
  const journal = (event, data) => {
103
198
  const line = JSON.stringify({
@@ -149,7 +244,7 @@ export async function runWorkflow(scriptPath, opts) {
149
244
  if (!policy) {
150
245
  throw new Error("external mutation authorization requires a host policy");
151
246
  }
152
- if (policyDecisions.length >= MAX_POLICY_DECISIONS) {
247
+ if (policyDecisions.size >= MAX_POLICY_DECISIONS && !policyDecisions.has(`p${policySeq + 1}`)) {
153
248
  throw new Error(`workflow policy decision cap reached (${MAX_POLICY_DECISIONS}); split the workflow or reduce protected actions`);
154
249
  }
155
250
  const request = summarizePolicyRequest(rawRequest);
@@ -169,10 +264,8 @@ export async function runWorkflow(scriptPath, opts) {
169
264
  let reason = evaluation.reason;
170
265
  if (evaluation.verdict === "ask") {
171
266
  resolvedBy = "fail_closed";
172
- if (!opts.resolvePolicyAsk) {
173
- reason = `${evaluation.reason}; no host approval resolver is configured`;
174
- }
175
- else {
267
+ let immediateResolution = false;
268
+ if (opts.resolvePolicyAsk) {
176
269
  try {
177
270
  const resolution = await withTimeout(Promise.resolve(opts.resolvePolicyAsk(request, evaluation)), opts.policyAskTimeoutMs ?? DEFAULT_POLICY_ASK_TIMEOUT_MS);
178
271
  if (!resolution || (resolution.verdict !== "allow" && resolution.verdict !== "deny")) {
@@ -182,12 +275,54 @@ export async function runWorkflow(scriptPath, opts) {
182
275
  verdict = resolution.verdict;
183
276
  resolvedBy = "host";
184
277
  reason = boundedPolicyReason(resolution.reason ?? evaluation.reason);
278
+ immediateResolution = true;
185
279
  }
186
280
  }
187
281
  catch (error) {
188
282
  reason = `${evaluation.reason}; approval failed closed: ${error.message}`;
189
283
  }
190
284
  }
285
+ else {
286
+ reason = `${evaluation.reason}; no host approval resolver is configured`;
287
+ }
288
+ if (!immediateResolution && approvalMode === "park") {
289
+ const stored = createWorkflowApproval({
290
+ coordRoot: opts.coordRoot,
291
+ runId,
292
+ decisionId: id,
293
+ addressedTo: approvalAddressee,
294
+ policy: { name: policy.name, sha256: policyDigest(policy) },
295
+ request,
296
+ evaluation,
297
+ });
298
+ if (stored.approval.status === "pending") {
299
+ if (stored.created) {
300
+ journal("approval.requested", {
301
+ approval_id: stored.approval.request.id,
302
+ decision_id: id,
303
+ addressed_to: stored.approval.request.addressed_to,
304
+ request_sha256: stored.approval.request.request_sha256,
305
+ });
306
+ }
307
+ journal("run.parked", {
308
+ approval_id: stored.approval.request.id,
309
+ decision_id: id,
310
+ phase: request.phase,
311
+ action: request.action,
312
+ });
313
+ throw new WorkflowParkedError(`workflow parked for approval ${stored.approval.request.id}: ${evaluation.reason}`, runId, stored.approval.request.id, journalPath);
314
+ }
315
+ verdict = stored.approval.decision.verdict;
316
+ resolvedBy = "approval";
317
+ reason = boundedPolicyReason(stored.approval.decision.reason ?? evaluation.reason);
318
+ journal("approval.consumed", {
319
+ approval_id: stored.approval.request.id,
320
+ decision_id: id,
321
+ verdict,
322
+ actor: stored.approval.decision.actor,
323
+ decided_at: stored.approval.decision.decided_at,
324
+ });
325
+ }
191
326
  }
192
327
  const decision = {
193
328
  id,
@@ -201,7 +336,7 @@ export async function runWorkflow(scriptPath, opts) {
201
336
  rule_codes: evaluation.rules.map((rule) => rule.code),
202
337
  request,
203
338
  };
204
- policyDecisions.push(decision);
339
+ policyDecisions.set(decision.id, decision);
205
340
  journal("policy.resolve", { ...decision });
206
341
  if (decision.verdict === "deny") {
207
342
  throw new PolicyDeniedError(`policy ${JSON.stringify(policy.name)} denied ${request.phase} ${JSON.stringify(request.action)}: ${decision.reason}`, decision.id);
@@ -236,6 +371,11 @@ export async function runWorkflow(scriptPath, opts) {
236
371
  const key = agentCallKey(currentStage, harness, agentOpts, prompt);
237
372
  const cached = resumeCache.get(key);
238
373
  if (cached) {
374
+ // Exact-run replay skips dispatch authorization because no dispatch
375
+ // occurs, but it must still reserve the original policy slot so a later
376
+ // durable ASK resolves against the same pN identity.
377
+ if (policy && opts.resumeRunId)
378
+ policySeq++;
239
379
  agentsCached++;
240
380
  agentProof.status = "cached";
241
381
  agentProof.result = digestResult(cached.value, cached.kind);
@@ -247,7 +387,7 @@ export async function runWorkflow(scriptPath, opts) {
247
387
  model: agentOpts.model ?? null,
248
388
  kind: cached.kind,
249
389
  });
250
- log(`[${name}] ${currentStage || "(no stage)"} → ${id} ${label} (cached from ${opts.resumeFrom})`);
390
+ log(`[${name}] ${currentStage || "(no stage)"} → ${id} ${label} (cached from ${resumeSource})`);
251
391
  return cached.value;
252
392
  }
253
393
  if (policy) {
@@ -327,19 +467,19 @@ export async function runWorkflow(scriptPath, opts) {
327
467
  billingProbed.set(harness, probe);
328
468
  journal("billing.probe", {
329
469
  harness,
330
- mode: opts.subscriptionOnly ? "subscription" : probe.mode,
470
+ mode: subscriptionOnly ? "subscription" : probe.mode,
331
471
  api_key_source: probe.apiKeySource,
332
472
  login: probe.login,
333
- subscription_only: Boolean(opts.subscriptionOnly),
473
+ subscription_only: subscriptionOnly,
334
474
  });
335
- if (opts.subscriptionOnly) {
475
+ if (subscriptionOnly) {
336
476
  if (probe.login === "absent") {
337
477
  throw new Error(`subscription-only: no stored login detected for ${harness}; ` +
338
478
  `log the harness CLI in (or drop --subscription-only for a key-only host)`);
339
479
  }
340
480
  log(`[billing] ${harness}: subscription-only (API-key vars scrubbed from child env)`);
341
481
  }
342
- else if (probe.mode === "api-key-override" && !opts.allowApiBilling) {
482
+ else if (probe.mode === "api-key-override" && !allowApiBilling) {
343
483
  throw new Error(`${probe.apiKeySource} is set AND a stored ${harness} login exists — the key silently ` +
344
484
  `overrides your subscription auth, so children would bill per-token API rates. ` +
345
485
  `Either unset ${probe.apiKeySource}, run with --subscription-only to scrub it from ` +
@@ -392,7 +532,7 @@ export async function runWorkflow(scriptPath, opts) {
392
532
  maxTurns: agentOpts.maxTurns ?? DEFAULT_MAX_TURNS,
393
533
  cwd,
394
534
  runId,
395
- subscriptionOnly: opts.subscriptionOnly,
535
+ subscriptionOnly,
396
536
  });
397
537
  agentProof.attempts = attempt;
398
538
  agentProof.duration_ms += last.durationMs;
@@ -413,6 +553,7 @@ export async function runWorkflow(scriptPath, opts) {
413
553
  key,
414
554
  attempts: attempt,
415
555
  cost_usd: last.costUsd,
556
+ total_cost_usd: agentCostUsd,
416
557
  duration_ms: last.durationMs,
417
558
  session_id: last.sessionId,
418
559
  result_kind: "text",
@@ -435,6 +576,7 @@ export async function runWorkflow(scriptPath, opts) {
435
576
  key,
436
577
  attempts: attempt,
437
578
  cost_usd: last.costUsd,
579
+ total_cost_usd: agentCostUsd,
438
580
  duration_ms: last.durationMs,
439
581
  session_id: last.sessionId,
440
582
  result_kind: "json",
@@ -511,20 +653,28 @@ export async function runWorkflow(scriptPath, opts) {
511
653
  });
512
654
  };
513
655
  const ctx = { agent, parallel, stage, log, evidence, authorize };
514
- const t0 = Date.now();
515
- const startedAt = new Date(t0).toISOString();
516
- journal("run.start", {
517
- name,
518
- script: absScript,
519
- objective: meta.objective ?? null,
520
- acceptance: meta.acceptance,
521
- max_agents: maxAgents,
522
- concurrency,
523
- policy: policy ? { name: policy.name, sha256: policyDigest(policy) } : null,
524
- isolation,
525
- network_access: networkAccess,
526
- });
527
656
  try {
657
+ if (resumeState) {
658
+ journal("run.resume", {
659
+ approval_id: resumeState.approvalId,
660
+ script: absScript,
661
+ resumed_at: new Date().toISOString(),
662
+ });
663
+ }
664
+ else {
665
+ journal("run.start", {
666
+ name,
667
+ work_item_id: opts.workItemId ?? null,
668
+ script: absScript,
669
+ objective: meta.objective ?? null,
670
+ acceptance: meta.acceptance,
671
+ max_agents: maxAgents,
672
+ concurrency,
673
+ policy: policy ? { name: policy.name, sha256: policyDigest(policy) } : null,
674
+ isolation,
675
+ network_access: networkAccess,
676
+ });
677
+ }
528
678
  const result = await mod.default(ctx);
529
679
  const endedAt = new Date().toISOString();
530
680
  const durationMs = Date.now() - t0;
@@ -539,6 +689,7 @@ export async function runWorkflow(scriptPath, opts) {
539
689
  try {
540
690
  proof = buildWorkflowProof({
541
691
  runId,
692
+ workItemId: opts.workItemId ?? resumeState?.manifest.work_item_id,
542
693
  meta,
543
694
  status: "succeeded",
544
695
  startedAt,
@@ -551,7 +702,12 @@ export async function runWorkflow(scriptPath, opts) {
551
702
  evidence: evidenceRecords,
552
703
  harnessEvidence: opts.harnessEvidence,
553
704
  policy: policy
554
- ? { config: policy, decisions: policyDecisions, isolation, networkAccess }
705
+ ? {
706
+ config: policy,
707
+ decisions: Array.from(policyDecisions.values()),
708
+ isolation,
709
+ networkAccess,
710
+ }
555
711
  : undefined,
556
712
  result,
557
713
  });
@@ -562,6 +718,7 @@ export async function runWorkflow(scriptPath, opts) {
562
718
  }
563
719
  const report = {
564
720
  runId,
721
+ workItemId: opts.workItemId ?? resumeState?.manifest.work_item_id,
565
722
  name,
566
723
  result,
567
724
  agentsSpawned,
@@ -574,14 +731,14 @@ export async function runWorkflow(scriptPath, opts) {
574
731
  contextTokensPerChildEstimate,
575
732
  billing: Array.from(billingProbed.values()).map((p) => ({
576
733
  harness: p.harness,
577
- mode: opts.subscriptionOnly ? "subscription" : p.mode,
734
+ mode: subscriptionOnly ? "subscription" : p.mode,
578
735
  })),
579
736
  policy: proof.policy?.summary,
580
737
  };
581
738
  return report;
582
739
  }
583
740
  catch (err) {
584
- if (err instanceof WorkflowRunError)
741
+ if (err instanceof WorkflowParkedError || err instanceof WorkflowRunError)
585
742
  throw err;
586
743
  const endedAt = new Date().toISOString();
587
744
  const durationMs = Date.now() - t0;
@@ -596,6 +753,7 @@ export async function runWorkflow(scriptPath, opts) {
596
753
  try {
597
754
  const proof = buildWorkflowProof({
598
755
  runId,
756
+ workItemId: opts.workItemId ?? resumeState?.manifest.work_item_id,
599
757
  meta,
600
758
  status: "failed",
601
759
  startedAt,
@@ -608,7 +766,12 @@ export async function runWorkflow(scriptPath, opts) {
608
766
  evidence: evidenceRecords,
609
767
  harnessEvidence: opts.harnessEvidence,
610
768
  policy: policy
611
- ? { config: policy, decisions: policyDecisions, isolation, networkAccess }
769
+ ? {
770
+ config: policy,
771
+ decisions: Array.from(policyDecisions.values()),
772
+ isolation,
773
+ networkAccess,
774
+ }
612
775
  : undefined,
613
776
  error: err.message,
614
777
  });
@@ -676,6 +839,38 @@ function loadResumeCache(coordRoot, resumeFrom) {
676
839
  }
677
840
  return cache;
678
841
  }
842
+ function loadRunHistory(path) {
843
+ const agentIds = new Set();
844
+ const agentCosts = new Map();
845
+ const decisions = new Map();
846
+ for (const line of readFileSync(path, "utf8").split("\n")) {
847
+ if (!line.trim())
848
+ continue;
849
+ const event = JSON.parse(line);
850
+ if (event.event === "agent.start" && typeof event.id === "string") {
851
+ agentIds.add(event.id);
852
+ }
853
+ if (event.event === "agent.end" && typeof event.id === "string") {
854
+ const cost = event.total_cost_usd ?? event.cost_usd;
855
+ if (typeof cost === "number" && Number.isFinite(cost) && cost >= 0) {
856
+ agentCosts.set(event.id, cost);
857
+ }
858
+ }
859
+ if (event.event === "policy.resolve" &&
860
+ typeof event.id === "string" &&
861
+ (event.verdict === "allow" || event.verdict === "deny") &&
862
+ typeof event.resolved_by === "string" &&
863
+ event.request &&
864
+ typeof event.request === "object") {
865
+ decisions.set(event.id, event);
866
+ }
867
+ }
868
+ return {
869
+ agentsSpawned: agentIds.size,
870
+ costUsd: round4(Array.from(agentCosts.values()).reduce((sum, value) => sum + value, 0)),
871
+ policyDecisions: Array.from(decisions.values()),
872
+ };
873
+ }
679
874
  function round4(n) {
680
875
  return Math.round(n * 10_000) / 10_000;
681
876
  }
@@ -684,6 +879,11 @@ function assertAgentCapacity(agentsSpawned, maxAgents) {
684
879
  throw new Error(`workflow agent cap reached (${maxAgents}); raise --max-agents deliberately if the fan-out is intended`);
685
880
  }
686
881
  }
882
+ function assertPositiveWorkflowBound(value, field) {
883
+ if (!Number.isSafeInteger(value) || value <= 0) {
884
+ throw new Error(`${field} must be a positive safe integer`);
885
+ }
886
+ }
687
887
  function boundedPolicyReason(value) {
688
888
  const normalized = Array.from(value, (character) => {
689
889
  const code = character.charCodeAt(0);
@@ -1,5 +1,9 @@
1
- export { runWorkflow, WorkflowRunError } from "./engine.js";
1
+ export type { CreateWorkflowApprovalInput, ResolveWorkflowApprovalInput, WorkflowApproval, WorkflowApprovalDecision, WorkflowApprovalRequest, WorkflowApprovalStatus, } from "./approvals.js";
2
+ export { assertWorkflowRunId, createWorkflowApproval, listWorkflowApprovals, readWorkflowApproval, renderWorkflowApproval, resolveWorkflowApproval, WORKFLOW_APPROVAL_SCHEMA_VERSION, workflowApprovalId, } from "./approvals.js";
3
+ export { runWorkflow, WorkflowParkedError, WorkflowRunError } from "./engine.js";
2
4
  export { buildWorkflowProof, createEvidenceRecord, digestResult, normalizeWorkflowMeta, readWorkflowProof, renderWorkflowProof, rollupAcceptance, writeWorkflowProof, } from "./proof.js";
3
- export type { AcceptanceCriterion, AcceptanceResult, AcceptanceStatus, AcceptanceSummary, AgentOpts, EngineOpts, EvidenceKind, EvidenceSource, EvidenceStatus, HarnessEvidenceCapability, HarnessEvidenceCoverage, HarnessName, ResultDigest, RunReport, Spawner, SpawnRequest, SpawnResult, StageSchema, WorkflowAgentProof, WorkflowContext, WorkflowEvidenceInput, WorkflowEvidenceRecord, WorkflowMeta, WorkflowModule, WorkflowPolicyProof, WorkflowProof, WorkflowProofUnknown, WorkflowRepoEvidence, WorkflowRepoSnapshot, WorkflowRunStatus, } from "./types.js";
5
+ export type { WorkflowRunManifest } from "./run-state.js";
6
+ export { acquireWorkflowResumeLease, assertWorkflowRunResumable, assertWorkflowScriptUnchanged, readWorkflowRunManifest, WORKFLOW_RUN_MANIFEST_SCHEMA_VERSION, workflowRunManifestPath, workflowScriptDigest, writeWorkflowRunManifest, } from "./run-state.js";
7
+ export type { AcceptanceCriterion, AcceptanceResult, AcceptanceStatus, AcceptanceSummary, AgentOpts, EngineOpts, EvidenceKind, EvidenceSource, EvidenceStatus, HarnessEvidenceCapability, HarnessEvidenceCoverage, HarnessName, ResultDigest, RunReport, Spawner, SpawnRequest, SpawnResult, StageSchema, WorkflowAgentProof, WorkflowApprovalMode, WorkflowContext, WorkflowEvidenceInput, WorkflowEvidenceRecord, WorkflowMeta, WorkflowModule, WorkflowPolicyProof, WorkflowProof, WorkflowProofUnknown, WorkflowRepoEvidence, WorkflowRepoSnapshot, WorkflowRunStatus, } from "./types.js";
4
8
  export { WORKFLOW_PROOF_SCHEMA_VERSION } from "./types.js";
5
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/workflow/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,YAAY,EACZ,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,SAAS,EACT,UAAU,EACV,YAAY,EACZ,cAAc,EACd,cAAc,EACd,yBAAyB,EACzB,uBAAuB,EACvB,WAAW,EACX,YAAY,EACZ,SAAS,EACT,OAAO,EACP,YAAY,EACZ,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,sBAAsB,EACtB,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,6BAA6B,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/workflow/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,2BAA2B,EAC3B,4BAA4B,EAC5B,gBAAgB,EAChB,wBAAwB,EACxB,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,sBAAsB,EACtB,uBAAuB,EACvB,gCAAgC,EAChC,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,YAAY,EACZ,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,EAC1B,6BAA6B,EAC7B,uBAAuB,EACvB,oCAAoC,EACpC,uBAAuB,EACvB,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,SAAS,EACT,UAAU,EACV,YAAY,EACZ,cAAc,EACd,cAAc,EACd,yBAAyB,EACzB,uBAAuB,EACvB,WAAW,EACX,YAAY,EACZ,SAAS,EACT,OAAO,EACP,YAAY,EACZ,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,qBAAqB,EACrB,sBAAsB,EACtB,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,6BAA6B,EAAE,MAAM,YAAY,CAAC"}
@@ -1,3 +1,5 @@
1
- export { runWorkflow, WorkflowRunError } from "./engine.js";
1
+ export { assertWorkflowRunId, createWorkflowApproval, listWorkflowApprovals, readWorkflowApproval, renderWorkflowApproval, resolveWorkflowApproval, WORKFLOW_APPROVAL_SCHEMA_VERSION, workflowApprovalId, } from "./approvals.js";
2
+ export { runWorkflow, WorkflowParkedError, WorkflowRunError } from "./engine.js";
2
3
  export { buildWorkflowProof, createEvidenceRecord, digestResult, normalizeWorkflowMeta, readWorkflowProof, renderWorkflowProof, rollupAcceptance, writeWorkflowProof, } from "./proof.js";
4
+ export { acquireWorkflowResumeLease, assertWorkflowRunResumable, assertWorkflowScriptUnchanged, readWorkflowRunManifest, WORKFLOW_RUN_MANIFEST_SCHEMA_VERSION, workflowRunManifestPath, workflowScriptDigest, writeWorkflowRunManifest, } from "./run-state.js";
3
5
  export { WORKFLOW_PROOF_SCHEMA_VERSION } from "./types.js";
@@ -9,6 +9,7 @@ export interface NormalizedWorkflowMeta {
9
9
  }
10
10
  export interface BuildWorkflowProofInput {
11
11
  runId: string;
12
+ workItemId?: string;
12
13
  meta: NormalizedWorkflowMeta;
13
14
  status: "succeeded" | "failed";
14
15
  startedAt: string;
@@ -1 +1 @@
1
- {"version":3,"file":"proof.d.ts","sourceRoot":"","sources":["../../../src/core/workflow/proof.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,mBAAmB,EACpB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EACV,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,yBAAyB,EAEzB,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,EACtB,YAAY,EAEZ,aAAa,EAId,MAAM,YAAY,CAAC;AAepB,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,mBAAmB,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,sBAAsB,CAAC;IAC7B,MAAM,EAAE,WAAW,GAAG,QAAQ,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,QAAQ,EAAE,sBAAsB,EAAE,CAAC;IACnC,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,yBAAyB,GAAG,SAAS,CAAC,CAAC,CAAC;IAClF,MAAM,CAAC,EAAE;QACP,MAAM,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;QACnC,SAAS,EAAE,SAAS,cAAc,EAAE,CAAC;QACrC,SAAS,EAAE,eAAe,CAAC;QAC3B,aAAa,EAAE,mBAAmB,CAAC;KACpC,CAAC;IACF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,YAAY,GAAG,SAAS,EAC9B,YAAY,EAAE,MAAM,GACnB,sBAAsB,CAqCxB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC1C,KAAK,EAAE,qBAAqB,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,sBAAsB,CA6BzB;AAED,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,QAAQ,EAAE,sBAAsB,EAAE,GACjC;IAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAA;CAAE,CAuB9D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,YAAY,CAQjF;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,aAAa,CAyChF;AAgCD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI,CAe3E;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa,CAkBjF;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAoChE"}
1
+ {"version":3,"file":"proof.d.ts","sourceRoot":"","sources":["../../../src/core/workflow/proof.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,mBAAmB,EACpB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EACV,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,yBAAyB,EAEzB,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,EACtB,YAAY,EAEZ,aAAa,EAId,MAAM,YAAY,CAAC;AAepB,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,mBAAmB,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,sBAAsB,CAAC;IAC7B,MAAM,EAAE,WAAW,GAAG,QAAQ,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,QAAQ,EAAE,sBAAsB,EAAE,CAAC;IACnC,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,yBAAyB,GAAG,SAAS,CAAC,CAAC,CAAC;IAClF,MAAM,CAAC,EAAE;QACP,MAAM,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;QACnC,SAAS,EAAE,SAAS,cAAc,EAAE,CAAC;QACrC,SAAS,EAAE,eAAe,CAAC;QAC3B,aAAa,EAAE,mBAAmB,CAAC;KACpC,CAAC;IACF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,YAAY,GAAG,SAAS,EAC9B,YAAY,EAAE,MAAM,GACnB,sBAAsB,CAqCxB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC1C,KAAK,EAAE,qBAAqB,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,sBAAsB,CA6BzB;AAED,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,QAAQ,EAAE,sBAAsB,EAAE,GACjC;IAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAA;CAAE,CAuB9D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,YAAY,CAQjF;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,aAAa,CA0ChF;AAgCD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI,CAe3E;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa,CAkBjF;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAoChE"}
@@ -120,6 +120,7 @@ export function buildWorkflowProof(input) {
120
120
  schema_version: WORKFLOW_PROOF_SCHEMA_VERSION,
121
121
  run: {
122
122
  id: input.runId,
123
+ work_item_id: input.workItemId,
123
124
  name: input.meta.name,
124
125
  status: input.status,
125
126
  started_at: input.startedAt,
@@ -0,0 +1,44 @@
1
+ import type { RepoSnapshot } from "../context/index.js";
2
+ import { type NormalizedPolicy, type PolicyIsolation, type PolicyNetworkAccess } from "../policy/index.js";
3
+ export declare const WORKFLOW_RUN_MANIFEST_SCHEMA_VERSION: 1;
4
+ export interface WorkflowRunManifest {
5
+ schema_version: typeof WORKFLOW_RUN_MANIFEST_SCHEMA_VERSION;
6
+ run_id: string;
7
+ work_item_id?: string;
8
+ name: string;
9
+ started_at: string;
10
+ script: {
11
+ path: string;
12
+ sha256: string;
13
+ };
14
+ repository_before: RepoSnapshot;
15
+ execution: {
16
+ cwd: string;
17
+ default_harness: string;
18
+ max_agents: number;
19
+ concurrency: number;
20
+ subscription_only: boolean;
21
+ allow_api_billing: boolean;
22
+ approval_mode: "deny" | "park";
23
+ approval_addressee: string;
24
+ isolation: PolicyIsolation;
25
+ network_access: PolicyNetworkAccess;
26
+ policy?: NormalizedPolicy;
27
+ };
28
+ }
29
+ export interface WriteWorkflowRunManifestInput {
30
+ coordRoot: string;
31
+ manifest: WorkflowRunManifest;
32
+ }
33
+ export declare function workflowScriptDigest(scriptPath: string): string;
34
+ export declare function writeWorkflowRunManifest(input: WriteWorkflowRunManifestInput): string;
35
+ export declare function readWorkflowRunManifest(coordRoot: string, runId: string): WorkflowRunManifest;
36
+ export declare function assertWorkflowRunResumable(coordRoot: string, runId: string): {
37
+ manifest: WorkflowRunManifest;
38
+ approvalId: string;
39
+ };
40
+ export declare function assertWorkflowScriptUnchanged(manifest: WorkflowRunManifest): void;
41
+ export declare function workflowRunManifestPath(coordRoot: string, runId: string): string;
42
+ /** Acquire an exclusive, crash-recoverable lease for one resume segment. */
43
+ export declare function acquireWorkflowResumeLease(coordRoot: string, runId: string): () => void;
44
+ //# sourceMappingURL=run-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-state.d.ts","sourceRoot":"","sources":["../../../src/core/workflow/run-state.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EACL,KAAK,gBAAgB,EAErB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EAEzB,MAAM,oBAAoB,CAAC;AAG5B,eAAO,MAAM,oCAAoC,EAAG,CAAU,CAAC;AAK/D,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE,OAAO,oCAAoC,CAAC;IAC5D,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,iBAAiB,EAAE,YAAY,CAAC;IAChC,SAAS,EAAE;QACT,GAAG,EAAE,MAAM,CAAC;QACZ,eAAe,EAAE,MAAM,CAAC;QACxB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,iBAAiB,EAAE,OAAO,CAAC;QAC3B,iBAAiB,EAAE,OAAO,CAAC;QAC3B,aAAa,EAAE,MAAM,GAAG,MAAM,CAAC;QAC/B,kBAAkB,EAAE,MAAM,CAAC;QAC3B,SAAS,EAAE,eAAe,CAAC;QAC3B,cAAc,EAAE,mBAAmB,CAAC;QACpC,MAAM,CAAC,EAAE,gBAAgB,CAAC;KAC3B,CAAC;CACH;AAED,MAAM,WAAW,6BAA6B;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,mBAAmB,CAAC;CAC/B;AAED,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,6BAA6B,GAAG,MAAM,CAmBrF;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,mBAAmB,CAgC7F;AAED,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ;IAAE,QAAQ,EAAE,mBAAmB,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CA4BvD;AAED,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CASjF;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAGhF;AAED,4EAA4E;AAC5E,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,IAAI,CA0CvF"}