lua-cli 3.32.1 → 3.32.2

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.
@@ -90,9 +90,9 @@ function mcpActionTokens(action) {
90
90
  return action.replace(/([a-z0-9])([A-Z])/g, "$1 $2").toLowerCase().split(/[^a-z0-9]+/).filter(Boolean);
91
91
  }
92
92
  function isReviewableMcpDraftTool(tool) {
93
- const sep = tool.indexOf("_");
94
- if (sep <= 0 || sep >= tool.length - 1) return false;
95
- const action = tool.slice(sep + 1);
93
+ const sep4 = tool.indexOf("_");
94
+ if (sep4 <= 0 || sep4 >= tool.length - 1) return false;
95
+ const action = tool.slice(sep4 + 1);
96
96
  const tokens = mcpActionTokens(action);
97
97
  if (!tokens.includes("draft") && !tokens.includes("drafts")) return false;
98
98
  return !MCP_TOOL_READ_VERB_RE.test(action);
@@ -356,6 +356,9 @@ function isDesktopFileSessionId(value3) {
356
356
  function isImplicitModelSelectionSource(source) {
357
357
  return source !== void 0 && IMPLICIT_MODEL_SELECTION_SOURCES.includes(source);
358
358
  }
359
+ function isPlatformFallbackModelSource(source) {
360
+ return source === PLATFORM_FALLBACK_MODEL_SOURCE;
361
+ }
359
362
  function resolveRequireToolApproval(rules) {
360
363
  const raw = rules?.requireToolApproval ?? rules?.requireApproval;
361
364
  if (raw === void 0 || raw === null) return void 0;
@@ -395,14 +398,14 @@ async function readCoreDrainingRetryDelayMs(response) {
395
398
  return coreDrainingRetryDelayMs(response.headers.get("Retry-After"));
396
399
  }
397
400
  function waitForCoreDrain(delayMs, signal) {
398
- return new Promise((resolve, reject) => {
401
+ return new Promise((resolve3, reject) => {
399
402
  if (signal?.aborted) {
400
403
  reject(signal.reason ?? new DOMException("Aborted", "AbortError"));
401
404
  return;
402
405
  }
403
406
  const timer = setTimeout(() => {
404
407
  signal?.removeEventListener("abort", onAbort);
405
- resolve();
408
+ resolve3();
406
409
  }, delayMs);
407
410
  function onAbort() {
408
411
  clearTimeout(timer);
@@ -535,6 +538,75 @@ function isKnownProfile(profiles, profileId) {
535
538
  function hasCapability(profiles, profileId, required) {
536
539
  return capabilitiesFor(profiles, profileId).includes(required);
537
540
  }
541
+ function workflowJobId(id) {
542
+ switch (id.kind) {
543
+ case "start":
544
+ return `wft_${id.runId}_0`;
545
+ case "start-redrive":
546
+ return `wft_${id.runId}_start_r${id.now}`;
547
+ case "tick":
548
+ return `wft_${id.runId}_${id.seq}`;
549
+ case "timer":
550
+ return `wft_${id.runId}_timer_${id.stepId}_${id.attempt}`;
551
+ case "timer-remainder":
552
+ return `wft_${id.runId}_timer_${id.stepId}_${id.attempt}_r${id.now}`;
553
+ case "timer-deferral":
554
+ return `wft_${id.runId}_timer_${id.stepId}_${id.attempt}_d${id.now}`;
555
+ case "timer-sibling":
556
+ return `wft_${id.runId}_timer_${id.stepId}_${id.attempt}_w${id.now}`;
557
+ case "retry":
558
+ return `wft_${id.runId}_retry_${id.stepId}_${id.attempt}`;
559
+ case "respawn":
560
+ return `wft_${id.runId}_respawn_${id.stepId}_${id.attempt}_s${id.segment}_r${id.now}`;
561
+ case "redrive":
562
+ return `wft_${id.runId}_redrive_${id.stepId}_${id.attempt}_r${id.now}`;
563
+ case "redispatch":
564
+ return `wft_${id.runId}_redispatch_${id.stepId}_${id.attempt}_x${id.executionId ?? "none"}_r${id.now}`;
565
+ case "expiry":
566
+ return `wft_${id.runId}_expire_${id.stepId}_${id.attempt}_t${id.suspendedAt}${id.hop > 0 ? `_h${id.hop}` : ""}`;
567
+ case "step-terminal":
568
+ return `wft_${id.runId}_term_${id.stepId}_${id.attempt}_r${id.now}`;
569
+ case "handback":
570
+ return `wft_${id.runId}_handback_${id.stepId}_${id.attempt}_${id.now}`;
571
+ case "foreach-rate":
572
+ return `wft_${id.runId}_fe_${id.stepId}_${id.attempt}_${id.bucket}`;
573
+ case "budget-expiry":
574
+ return `wft_${id.runId}_expiry_budget_r${id.now}`;
575
+ case "budget-resume":
576
+ return `wft_${id.runId}_resume_budget_${id.now}`;
577
+ case "deadline":
578
+ return `wft_${id.runId}_deadline_${id.deadlineAt}`;
579
+ case "deadline-remainder":
580
+ return `wft_${id.runId}_deadline_${id.deadlineAt}_r${id.now}`;
581
+ case "readmit":
582
+ return `wft_${id.runId}_readmit_${id.now}`;
583
+ case "cancel":
584
+ return `wft_${id.runId}_cancel`;
585
+ case "reconcile":
586
+ return `wft_${id.runId}_reconcile_${id.now}`;
587
+ case "replay":
588
+ return `wft_${id.runId}_replay_g${id.leaseGeneration}`;
589
+ case "migration":
590
+ return `wfm_${id.migrationId}`;
591
+ default:
592
+ return assertNever(id);
593
+ }
594
+ }
595
+ function assertNever(id) {
596
+ throw new Error(`workflowJobId: unknown wake kind ${JSON.stringify(id)}`);
597
+ }
598
+ function agentStepJobId(msg) {
599
+ return `${msg.runId}_${msg.stepId}_${msg.attempt}_x${msg.executionId}`;
600
+ }
601
+ function heavyStepJobId(msg) {
602
+ return `${msg.runId}_${msg.stepId}_${msg.attempt}_x${msg.executionId}`;
603
+ }
604
+ function jobSpawnJobId(msg) {
605
+ return `${msg.runId}_${msg.stepId}_${msg.attempt}_s${msg.segment}_${msg.executionId}`;
606
+ }
607
+ function exportAutoJobId(exportId, suffix) {
608
+ return suffix ? `${exportId}:${suffix}` : exportId;
609
+ }
538
610
  function isSystemRun(identity) {
539
611
  return identity.userId.startsWith(SYSTEM_USER_PREFIX);
540
612
  }
@@ -581,6 +653,33 @@ function scheduledTimeKey(scheduledTime) {
581
653
  function scheduledWorkflowRunIdForTime(jobId, scheduledTime) {
582
654
  return scheduledWorkflowRunId(jobId, scheduledTime);
583
655
  }
656
+ function isWithinWorkflowJobRange(member, value3) {
657
+ const { min, max } = WORKFLOW_JOB_RANGES[member];
658
+ return typeof value3 === "number" && Number.isInteger(value3) && value3 >= min && value3 <= max;
659
+ }
660
+ function workflowJobRangeMessage(member) {
661
+ const { min, max } = WORKFLOW_JOB_RANGES[member];
662
+ return `\`${member}\` must be an integer ${min}..${max}`;
663
+ }
664
+ function isWorkflowSingleStepType(type) {
665
+ return typeof type === "string" && WORKFLOW_SINGLE_STEP_TYPES.includes(type);
666
+ }
667
+ function isWorkflowHitlEntryType(type) {
668
+ return typeof type === "string" && WORKFLOW_HITL_ENTRY_TYPES.includes(type);
669
+ }
670
+ function isWorkflowArmEntryType(type) {
671
+ return typeof type === "string" && WORKFLOW_ARM_ENTRY_TYPES.includes(type);
672
+ }
673
+ function workflowContainerRunsHitlArm(container) {
674
+ return typeof container === "string" && WORKFLOW_HITL_ARM_CONTAINERS.includes(container);
675
+ }
676
+ function workflowHitlArmUnsupportedMessage(type, id, container) {
677
+ const legal = WORKFLOW_HITL_ARM_CONTAINERS.map((c) => `\`${c}\``).join(" / ");
678
+ return `the engine does not run \`${type}\` inside a \`${container}\` yet (node "${id}") \u2014 place it at the top level, as a ${legal} arm, or inside a child \`workflow\``;
679
+ }
680
+ function workflowHitlArmShapeMessage(type, id, shape) {
681
+ return shape === "mapped-arm" ? `\`${type}\` arm "${id}" takes the previous output as its payload \u2014 it cannot head a [mapping, step] chain; map before the container instead` : `a chunked foreach hands each child a slice of items, not one \u2014 \`${type}\` body "${id}" takes one item; drop \`chunk\``;
682
+ }
584
683
  function groupCount(re) {
585
684
  let n2 = GROUP_COUNT.get(re);
586
685
  if (n2 === void 0) {
@@ -589,6 +688,9 @@ function groupCount(re) {
589
688
  }
590
689
  return n2;
591
690
  }
691
+ function isWorkflowSecretKey(key) {
692
+ return WORKFLOW_SECRET_KEY_RE.test(key);
693
+ }
592
694
  function applyPatterns(text, patterns) {
593
695
  let out = text;
594
696
  for (const { re, suffix } of patterns) {
@@ -611,8 +713,15 @@ function scrubSecretText(text) {
611
713
  if (typeof text !== "string" || text.length < 4) return text;
612
714
  return applyPatterns(applyPatterns(text, SECRET_LITERAL_PATTERNS), SECRET_PAIR_PATTERNS);
613
715
  }
716
+ function boundScrubInput(text, max = SCRUB_INPUT_MAX_CHARS) {
717
+ if (typeof text !== "string" || text.length <= max) return text;
718
+ const window = text.slice(Math.max(0, max - SCRUB_CUT_BACKOFF_CHARS), max);
719
+ const ws = window.search(/\s\S*$/);
720
+ const cut = ws >= 0 ? max - window.length + ws : max;
721
+ return `${text.slice(0, cut)}\u2026`;
722
+ }
614
723
  function scrubSecretLines(lines) {
615
- return lines.map((l) => typeof l === "string" ? scrubSecretText(l) : l);
724
+ return lines.map((l) => typeof l === "string" ? scrubSecretText(boundScrubInput(l)) : l);
616
725
  }
617
726
  function messageText(value3) {
618
727
  if (typeof value3 === "string") return value3;
@@ -629,11 +738,14 @@ function messageText(value3) {
629
738
  return value3 === void 0 || value3 === null ? "" : String(value3);
630
739
  }
631
740
  function scrubProviderMessage(raw, max = PROVIDER_MESSAGE_MAX_CHARS) {
632
- const text = messageText(raw).replace(/\s+/g, " ").trim();
741
+ const text = boundScrubInput(messageText(raw)).replace(/\s+/g, " ").trim();
633
742
  if (!text) return void 0;
634
743
  const out = scrubSecretText(text);
635
744
  return out.length > max ? `${out.slice(0, max - 1)}\u2026` : out;
636
745
  }
746
+ function scrubStepErrorMessage(raw) {
747
+ return scrubProviderMessage(raw, ERROR_MESSAGE_MAX_CHARS);
748
+ }
637
749
  function isWorkflowAuditEvent(action) {
638
750
  return typeof action === "string" && WORKFLOW_AUDIT_EVENTS.includes(action);
639
751
  }
@@ -728,7 +840,7 @@ ${PREAMBLE}
728
840
 
729
841
  ${items.join("\n\n")}`;
730
842
  }
731
- var __defProp2, __name2, CHANNEL_SEND_CHANNELS, REVIEWABLE_ACTION_EXECUTE_TOOL_ALLOWLIST, REVIEWABLE_MCP_SEND_TOOL_SUFFIX, MCP_TOOL_READ_VERB_RE, MCP_DRAFT_CREATE_VERBS, NON_INTERACTIVE_CHANNELS, RICH_PARTS_MESSAGE_ID_PREFIX, SCREENSHOT_MESSAGE_ID_PREFIX, BROWSER_COMMANDS, BROWSER_COMMAND_NAMES, DESKTOP_FILE_COMMANDS, DESKTOP_FILE_COMMAND_SET, REASONING_EFFORT_VALUES, IMPLICIT_MODEL_SELECTION_SOURCES, AGENT_NAME_TOKEN, DEFAULT_PERSONA_GUIDE, PERSONAL_SPACE_STARTING_PERSONA, CORE_DRAINING_CODE, CORE_DRAINING_DEFAULT_RETRY_MS, CORE_DRAINING_MAX_RETRY_MS, VoiceNameSchema, PluginProviderSchema, RealtimeProviderSchema, PluginClassSchema, ModelDescriptorSchema, InferenceModelSchema, PluginModelSchema, RealtimeModelSchema, LuaVoiceModelSchema, TurnDetectionSchema, InterruptionSchema, BuiltinAudioClipSchema, AudioConfigSchema, BackgroundAudioEntrySchema, BackgroundAudioSchema, LuaVoiceConfigInnerSchema, LuaVoiceConfigSchema, LuaVoiceRefSchema, LUA_JOB_DEFAULT_TIMEOUT_SECONDS, LUA_JOB_MIN_TIMEOUT_SECONDS, LUA_JOB_MAX_TIMEOUT_SECONDS, TEMPLATE_TRIGGER_URL_ENV_PREFIX, SUBJECT_TYPES, SubjectTypeSchema, CREDENTIAL_TYPES, CredentialTypeSchema, DEVICE_OPERATIONS, DeviceOperationSchema, DEVICE_SCOPE_BY_OPERATION, DeviceBindingSchema, IdSchema, PrincipalDescriptorSchema, ActorDescriptorSchema, PrincipalOwnerSchema, CredentialLifecycleSchema, GeneralCredentialDescriptorSchema, DeviceCredentialDescriptorSchema, GeneralPrincipalContextSchema, DeviceCredentialPrincipalContextSchema, RawPrincipalContextSchema, PrincipalContextSchema, DeviceCredentialClaimSchema, LUA_CLIENT_HEADER, LUA_CLIENT_APPS, SEMVER_PATTERN, WEB_RELEASE_PATTERN, CLIENT_HEADER_PATTERN, AUTHZ_PROJECTION_VERSION, ProjectedScopeSchema, DisplayRoleSchema, AuthorizationPrincipalSchema, CredentialContextSchema, ProjectionAnomalySchema, ProjectedOrgSchema, ProjectedResourceSchema, CapabilityProfilesSchema, RoleCatalogSchema, EffectiveAuthorizationSchema, ResourcePageSchema, SYSTEM_USER_PREFIX, WORKFLOW_RUN_IN_FLIGHT, WORKFLOW_RUN_IDLE, WORKFLOW_RUN_TERMINAL, WORKFLOW_RUN_STATUSES, WORKFLOW_STEP_STATUSES, WORKFLOW_STEP_IN_FLIGHT, ARCHIVE_WINDOW_MARGIN_DAYS, WORKFLOW_ORG_PURGING_TTL_S, WORKFLOW_ORG_PURGE_FORCE_AFTER_MS, IDEMPOTENCY_HOLDING_STATUSES, WORKFLOW_SCHEDULED_RUN_ID_PREFIX, CLOUD_TASK_RUN_ID_PREFIX, WORKFLOW_OPERATION_ID_PREFIX, WORKFLOW_CONNECTION_KEY_RE, WORKFLOW_SIGNAL_PAYLOAD_MAX_BYTES, REDACTED_PLACEHOLDER, PROVIDER_MESSAGE_MAX_CHARS, SECRET_LITERAL_PATTERNS, SECRET_NAME, SECRET_PAIR_PATTERNS, GROUP_COUNT, WORKFLOW_AUDIT_EVENTS, WORKFLOW_AUDIT_METADATA_MAX_BYTES, INDENT, WRAP_WIDTH, NOUNS, GET_TOOL_NAMES, PREAMBLE;
843
+ var __defProp2, __name2, CHANNEL_SEND_CHANNELS, REVIEWABLE_ACTION_EXECUTE_TOOL_ALLOWLIST, REVIEWABLE_MCP_SEND_TOOL_SUFFIX, MCP_TOOL_READ_VERB_RE, MCP_DRAFT_CREATE_VERBS, NON_INTERACTIVE_CHANNELS, RICH_PARTS_MESSAGE_ID_PREFIX, SCREENSHOT_MESSAGE_ID_PREFIX, BROWSER_COMMANDS, BROWSER_COMMAND_NAMES, DESKTOP_FILE_COMMANDS, DESKTOP_FILE_COMMAND_SET, REASONING_EFFORT_VALUES, IMPLICIT_MODEL_SELECTION_SOURCES, PLATFORM_FALLBACK_MODEL_SOURCE, AGENT_NAME_TOKEN, DEFAULT_PERSONA_GUIDE, PERSONAL_SPACE_STARTING_PERSONA, CORE_DRAINING_CODE, CORE_DRAINING_DEFAULT_RETRY_MS, CORE_DRAINING_MAX_RETRY_MS, VoiceNameSchema, PluginProviderSchema, RealtimeProviderSchema, PluginClassSchema, ModelDescriptorSchema, InferenceModelSchema, PluginModelSchema, RealtimeModelSchema, LuaVoiceModelSchema, TurnDetectionSchema, InterruptionSchema, BuiltinAudioClipSchema, AudioConfigSchema, BackgroundAudioEntrySchema, BackgroundAudioSchema, LuaVoiceConfigInnerSchema, LuaVoiceConfigSchema, LuaVoiceRefSchema, LUA_JOB_DEFAULT_TIMEOUT_SECONDS, LUA_JOB_MIN_TIMEOUT_SECONDS, LUA_JOB_MAX_TIMEOUT_SECONDS, TEMPLATE_TRIGGER_URL_ENV_PREFIX, SUBJECT_TYPES, SubjectTypeSchema, CREDENTIAL_TYPES, CredentialTypeSchema, DEVICE_OPERATIONS, DeviceOperationSchema, DEVICE_SCOPE_BY_OPERATION, DeviceBindingSchema, IdSchema, PrincipalDescriptorSchema, ActorDescriptorSchema, PrincipalOwnerSchema, CredentialLifecycleSchema, GeneralCredentialDescriptorSchema, DeviceCredentialDescriptorSchema, GeneralPrincipalContextSchema, DeviceCredentialPrincipalContextSchema, RawPrincipalContextSchema, PrincipalContextSchema, DeviceCredentialClaimSchema, LUA_CLIENT_HEADER, LUA_CLIENT_APPS, SEMVER_PATTERN, WEB_RELEASE_PATTERN, CLIENT_HEADER_PATTERN, AUTHZ_PROJECTION_VERSION, ProjectedScopeSchema, DisplayRoleSchema, AuthorizationPrincipalSchema, CredentialContextSchema, ProjectionAnomalySchema, ProjectedOrgSchema, ProjectedResourceSchema, CapabilityProfilesSchema, RoleCatalogSchema, EffectiveAuthorizationSchema, ResourcePageSchema, SYSTEM_USER_PREFIX, WORKFLOW_RUN_IN_FLIGHT, WORKFLOW_RUN_IDLE, WORKFLOW_RUN_TERMINAL, WORKFLOW_RUN_STATUSES, WORKFLOW_STEP_STATUSES, WORKFLOW_STEP_IN_FLIGHT, ARCHIVE_WINDOW_MARGIN_DAYS, WORKFLOW_ORG_PURGING_TTL_S, WORKFLOW_ORG_PURGE_FORCE_AFTER_MS, IDEMPOTENCY_HOLDING_STATUSES, WORKFLOW_SCHEDULED_RUN_ID_PREFIX, CLOUD_TASK_RUN_ID_PREFIX, WORKFLOW_OPERATION_ID_PREFIX, WORKFLOW_CONNECTION_KEY_RE, WORKFLOW_SIGNAL_PAYLOAD_MAX_BYTES, WORKFLOW_RESOLVE_OUTPUT_MAX_BYTES, WORKFLOW_RETRY_BACKOFFS, WORKFLOW_JOB_RESOURCES, WORKFLOW_SIDE_EFFECTS, WORKFLOW_JOB_RANGES, WORKFLOW_JOB_RANGE_MEMBERS, WORKFLOW_SINGLE_STEP_TYPES, WORKFLOW_HITL_ENTRY_TYPES, WORKFLOW_ARM_ENTRY_TYPES, WORKFLOW_HITL_ARM_CONTAINERS, WORKFLOW_GRAPH_ENTRY_STEP_KINDS, WORKFLOW_ARM_ENTRY_STEP_KINDS, WORKFLOW_BUDGET_MAX_DURATION_SECONDS, REDACTED_PLACEHOLDER, PROVIDER_MESSAGE_MAX_CHARS, ERROR_MESSAGE_MAX_CHARS, SECRET_LITERAL_PATTERNS, SECRET_NAME, SECRET_PAIR_PATTERNS, GROUP_COUNT, WORKFLOW_SECRET_KEY_RE, WORKFLOW_RESERVED_SECRET_KEYS, SCRUB_INPUT_MAX_CHARS, SCRUB_CUT_BACKOFF_CHARS, WORKFLOW_AUDIT_EVENTS, WORKFLOW_AUDIT_METADATA_MAX_BYTES, INDENT, WRAP_WIDTH, NOUNS, GET_TOOL_NAMES, PREAMBLE;
732
844
  var init_dist = __esm({
733
845
  "../shared-types/dist/index.mjs"() {
734
846
  "use strict";
@@ -1059,6 +1171,9 @@ var init_dist = __esm({
1059
1171
  ];
1060
1172
  __name(isImplicitModelSelectionSource, "isImplicitModelSelectionSource");
1061
1173
  __name2(isImplicitModelSelectionSource, "isImplicitModelSelectionSource");
1174
+ PLATFORM_FALLBACK_MODEL_SOURCE = "platform-fallback";
1175
+ __name(isPlatformFallbackModelSource, "isPlatformFallbackModelSource");
1176
+ __name2(isPlatformFallbackModelSource, "isPlatformFallbackModelSource");
1062
1177
  __name(resolveRequireToolApproval, "resolveRequireToolApproval");
1063
1178
  __name2(resolveRequireToolApproval, "resolveRequireToolApproval");
1064
1179
  AGENT_NAME_TOKEN = "[Your Agent Name]";
@@ -1711,6 +1826,18 @@ This text is who you are for this person. As you learn them, their name, their w
1711
1826
  __name2(isKnownProfile, "isKnownProfile");
1712
1827
  __name(hasCapability, "hasCapability");
1713
1828
  __name2(hasCapability, "hasCapability");
1829
+ __name(workflowJobId, "workflowJobId");
1830
+ __name2(workflowJobId, "workflowJobId");
1831
+ __name(assertNever, "assertNever");
1832
+ __name2(assertNever, "assertNever");
1833
+ __name(agentStepJobId, "agentStepJobId");
1834
+ __name2(agentStepJobId, "agentStepJobId");
1835
+ __name(heavyStepJobId, "heavyStepJobId");
1836
+ __name2(heavyStepJobId, "heavyStepJobId");
1837
+ __name(jobSpawnJobId, "jobSpawnJobId");
1838
+ __name2(jobSpawnJobId, "jobSpawnJobId");
1839
+ __name(exportAutoJobId, "exportAutoJobId");
1840
+ __name2(exportAutoJobId, "exportAutoJobId");
1714
1841
  SYSTEM_USER_PREFIX = "system:";
1715
1842
  __name(isSystemRun, "isSystemRun");
1716
1843
  __name2(isSystemRun, "isSystemRun");
@@ -1796,8 +1923,99 @@ This text is who you are for this person. As you learn them, their name, their w
1796
1923
  __name(scheduledWorkflowRunIdForTime, "scheduledWorkflowRunIdForTime");
1797
1924
  __name2(scheduledWorkflowRunIdForTime, "scheduledWorkflowRunIdForTime");
1798
1925
  WORKFLOW_SIGNAL_PAYLOAD_MAX_BYTES = 64 * 1024;
1926
+ WORKFLOW_RESOLVE_OUTPUT_MAX_BYTES = 256 * 1024;
1927
+ WORKFLOW_RETRY_BACKOFFS = [
1928
+ "fixed",
1929
+ "exponential"
1930
+ ];
1931
+ WORKFLOW_JOB_RESOURCES = [
1932
+ "small",
1933
+ "medium",
1934
+ "large"
1935
+ ];
1936
+ WORKFLOW_SIDE_EFFECTS = [
1937
+ "none",
1938
+ "external"
1939
+ ];
1940
+ WORKFLOW_JOB_RANGES = Object.freeze({
1941
+ /** Coding-turn cap (`claude -p --max-turns`); absent ⇒ the cluster default (LUA_WF_JOB_MAX_TURNS). */
1942
+ maxTurns: Object.freeze({
1943
+ min: 1,
1944
+ max: 500
1945
+ }),
1946
+ /** Harness messages per attempt (one per content block); absent ⇒ the cluster default (400). */
1947
+ maxMessages: Object.freeze({
1948
+ min: 1,
1949
+ max: 5e3
1950
+ }),
1951
+ /** Input-side tokens per attempt (prompt + cache); absent ⇒ the cluster default (4M — LUA-708, was 30M). */
1952
+ maxInputTokens: Object.freeze({
1953
+ min: 1e6,
1954
+ max: 5e8
1955
+ })
1956
+ });
1957
+ WORKFLOW_JOB_RANGE_MEMBERS = Object.keys(WORKFLOW_JOB_RANGES);
1958
+ __name(isWithinWorkflowJobRange, "isWithinWorkflowJobRange");
1959
+ __name2(isWithinWorkflowJobRange, "isWithinWorkflowJobRange");
1960
+ __name(workflowJobRangeMessage, "workflowJobRangeMessage");
1961
+ __name2(workflowJobRangeMessage, "workflowJobRangeMessage");
1962
+ WORKFLOW_SINGLE_STEP_TYPES = [
1963
+ "agent",
1964
+ "tool",
1965
+ "workflow",
1966
+ "step"
1967
+ ];
1968
+ WORKFLOW_HITL_ENTRY_TYPES = [
1969
+ "approval",
1970
+ "waitForSignal"
1971
+ ];
1972
+ WORKFLOW_ARM_ENTRY_TYPES = [
1973
+ ...WORKFLOW_SINGLE_STEP_TYPES,
1974
+ ...WORKFLOW_HITL_ENTRY_TYPES
1975
+ ];
1976
+ WORKFLOW_HITL_ARM_CONTAINERS = [
1977
+ "parallel",
1978
+ "conditional",
1979
+ "foreach"
1980
+ ];
1981
+ __name(isWorkflowSingleStepType, "isWorkflowSingleStepType");
1982
+ __name2(isWorkflowSingleStepType, "isWorkflowSingleStepType");
1983
+ __name(isWorkflowHitlEntryType, "isWorkflowHitlEntryType");
1984
+ __name2(isWorkflowHitlEntryType, "isWorkflowHitlEntryType");
1985
+ __name(isWorkflowArmEntryType, "isWorkflowArmEntryType");
1986
+ __name2(isWorkflowArmEntryType, "isWorkflowArmEntryType");
1987
+ __name(workflowContainerRunsHitlArm, "workflowContainerRunsHitlArm");
1988
+ __name2(workflowContainerRunsHitlArm, "workflowContainerRunsHitlArm");
1989
+ __name(workflowHitlArmUnsupportedMessage, "workflowHitlArmUnsupportedMessage");
1990
+ __name2(workflowHitlArmUnsupportedMessage, "workflowHitlArmUnsupportedMessage");
1991
+ __name(workflowHitlArmShapeMessage, "workflowHitlArmShapeMessage");
1992
+ __name2(workflowHitlArmShapeMessage, "workflowHitlArmShapeMessage");
1993
+ WORKFLOW_GRAPH_ENTRY_STEP_KINDS = Object.freeze({
1994
+ agent: "agent",
1995
+ tool: "tool",
1996
+ workflow: "subrun",
1997
+ step: "code",
1998
+ mapping: "map",
1999
+ sleep: "sleep",
2000
+ sleepUntil: "sleepUntil",
2001
+ parallel: null,
2002
+ conditional: "branch",
2003
+ foreach: "foreach",
2004
+ loop: "loop",
2005
+ approval: "approval",
2006
+ waitForSignal: "signal"
2007
+ });
2008
+ WORKFLOW_ARM_ENTRY_STEP_KINDS = Object.freeze(Object.fromEntries(WORKFLOW_ARM_ENTRY_TYPES.map((t) => [
2009
+ t,
2010
+ WORKFLOW_GRAPH_ENTRY_STEP_KINDS[t]
2011
+ ])));
2012
+ WORKFLOW_BUDGET_MAX_DURATION_SECONDS = Object.freeze({
2013
+ min: 60,
2014
+ max: 2592e3
2015
+ });
1799
2016
  REDACTED_PLACEHOLDER = "[REDACTED]";
1800
2017
  PROVIDER_MESSAGE_MAX_CHARS = 300;
2018
+ ERROR_MESSAGE_MAX_CHARS = 2e3;
1801
2019
  SECRET_LITERAL_PATTERNS = [
1802
2020
  {
1803
2021
  re: /\b(github_pat_)[A-Za-z0-9_]{16,}/g
@@ -1808,6 +2026,10 @@ This text is who you are for this person. As you learn them, their name, their w
1808
2026
  {
1809
2027
  re: /\b(glpat-)[A-Za-z0-9_-]{16,}/g
1810
2028
  },
2029
+ // LUA-696 review (3): the npm granular / classic token (`npm_` + 36 alphanumerics).
2030
+ {
2031
+ re: /\b(npm_)[A-Za-z0-9]{36}\b/g
2032
+ },
1811
2033
  {
1812
2034
  re: /\b(sk-ant-)[A-Za-z0-9_-]{16,}/g
1813
2035
  },
@@ -1844,8 +2066,15 @@ This text is who you are for this person. As you learn them, their name, their w
1844
2066
  // `FOO_TOKEN=x`, `secretKey=x`, `password=x`. Groups: the char before the name, the name, the separator
1845
2067
  // (with its quotes), the scheme word — all kept; the value goes. A value a literal rule already replaced
1846
2068
  // (`x-access-token:[REDACTED]@host`) is left alone so the host after it survives.
2069
+ // LUA-696: the second lookahead keeps a scrubbed `Authorization: Bearer [REDACTED]` as it is — without it the
2070
+ // optional scheme group backtracks to empty and `Bearer` itself becomes the value (`[REDACTED] [REDACTED]`).
2071
+ // The scrub is applied more than once on purpose (the Job site at its copy, the outcome table at the row
2072
+ // write, lua-api on the way out), so it must be idempotent.
2073
+ // LUA-696 review (HIGH): the identifier prefix is BOUNDED (`{1,64}`) — unbounded, `[A-Za-z0-9-]+` made the
2074
+ // scan quadratic on `-`-heavy text (100 KB of `-` took 12.7 s on the lua-core event loop; a worker-tier step
2075
+ // can throw that). No identifier that names a credential is longer; the probe list is unchanged.
1847
2076
  {
1848
- re: new RegExp(`(^|[^A-Za-z0-9])((?:[A-Za-z0-9-]+[_-])?${SECRET_NAME}|[A-Za-z0-9-]+_key)(["']?\\s*[:=]\\s*["']?)((?:basic\\s+|bearer\\s+|token\\s+)?)(?!\\[REDACTED\\])[^\\s"',;)}&]{4,}`, "gi")
2077
+ re: new RegExp(`(^|[^A-Za-z0-9])((?:[A-Za-z0-9-]{1,64}[_-])?${SECRET_NAME}|[A-Za-z0-9-]{1,64}_key)(["']?\\s*[:=]\\s*["']?)((?:basic\\s+|bearer\\s+|token\\s+)?)(?!\\[REDACTED\\]|(?:basic|bearer|token)\\s+\\[REDACTED\\])[^\\s"',;)}&]{4,}`, "gi")
1849
2078
  },
1850
2079
  // `?token=x`, `&key=x`, `&X-Amz-Signature=x`, `&sig=x`
1851
2080
  {
@@ -1864,16 +2093,47 @@ This text is who you are for this person. As you learn them, their name, their w
1864
2093
  GROUP_COUNT = /* @__PURE__ */ new WeakMap();
1865
2094
  __name(groupCount, "groupCount");
1866
2095
  __name2(groupCount, "groupCount");
2096
+ WORKFLOW_SECRET_KEY_RE = /(^|[_\-.\s])(secret|token|password|passwd|pwd|passphrase|api[_-]?key|apikey|access[_-]?key|secret[_-]?key|private[_-]?key|client[_-]?secret|authorization|auth[_-]?token|access[_-]?token|id[_-]?token|refresh[_-]?token|session[_-]?key|credential(s)?)([_\-.\s]|$)|^(secret|token|password|passwd|pwd|passphrase|apikey|authorization|credentials?)$/i;
2097
+ WORKFLOW_RESERVED_SECRET_KEYS = Object.freeze([
2098
+ "secret",
2099
+ "token",
2100
+ "password",
2101
+ "passwd",
2102
+ "pwd",
2103
+ "passphrase",
2104
+ "api_key",
2105
+ "apikey",
2106
+ "access_key",
2107
+ "secret_key",
2108
+ "private_key",
2109
+ "client_secret",
2110
+ "authorization",
2111
+ "auth_token",
2112
+ "access_token",
2113
+ "id_token",
2114
+ "refresh_token",
2115
+ "session_key",
2116
+ "credential",
2117
+ "credentials"
2118
+ ]);
2119
+ __name(isWorkflowSecretKey, "isWorkflowSecretKey");
2120
+ __name2(isWorkflowSecretKey, "isWorkflowSecretKey");
1867
2121
  __name(applyPatterns, "applyPatterns");
1868
2122
  __name2(applyPatterns, "applyPatterns");
1869
2123
  __name(scrubSecretText, "scrubSecretText");
1870
2124
  __name2(scrubSecretText, "scrubSecretText");
2125
+ SCRUB_INPUT_MAX_CHARS = 16 * 1024;
2126
+ SCRUB_CUT_BACKOFF_CHARS = 256;
2127
+ __name(boundScrubInput, "boundScrubInput");
2128
+ __name2(boundScrubInput, "boundScrubInput");
1871
2129
  __name(scrubSecretLines, "scrubSecretLines");
1872
2130
  __name2(scrubSecretLines, "scrubSecretLines");
1873
2131
  __name(messageText, "messageText");
1874
2132
  __name2(messageText, "messageText");
1875
2133
  __name(scrubProviderMessage, "scrubProviderMessage");
1876
2134
  __name2(scrubProviderMessage, "scrubProviderMessage");
2135
+ __name(scrubStepErrorMessage, "scrubStepErrorMessage");
2136
+ __name2(scrubStepErrorMessage, "scrubStepErrorMessage");
1877
2137
  WORKFLOW_AUDIT_EVENTS = [
1878
2138
  // --- definitions / versions / templates (13, 11 §11.11.5) ---
1879
2139
  "workflow.published",
@@ -1997,6 +2257,19 @@ import { createHash } from "crypto";
1997
2257
  import { z as z4 } from "zod";
1998
2258
  import { z as z22 } from "zod";
1999
2259
  import { createHash as createHash2 } from "crypto";
2260
+ function workspaceTemplatePath(template22) {
2261
+ const key = template22.trim();
2262
+ const expr = WORKSPACE_TEMPLATE_EXPR_RE.exec(key);
2263
+ if (expr) return expr[1].split(".");
2264
+ if (key.includes("${")) return void 0;
2265
+ return key.replace(/^(?:input|initData)\./, "").split(".");
2266
+ }
2267
+ function retryBackoffs() {
2268
+ if (!Array.isArray(WORKFLOW_RETRY_BACKOFFS)) {
2269
+ throw new Error("@lua/shared-types.WORKFLOW_RETRY_BACKOFFS is not a tuple \u2014 a jest.mock('@lua/shared-types') must spread jest.requireActual('@lua/shared-types')");
2270
+ }
2271
+ return WORKFLOW_RETRY_BACKOFFS;
2272
+ }
2000
2273
  function sleepUntilUnsupportedMessage(id) {
2001
2274
  return `the engine does not execute \`sleepUntil\` yet (node "${id}") \u2014 replace it with a \`sleep\` node with a \`duration\` in ms, e.g. { type: 'sleep', id: '${id}', duration: ${SLEEP_UNTIL_REPLACEMENT.duration} }`;
2002
2275
  }
@@ -2029,8 +2302,28 @@ function fillSingle(node) {
2029
2302
  return;
2030
2303
  }
2031
2304
  }
2305
+ function fillHitl(node) {
2306
+ if (node.type === "approval") {
2307
+ const a = node;
2308
+ if (a.approver === void 0) a.approver = "creator";
2309
+ if (a.timeoutHours === void 0) a.timeoutHours = WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS;
2310
+ if (a.onTimeout === void 0) a.onTimeout = "deny";
2311
+ if (a.onDeny === void 0) a.onDeny = "continue";
2312
+ if (a.excludeInitiator === void 0) a.excludeInitiator = false;
2313
+ if (a.editable === void 0) a.editable = false;
2314
+ return;
2315
+ }
2316
+ const w = node;
2317
+ if (w.timeoutHours === void 0) w.timeoutHours = WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS;
2318
+ if (w.onTimeout === void 0) w.onTimeout = "fail";
2319
+ if (w.acceptedSources === void 0) w.acceptedSources = [
2320
+ ...WORKFLOW_SIGNAL_DEFAULT_SOURCES
2321
+ ];
2322
+ }
2032
2323
  function fillArm(arm) {
2033
- if (arm.type !== "mapping") fillSingle(arm);
2324
+ if (arm.type === "mapping") return;
2325
+ if (isHitlNode(arm)) fillHitl(arm);
2326
+ else fillSingle(arm);
2034
2327
  }
2035
2328
  function fillEntry(entry) {
2036
2329
  switch (entry.type) {
@@ -2041,7 +2334,7 @@ function fillEntry(entry) {
2041
2334
  fillSingle(entry);
2042
2335
  return;
2043
2336
  case "parallel":
2044
- entry.steps.forEach(fillSingle);
2337
+ entry.steps.forEach(fillArm);
2045
2338
  return;
2046
2339
  case "conditional": {
2047
2340
  const c = entry;
@@ -2055,34 +2348,19 @@ function fillEntry(entry) {
2055
2348
  f.opts = f.opts ?? {};
2056
2349
  if (f.opts.concurrency === void 0) f.opts.concurrency = WORKFLOW_FOREACH_DEFAULT_CONCURRENCY;
2057
2350
  if (f.opts.maxItems === void 0) f.opts.maxItems = WORKFLOW_FOREACH_DEFAULT_MAX_ITEMS;
2058
- fillSingle(f.step);
2351
+ fillArm(f.step);
2059
2352
  return;
2060
2353
  }
2061
2354
  case "loop": {
2062
2355
  const l = entry;
2063
2356
  if (l.maxIterations === void 0) l.maxIterations = WORKFLOW_LOOP_DEFAULT_MAX_ITERATIONS;
2064
- fillSingle(l.step);
2065
- return;
2066
- }
2067
- case "approval": {
2068
- const a = entry;
2069
- if (a.approver === void 0) a.approver = "creator";
2070
- if (a.timeoutHours === void 0) a.timeoutHours = WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS;
2071
- if (a.onTimeout === void 0) a.onTimeout = "deny";
2072
- if (a.onDeny === void 0) a.onDeny = "continue";
2073
- if (a.excludeInitiator === void 0) a.excludeInitiator = false;
2074
- if (a.editable === void 0) a.editable = false;
2357
+ fillArm(l.step);
2075
2358
  return;
2076
2359
  }
2077
- case "waitForSignal": {
2078
- const w = entry;
2079
- if (w.timeoutHours === void 0) w.timeoutHours = WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS;
2080
- if (w.onTimeout === void 0) w.onTimeout = "fail";
2081
- if (w.acceptedSources === void 0) w.acceptedSources = [
2082
- ...WORKFLOW_SIGNAL_DEFAULT_SOURCES
2083
- ];
2360
+ case "approval":
2361
+ case "waitForSignal":
2362
+ fillHitl(entry);
2084
2363
  return;
2085
- }
2086
2364
  case "mapping":
2087
2365
  case "sleep":
2088
2366
  case "sleepUntil":
@@ -2124,14 +2402,19 @@ function templateStepRefs(text) {
2124
2402
  for (const m of text.matchAll(TEMPLATE_STEP_REF)) ids.push(m[1]);
2125
2403
  return ids;
2126
2404
  }
2127
- function mapConfigStepRefs(raw) {
2128
- if (!raw) return [];
2129
- let cfg;
2405
+ function readMapConfig(raw) {
2406
+ if (!raw) return void 0;
2407
+ if (typeof raw !== "string") return raw;
2130
2408
  try {
2131
- cfg = typeof raw === "string" ? JSON.parse(raw) : raw;
2409
+ const cfg = JSON.parse(raw);
2410
+ return cfg && typeof cfg === "object" && !Array.isArray(cfg) ? cfg : void 0;
2132
2411
  } catch {
2133
- return [];
2412
+ return void 0;
2134
2413
  }
2414
+ }
2415
+ function mapConfigStepRefs(raw) {
2416
+ const cfg = readMapConfig(raw);
2417
+ if (!cfg) return [];
2135
2418
  const ids = [];
2136
2419
  for (const d of Object.values(cfg)) {
2137
2420
  if (!d || typeof d !== "object") continue;
@@ -2202,6 +2485,16 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2202
2485
  if (envelopeWorkspace?.backend && envelopeWorkspace.backend !== "ebs" && opts.policy?.workspaceBackends && !opts.policy.workspaceBackends.includes(envelopeWorkspace.backend)) {
2203
2486
  err("workspace-backend-unavailable", `workspace.backend '${envelopeWorkspace.backend}' is not enabled (LUA_WF_WORKSPACE_BACKENDS = ${opts.policy.workspaceBackends.join(",")}) \u2014 'ebs' is the normative fallback`, "workspace.backend");
2204
2487
  }
2488
+ for (const member of [
2489
+ "repo",
2490
+ "ref"
2491
+ ]) {
2492
+ const v = envelopeWorkspace?.[member];
2493
+ const tpl = v && typeof v === "object" && typeof v.template === "string" ? v.template : void 0;
2494
+ if (tpl !== void 0 && workspaceTemplatePath(tpl) === void 0) {
2495
+ warn("workspace-template-composite", `workspace.${member} template ${JSON.stringify(tpl)} is a composite \u2014 the engine binds one whole-string \${initData.<path>} (or an input.<path> key) and every start would fail workspace_provision_failed{binding_unresolved}; put the assembled value in the run input and bind that path`, `workspace.${member}`);
2496
+ }
2497
+ }
2205
2498
  const declaredKeys = new Set(opts.connectionKeys ?? []);
2206
2499
  if (g.connections !== void 0 && !Array.isArray(g.connections)) {
2207
2500
  err("connection-declaration-invalid", "`connections` must be an array of { key, integrationType }", "connections");
@@ -2254,8 +2547,10 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2254
2547
  const r = node.retry;
2255
2548
  if (!r) return;
2256
2549
  const id = singleId(node);
2257
- if (r.backoff !== void 0 && r.backoff !== "fixed" && r.backoff !== "exponential") {
2258
- err("backoff-invalid", `retry.backoff must be 'fixed' | 'exponential'`, `${path3}.retry.backoff`, id);
2550
+ const backoffs = retryBackoffs();
2551
+ if (r.backoff !== void 0 && !backoffs.includes(r.backoff)) {
2552
+ const list = backoffs.map((b) => `'${b}'`).join(" | ");
2553
+ err("backoff-invalid", `retry.backoff must be ${list}`, `${path3}.retry.backoff`, id);
2259
2554
  }
2260
2555
  if (r.backoffSeconds !== void 0 && r.backoffSeconds < 0) {
2261
2556
  err("backoff-invalid", "retry.backoffSeconds must be \u2265 0", `${path3}.retry.backoffSeconds`, id);
@@ -2407,8 +2702,13 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2407
2702
  err("container-arm-empty", "a bare mapping arm has nothing to run", `${path3}.graph.1`, node.id);
2408
2703
  return;
2409
2704
  }
2705
+ const inner = body[1];
2706
+ if (isHitlNode(inner)) {
2707
+ err("node-type-unsupported-in-container", workflowHitlArmShapeMessage(inner.type, inner.id, "mapped-arm"), `${path3}.graph.1`, inner.id);
2708
+ return;
2709
+ }
2410
2710
  upstream.add(singleId(body[1]));
2411
- checkArm(body[0], `${path3}.graph.0`, depth);
2711
+ checkArm(body[0], `${path3}.graph.0`, depth, "parallel");
2412
2712
  checkSingle(body[1], `${path3}.graph.1`, depth);
2413
2713
  upstream.add(body[0].id);
2414
2714
  upstream.add(singleId(body[1]));
@@ -2440,13 +2740,60 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2440
2740
  if (node.type === "workflow" && node.kind === "subrun" && depth > caps.maxNestingDepth) {
2441
2741
  err("cap-exceeded", `nesting depth ${depth} exceeds ${caps.maxNestingDepth}`, path3, node.id);
2442
2742
  }
2743
+ if (node.type === "workflow" && node.workflowId !== WORKFLOW_ARM_SUBRUN_ID && typeof g.definition?.id === "string" && node.workflowId === g.definition.id) {
2744
+ err("subrun-cycle", `"${node.id}" starts "${node.workflowId}", which is this workflow itself`, path3, node.id);
2745
+ }
2443
2746
  for (const ref of nodeStepRefs(node)) {
2444
2747
  if (!upstream.has(ref)) {
2445
2748
  err("template-reference-unresolved", `"${singleId(node)}" references stepResults.${ref}, which is not upstream`, path3, singleId(node));
2446
2749
  }
2447
2750
  }
2448
2751
  }, "checkSingle");
2449
- const checkArm = /* @__PURE__ */ __name3((arm, path3, depth) => {
2752
+ const checkHitl = /* @__PURE__ */ __name3((node, path3) => {
2753
+ if (node.type === "waitForSignal") {
2754
+ const w = node;
2755
+ checkId(w.id, path3);
2756
+ if (typeof w.signal !== "string" || w.signal.length === 0) err("invalid-envelope", "waitForSignal.signal is required", `${path3}.signal`, w.id);
2757
+ return;
2758
+ }
2759
+ const a = node;
2760
+ checkId(a.id, path3);
2761
+ if (a.approver === "creator" && a.excludeInitiator === true) {
2762
+ err("approver-excludes-only-candidate", "approver:'creator' with excludeInitiator:true always excludes the only candidate", path3, a.id);
2763
+ }
2764
+ if (a.fourEyes !== void 0 && a.editable !== true) {
2765
+ err("four-eyes-requires-editable", "`fourEyes` requires editable:true", `${path3}.fourEyes`, a.id);
2766
+ }
2767
+ if ((a.editablePaths !== void 0 || a.editedPayloadSchema !== void 0) && a.editable !== true) {
2768
+ err("editable-path-invalid", "`editablePaths` / `editedPayloadSchema` require editable:true", `${path3}.editablePaths`, a.id);
2769
+ }
2770
+ for (const p of a.editablePaths ?? []) {
2771
+ if (!EDITABLE_PATH_RE.test(p)) err("editable-path-invalid", `editablePaths entry "${p}" is outside the seg(.seg)*[*]/[n] grammar`, `${path3}.editablePaths`, a.id);
2772
+ }
2773
+ if (Array.isArray(a.onTimeout)) {
2774
+ const chain = a.onTimeout;
2775
+ const hops = chain.filter((h) => typeof h === "object" && h !== null && "escalateTo" in h);
2776
+ if (hops.length > 3) err("escalation-chain-too-long", "an onTimeout chain carries at most 3 escalation hops", `${path3}.onTimeout`, a.id);
2777
+ const last = chain[chain.length - 1];
2778
+ if (last === void 0 || typeof last === "object" && last !== null && "escalateTo" in last) {
2779
+ err("escalation-chain-not-terminal", "an onTimeout chain must end in a terminal member", `${path3}.onTimeout`, a.id);
2780
+ }
2781
+ }
2782
+ if (typeof a.details === "string") {
2783
+ for (const ref of templateStepRefs(a.details)) {
2784
+ if (!upstream.has(ref)) err("template-reference-unresolved", `"${a.id}" references stepResults.${ref}, which is not upstream`, path3, a.id);
2785
+ }
2786
+ }
2787
+ }, "checkHitl");
2788
+ const checkHitlArm = /* @__PURE__ */ __name3((node, path3, container) => {
2789
+ if (!workflowContainerRunsHitlArm(container)) {
2790
+ checkId(node.id, path3);
2791
+ err("node-type-unsupported-in-container", workflowHitlArmUnsupportedMessage(node.type, node.id, container), path3, node.id);
2792
+ return;
2793
+ }
2794
+ checkHitl(node, path3);
2795
+ }, "checkHitlArm");
2796
+ const checkArm = /* @__PURE__ */ __name3((arm, path3, depth, container) => {
2450
2797
  if (arm.type === "mapping") {
2451
2798
  checkId(arm.id, path3);
2452
2799
  for (const ref of nodeStepRefs(arm)) {
@@ -2454,6 +2801,10 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2454
2801
  }
2455
2802
  return;
2456
2803
  }
2804
+ if (isHitlNode(arm)) {
2805
+ checkHitlArm(arm, path3, container);
2806
+ return;
2807
+ }
2457
2808
  checkSingle(arm, path3, depth);
2458
2809
  }, "checkArm");
2459
2810
  graph.forEach((entry, i) => {
@@ -2503,18 +2854,15 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2503
2854
  err("mapping-placement", "a bare mapping cannot be a parallel arm \u2014 chain it as [map, step]", armPath);
2504
2855
  return;
2505
2856
  }
2506
- if (arm.type === "approval" || arm.type === "waitForSignal") {
2507
- err("approval-inside-container", "approval / waitForSignal are top-level only in v1", armPath);
2508
- return;
2509
- }
2510
- checkSingle(arm, armPath, 1);
2857
+ checkArm(arm, armPath, 1, "parallel");
2511
2858
  declared.push(singleId(arm));
2512
2859
  });
2513
- const worktreeArms = p.steps.filter((a) => a.workspace?.isolation === "worktree");
2860
+ const executableArms = p.steps.filter(isSingleStep);
2861
+ const worktreeArms = executableArms.filter((a) => a.workspace?.isolation === "worktree");
2514
2862
  if (worktreeArms.length > 0 && !p.merge) err("worktree-arms-require-merge", "worktree arms need a `merge` policy", path3);
2515
2863
  if (worktreeArms.length === 0 && p.merge) err("merge-requires-worktree-arms", "`merge` needs at least one worktree arm", path3);
2516
2864
  if (worktreeArms.length > WORKFLOW_JOB_MAX_WORKTREE_ARMS) err("worktree-arms-exceed-cap", `at most ${WORKFLOW_JOB_MAX_WORKTREE_ARMS} worktree arms per parallel`, path3);
2517
- const sharedArms = p.steps.filter((a) => {
2865
+ const sharedArms = executableArms.filter((a) => {
2518
2866
  const w = workspaceOf(a);
2519
2867
  if (!w || w === "inherit" || w.isolation === "worktree") return false;
2520
2868
  return !(envelopeWorkspace?.backend === "efs" && w.mount === "ro");
@@ -2531,11 +2879,11 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2531
2879
  if (!isWellFormedPredicate(p)) err("closure-predicate", "a conditional predicate must be a well-formed LuaPredicate object ({op, left/right | value | path | args | arg}), not a function or an expression string", `${path3}.predicates.${j}`);
2532
2880
  });
2533
2881
  c.steps.forEach((arm, j) => {
2534
- checkArm(arm, `${path3}.steps.${j}`, 1);
2882
+ checkArm(arm, `${path3}.steps.${j}`, 1, "conditional");
2535
2883
  declared.push(armId(arm));
2536
2884
  });
2537
2885
  if (c.otherwise) {
2538
- checkArm(c.otherwise, `${path3}.otherwise`, 1);
2886
+ checkArm(c.otherwise, `${path3}.otherwise`, 1, "conditional");
2539
2887
  declared.push(armId(c.otherwise));
2540
2888
  }
2541
2889
  break;
@@ -2558,8 +2906,9 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2558
2906
  }
2559
2907
  if (o.chunk !== void 0) {
2560
2908
  const max = o.maxItems ?? WORKFLOW_FOREACH_DEFAULT_MAX_ITEMS;
2561
- if (!Number.isInteger(o.chunk.size) || o.chunk.size < 1 || o.chunk.size > max) {
2562
- err("chunk-size-invalid", `foreach.chunk.size must be an integer in [1, ${max}]`, `${path3}.opts.chunk.size`);
2909
+ const size = typeof o.chunk === "number" ? o.chunk : o.chunk.size;
2910
+ if (!Number.isInteger(size) || size < 1 || size > max) {
2911
+ err("chunk-size-invalid", `foreach.chunk.size must be an integer in [1, ${max}]`, typeof o.chunk === "number" ? `${path3}.opts.chunk` : `${path3}.opts.chunk.size`);
2563
2912
  }
2564
2913
  }
2565
2914
  if (o.rateLimit !== void 0) {
@@ -2576,12 +2925,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2576
2925
  const bodyType = f.step.type;
2577
2926
  const prevEntry = i > 0 ? graph[i - 1] : void 0;
2578
2927
  if (bodyType !== "mapping" && prevEntry?.type === "mapping" && prevEntry.id === `${singleId(f.step)}_items`) {
2579
- let cfg;
2580
- try {
2581
- cfg = JSON.parse(prevEntry.mapConfig);
2582
- } catch {
2583
- cfg = void 0;
2584
- }
2928
+ const cfg = readMapConfig(prevEntry.mapConfig);
2585
2929
  const d = cfg?.[""];
2586
2930
  let arrayLike;
2587
2931
  if (d && "value" in d) arrayLike = Array.isArray(d.value);
@@ -2593,8 +2937,13 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2593
2937
  if (arrayLike === false) err("foreach-items-not-array", `foreach({items}) for "${singleId(f.step)}" binds a value that is not an array`, `${path3}.step`, singleId(f.step));
2594
2938
  }
2595
2939
  if (bodyType === "mapping") err("container-arm-empty", "a foreach body needs a step, not a bare mapping", `${path3}.step`);
2596
- else if (bodyType === "approval" || bodyType === "waitForSignal") err("approval-inside-container", "approval / waitForSignal are top-level only in v1", `${path3}.step`);
2597
- else {
2940
+ else if (isHitlNode(f.step)) {
2941
+ if (o.chunk !== void 0) {
2942
+ checkId(f.step.id, `${path3}.step`);
2943
+ err("node-type-unsupported-in-container", workflowHitlArmShapeMessage(f.step.type, f.step.id, "chunked-foreach"), `${path3}.step`, f.step.id);
2944
+ } else checkHitlArm(f.step, `${path3}.step`, "foreach");
2945
+ declared.push(f.step.id);
2946
+ } else {
2598
2947
  checkSingle(f.step, `${path3}.step`, o.chunk ? 2 : 1);
2599
2948
  declared.push(singleId(f.step));
2600
2949
  }
@@ -2611,52 +2960,20 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2611
2960
  if (!isWellFormedPredicate(l.predicate)) err("closure-predicate", "a loop predicate must be a well-formed LuaPredicate object ({op, left/right | value | path | args | arg}), not a function or an expression string", `${path3}.predicate`);
2612
2961
  const bodyType = l.step.type;
2613
2962
  if (bodyType === "mapping") err("container-arm-empty", "a loop body needs a step, not a bare mapping", `${path3}.step`);
2614
- else if (bodyType === "approval" || bodyType === "waitForSignal") err("approval-inside-container", "approval / waitForSignal are top-level only in v1", `${path3}.step`);
2615
- else {
2963
+ else if (isHitlNode(l.step)) {
2964
+ checkHitlArm(l.step, `${path3}.step`, "loop");
2965
+ declared.push(l.step.id);
2966
+ } else {
2616
2967
  checkSingle(l.step, `${path3}.step`, 1);
2617
2968
  declared.push(singleId(l.step));
2618
2969
  }
2619
2970
  break;
2620
2971
  }
2621
- case "approval": {
2622
- const a = entry;
2623
- checkId(a.id, path3);
2624
- if (a.approver === "creator" && a.excludeInitiator === true) {
2625
- err("approver-excludes-only-candidate", "approver:'creator' with excludeInitiator:true always excludes the only candidate", path3, a.id);
2626
- }
2627
- if (a.fourEyes !== void 0 && a.editable !== true) {
2628
- err("four-eyes-requires-editable", "`fourEyes` requires editable:true", `${path3}.fourEyes`, a.id);
2629
- }
2630
- if ((a.editablePaths !== void 0 || a.editedPayloadSchema !== void 0) && a.editable !== true) {
2631
- err("editable-path-invalid", "`editablePaths` / `editedPayloadSchema` require editable:true", `${path3}.editablePaths`, a.id);
2632
- }
2633
- for (const p of a.editablePaths ?? []) {
2634
- if (!EDITABLE_PATH_RE.test(p)) err("editable-path-invalid", `editablePaths entry "${p}" is outside the seg(.seg)*[*]/[n] grammar`, `${path3}.editablePaths`, a.id);
2635
- }
2636
- if (Array.isArray(a.onTimeout)) {
2637
- const chain = a.onTimeout;
2638
- const hops = chain.filter((h) => typeof h === "object" && h !== null && "escalateTo" in h);
2639
- if (hops.length > 3) err("escalation-chain-too-long", "an onTimeout chain carries at most 3 escalation hops", `${path3}.onTimeout`, a.id);
2640
- const last = chain[chain.length - 1];
2641
- if (last === void 0 || typeof last === "object" && last !== null && "escalateTo" in last) {
2642
- err("escalation-chain-not-terminal", "an onTimeout chain must end in a terminal member", `${path3}.onTimeout`, a.id);
2643
- }
2644
- }
2645
- if (typeof a.details === "string") {
2646
- for (const ref of templateStepRefs(a.details)) {
2647
- if (!upstream.has(ref)) err("template-reference-unresolved", `"${a.id}" references stepResults.${ref}, which is not upstream`, path3, a.id);
2648
- }
2649
- }
2650
- declared.push(a.id);
2651
- break;
2652
- }
2653
- case "waitForSignal": {
2654
- const w = entry;
2655
- checkId(w.id, path3);
2656
- if (typeof w.signal !== "string" || w.signal.length === 0) err("invalid-envelope", "waitForSignal.signal is required", `${path3}.signal`, w.id);
2657
- declared.push(w.id);
2972
+ case "approval":
2973
+ case "waitForSignal":
2974
+ checkHitl(entry, path3);
2975
+ declared.push(entry.id);
2658
2976
  break;
2659
- }
2660
2977
  default:
2661
2978
  err("invalid-envelope", `unknown entry type "${entry.type}"`, path3);
2662
2979
  }
@@ -2745,10 +3062,10 @@ function compilePlan(g) {
2745
3062
  let prevTails = [];
2746
3063
  const foreachJoinToEntry = /* @__PURE__ */ new Map();
2747
3064
  g.definition.graph.forEach((entry, entryIndex) => {
2748
- if (isSingleStep(entry)) {
2749
- const id = singleStepId(entry);
3065
+ if (isArmStep(entry)) {
3066
+ const id = armStepId(entry);
2750
3067
  addNode(id, {
2751
- kind: SINGLE_STEP_KINDS[entry.type],
3068
+ kind: armStepKind(entry),
2752
3069
  dependsOn: prevTails,
2753
3070
  downstream: [],
2754
3071
  unsatisfiedDeps: prevTails.length,
@@ -2773,9 +3090,8 @@ function compilePlan(g) {
2773
3090
  ];
2774
3091
  return;
2775
3092
  case "sleep":
2776
- case "sleepUntil":
2777
- case "approval": {
2778
- const kind = entry.type === "approval" ? "approval" : entry.type;
3093
+ case "sleepUntil": {
3094
+ const kind = entry.type;
2779
3095
  addNode(entry.id, {
2780
3096
  kind,
2781
3097
  dependsOn: prevTails,
@@ -2788,24 +3104,12 @@ function compilePlan(g) {
2788
3104
  ];
2789
3105
  return;
2790
3106
  }
2791
- case "waitForSignal":
2792
- addNode(entry.id, {
2793
- kind: "signal",
2794
- dependsOn: prevTails,
2795
- downstream: [],
2796
- unsatisfiedDeps: prevTails.length,
2797
- entry
2798
- });
2799
- prevTails = [
2800
- entry.id
2801
- ];
2802
- return;
2803
3107
  case "parallel": {
2804
3108
  const entryId = containerIdOf("parallel", entryIndex);
2805
3109
  const childIds = entry.steps.map((arm) => {
2806
- const childId = singleStepId(arm);
3110
+ const childId = armStepId(arm);
2807
3111
  addNode(childId, {
2808
- kind: SINGLE_STEP_KINDS[arm.type],
3112
+ kind: armStepKind(arm),
2809
3113
  dependsOn: prevTails,
2810
3114
  downstream: [],
2811
3115
  unsatisfiedDeps: prevTails.length,
@@ -2843,9 +3147,9 @@ function compilePlan(g) {
2843
3147
  node.otherwise
2844
3148
  ] : node.steps;
2845
3149
  const childIds = arms.map((arm) => {
2846
- const childId = arm.type === "mapping" ? arm.id : singleStepId(arm);
3150
+ const childId = arm.type === "mapping" ? arm.id : armStepId(arm);
2847
3151
  addNode(childId, {
2848
- kind: arm.type === "mapping" ? "map" : SINGLE_STEP_KINDS[arm.type],
3152
+ kind: arm.type === "mapping" ? "map" : armStepKind(arm),
2849
3153
  dependsOn: [
2850
3154
  entryId
2851
3155
  ],
@@ -3114,13 +3418,25 @@ function toPathOrLiteral(v) {
3114
3418
  literal: v
3115
3419
  };
3116
3420
  }
3421
+ function isMapConfigObject(v) {
3422
+ return typeof v === "object" && v !== null && !Array.isArray(v);
3423
+ }
3117
3424
  function parseMapConfig(raw, stepId) {
3425
+ if (isMapConfigObject(raw)) return raw;
3426
+ if (typeof raw !== "string") {
3427
+ throw new Error(`Stored mapping step "${stepId}" has a mapConfig that is neither a JSON string nor an object.`);
3428
+ }
3118
3429
  try {
3119
3430
  return JSON.parse(raw);
3120
3431
  } catch (e) {
3121
3432
  throw new Error(`Stored mapping step "${stepId}" has invalid JSON mapConfig: ${e.message}`);
3122
3433
  }
3123
3434
  }
3435
+ function mapConfigWire(raw) {
3436
+ if (typeof raw === "string") return raw;
3437
+ if (isMapConfigObject(raw)) return canonicalJson(raw);
3438
+ return void 0;
3439
+ }
3124
3440
  function describeBadPlaceholder(template22, idx, rawExpr) {
3125
3441
  return `Template placeholder #${idx} (\${${rawExpr}}) in '${template22}'`;
3126
3442
  }
@@ -3367,7 +3683,28 @@ function resolvePlacements(calls) {
3367
3683
  break;
3368
3684
  }
3369
3685
  });
3370
- const resolve = /* @__PURE__ */ __name3((ref, i, allowMapping) => {
3686
+ const hitlPlacementIssue = /* @__PURE__ */ __name3((node, ref, i, container) => {
3687
+ if (!isHitlNode2(node)) return void 0;
3688
+ const id = node.id;
3689
+ if (ref.armMap) {
3690
+ return {
3691
+ code: "node-type-unsupported-in-container",
3692
+ message: workflowHitlArmShapeMessage(node.type, id, "mapped-arm"),
3693
+ callIndex: i,
3694
+ stepId: id
3695
+ };
3696
+ }
3697
+ if (container !== "place" && !workflowContainerRunsHitlArm(container)) {
3698
+ return {
3699
+ code: "node-type-unsupported-in-container",
3700
+ message: workflowHitlArmUnsupportedMessage(node.type, id, container),
3701
+ callIndex: i,
3702
+ stepId: id
3703
+ };
3704
+ }
3705
+ return void 0;
3706
+ }, "hitlPlacementIssue");
3707
+ const resolve3 = /* @__PURE__ */ __name3((ref, i, allowMapping, container) => {
3371
3708
  if ("node" in ref) {
3372
3709
  if (ref.node.type === "mapping" && !allowMapping) {
3373
3710
  issues.push({
@@ -3384,7 +3721,7 @@ function resolvePlacements(calls) {
3384
3721
  if (!d) {
3385
3722
  issues.push({
3386
3723
  code: "unknown-step-ref",
3387
- message: `"${ref.ref}" is not declared anywhere in the chain \u2014 declare it with agentStep/specialistStep/toolStep/map(\u2026, { id })/workflow(\u2026)`,
3724
+ message: `"${ref.ref}" is not declared anywhere in the chain \u2014 declare it with agentStep/specialistStep/toolStep/map(\u2026, { id })/workflow(\u2026)/approval(\u2026)/waitForSignal(\u2026)`,
3388
3725
  callIndex: i,
3389
3726
  stepId: ref.ref
3390
3727
  });
@@ -3399,6 +3736,11 @@ function resolvePlacements(calls) {
3399
3736
  });
3400
3737
  return void 0;
3401
3738
  }
3739
+ const hitl = hitlPlacementIssue(d.node, ref, i, container);
3740
+ if (hitl) {
3741
+ issues.push(hitl);
3742
+ return void 0;
3743
+ }
3402
3744
  const prior = placedBy.get(ref.ref);
3403
3745
  if (prior !== void 0 && prior !== i) {
3404
3746
  issues.push({
@@ -3412,23 +3754,31 @@ function resolvePlacements(calls) {
3412
3754
  placedBy.set(ref.ref, i);
3413
3755
  return d.node;
3414
3756
  }, "resolve");
3757
+ const claim = /* @__PURE__ */ __name3((ref, i, allowMapping, container) => {
3758
+ if ("ref" in ref) {
3759
+ resolve3(ref, i, allowMapping, container);
3760
+ return;
3761
+ }
3762
+ const hitl = hitlPlacementIssue(ref.node, ref, i, container);
3763
+ if (hitl) issues.push(hitl);
3764
+ }, "claim");
3415
3765
  calls.forEach((call, i) => {
3416
3766
  switch (call.kind) {
3417
3767
  case "place":
3418
- resolve({
3768
+ claim({
3419
3769
  ref: call.ref
3420
- }, i, false);
3770
+ }, i, false, "place");
3421
3771
  break;
3422
3772
  case "parallel":
3423
- for (const arm of call.arms) if ("ref" in arm) resolve(arm, i, false);
3773
+ for (const arm of call.arms) claim(arm, i, false, "parallel");
3424
3774
  break;
3425
3775
  case "conditional":
3426
- for (const a of call.arms) if ("ref" in a.target) resolve(a.target, i, true);
3427
- if (call.otherwise && "ref" in call.otherwise) resolve(call.otherwise, i, true);
3776
+ for (const a of call.arms) claim(a.target, i, true, "conditional");
3777
+ if (call.otherwise) claim(call.otherwise, i, true, "conditional");
3428
3778
  break;
3429
3779
  case "foreach":
3430
3780
  case "loop":
3431
- if ("ref" in call.body) resolve(call.body, i, false);
3781
+ claim(call.body, i, false, call.kind);
3432
3782
  break;
3433
3783
  default:
3434
3784
  break;
@@ -3437,7 +3787,7 @@ function resolvePlacements(calls) {
3437
3787
  const graph = [];
3438
3788
  const lookup = /* @__PURE__ */ __name3((ref) => {
3439
3789
  const n2 = "node" in ref ? ref.node : declared.get(ref.ref)?.node;
3440
- if (!n2 || !ref.armMap || n2.type === "mapping") return n2;
3790
+ if (!n2 || !ref.armMap || n2.type === "mapping" || isHitlNode2(n2)) return n2;
3441
3791
  return lowerContainerArm(ref.armMap, n2);
3442
3792
  }, "lookup");
3443
3793
  calls.forEach((call, i) => {
@@ -3517,6 +3867,57 @@ function resolvePlacements(calls) {
3517
3867
  issues
3518
3868
  };
3519
3869
  }
3870
+ function isConditionalJoinId(stepId) {
3871
+ return CONDITIONAL_JOIN_ID.test(stepId);
3872
+ }
3873
+ function isPlainObject(v) {
3874
+ return typeof v === "object" && v !== null && !Array.isArray(v);
3875
+ }
3876
+ function leafValue(row) {
3877
+ if (row.status === "completed") return row.output === void 0 ? null : row.output;
3878
+ return continuedFailureValue(row.error, row.killReason);
3879
+ }
3880
+ function runOutputLeaves(steps) {
3881
+ const dependedOn = /* @__PURE__ */ new Set();
3882
+ for (const s of steps) {
3883
+ if (s.stepId === GOAL_JUDGE_STEP_ID) continue;
3884
+ for (const d of s.dependsOn ?? []) dependedOn.add(d);
3885
+ }
3886
+ return steps.filter((s) => s.stepId !== GOAL_JUDGE_STEP_ID && !NON_LEAF_KINDS.has(s.kind ?? "") && s.foreachIndex === void 0 && s.loopParentId === void 0 && s.status !== "skipped" && !dependedOn.has(s.stepId));
3887
+ }
3888
+ function deriveRunOutput(steps) {
3889
+ const leaves = runOutputLeaves(steps);
3890
+ if (leaves.length === 0) return void 0;
3891
+ if (leaves.length === 1) {
3892
+ const leaf = leaves[0];
3893
+ const value22 = leafValue(leaf);
3894
+ if (isConditionalJoinId(leaf.stepId) && isPlainObject(value22)) {
3895
+ const keys = Object.keys(value22);
3896
+ if (keys.length === 1) return {
3897
+ output: value22[keys[0]],
3898
+ leafIds: [
3899
+ keys[0]
3900
+ ]
3901
+ };
3902
+ }
3903
+ return {
3904
+ output: value22,
3905
+ leafIds: [
3906
+ leaf.stepId
3907
+ ]
3908
+ };
3909
+ }
3910
+ const output = {};
3911
+ for (const leaf of leaves) output[leaf.stepId] = leafValue(leaf);
3912
+ return {
3913
+ output,
3914
+ leafIds: leaves.map((l) => l.stepId)
3915
+ };
3916
+ }
3917
+ function subrunSettledOutput(child) {
3918
+ if (child.output !== void 0) return child.output;
3919
+ return deriveRunOutput(child.steps ?? [])?.output ?? null;
3920
+ }
3520
3921
  function seedLedgerFromRun(run, steps, targetPlan, opts = {}) {
3521
3922
  const byId = /* @__PURE__ */ new Map();
3522
3923
  for (const s of steps) {
@@ -3539,15 +3940,15 @@ function seedLedgerFromRun(run, steps, targetPlan, opts = {}) {
3539
3940
  parent
3540
3941
  ] : [];
3541
3942
  }, "dependsOf");
3542
- const walk2 = [
3943
+ const walk22 = [
3543
3944
  ...targetPlan.order
3544
3945
  ];
3545
3946
  for (const s of steps) {
3546
- if (!known.has(s.stepId) && parentOf(s.stepId) && known.has(parentOf(s.stepId)) && !walk2.includes(s.stepId)) {
3547
- walk2.push(s.stepId);
3947
+ if (!known.has(s.stepId) && parentOf(s.stepId) && known.has(parentOf(s.stepId)) && !walk22.includes(s.stepId)) {
3948
+ walk22.push(s.stepId);
3548
3949
  }
3549
3950
  }
3550
- for (const id of walk2) {
3951
+ for (const id of walk22) {
3551
3952
  const row = byId.get(id);
3552
3953
  if (!row || row.status !== "completed") continue;
3553
3954
  if (!dependsOf(id).every((d) => seededIds.has(d))) {
@@ -3667,6 +4068,15 @@ function replayLedger(g, ledger) {
3667
4068
  local,
3668
4069
  diverged: recordedCount !== local
3669
4070
  });
4071
+ } else if (node.kind === "subrun" && recorded.status === "completed" && recorded.child) {
4072
+ const local = subrunSettledOutput(recorded.child);
4073
+ verdicts.push({
4074
+ stepId: id,
4075
+ kind: "subrun",
4076
+ recorded: recorded.output,
4077
+ local,
4078
+ diverged: canonical(recorded.output) !== canonical(local)
4079
+ });
3670
4080
  }
3671
4081
  }
3672
4082
  return {
@@ -3708,7 +4118,7 @@ function ancestorResults(plan, id, rows22) {
3708
4118
  }
3709
4119
  return hit;
3710
4120
  }, "take");
3711
- const walk2 = /* @__PURE__ */ __name3((ids) => {
4121
+ const walk22 = /* @__PURE__ */ __name3((ids) => {
3712
4122
  for (const dep of ids) {
3713
4123
  if (seen.has(dep)) continue;
3714
4124
  seen.add(dep);
@@ -3733,10 +4143,10 @@ function ancestorResults(plan, id, rows22) {
3733
4143
  }
3734
4144
  }
3735
4145
  }
3736
- walk2(node.dependsOn);
4146
+ walk22(node.dependsOn);
3737
4147
  }
3738
4148
  }, "walk");
3739
- walk2(plan.steps[id]?.dependsOn ?? []);
4149
+ walk22(plan.steps[id]?.dependsOn ?? []);
3740
4150
  return out;
3741
4151
  }
3742
4152
  function inferTaken(entry, rows22) {
@@ -3822,7 +4232,23 @@ function runCancelView(cancel) {
3822
4232
  return {
3823
4233
  requestedAt: cancel.requestedAt,
3824
4234
  requestedBy: cancel.requestedBy ?? "",
3825
- forceAvailableAt: cancel.forceAfter ?? cancel.requestedAt + FORCE_CANCEL_STALE_MS
4235
+ forceAvailableAt: cancel.forceAfter ?? cancel.requestedAt + FORCE_CANCEL_STALE_MS,
4236
+ // LUA-686: the wall's own request (LUA-683 stamps `wall:true` from a system actor only) rides the wire, so a
4237
+ // client can tell a wall-ended `timed_out` run's audit block from a cancel it should chip. Absent, never false.
4238
+ ...cancel.wall === true ? {
4239
+ wall: true
4240
+ } : {},
4241
+ // LUA-704: a forced terminal's audit — who forced it, when, and a human's own reason text (the run's `reason`
4242
+ // is the terminal's). Absent on an unforced terminal, never null.
4243
+ ...typeof cancel.forcedAt === "number" ? {
4244
+ forcedAt: cancel.forcedAt
4245
+ } : {},
4246
+ ...typeof cancel.forcedBy === "string" && cancel.forcedBy ? {
4247
+ forcedBy: cancel.forcedBy
4248
+ } : {},
4249
+ ...typeof cancel.forceReason === "string" && cancel.forceReason ? {
4250
+ forceReason: cancel.forceReason
4251
+ } : {}
3826
4252
  };
3827
4253
  }
3828
4254
  function runWorkspaceView(ws) {
@@ -3841,7 +4267,6 @@ function runWorkspaceView(ws) {
3841
4267
  function toWorkflowRunSummary(run) {
3842
4268
  const status = run.status;
3843
4269
  const principal = run.principal?.principal;
3844
- const gated = status === "gated" || status === "suspended";
3845
4270
  return pruneUndefined({
3846
4271
  runId: run.id,
3847
4272
  workflowId: run.workflowId,
@@ -3853,7 +4278,14 @@ function toWorkflowRunSummary(run) {
3853
4278
  orgId: run.orgId,
3854
4279
  spaceAgentId: run.spaceAgentId,
3855
4280
  status,
3856
- gate: gated ? run.gate : void 0,
4281
+ // LUA-702 (pass-3B D6): the gate rides the wire whenever a NON-terminal doc carries one. In the LUA-681 window
4282
+ // (an approval resolved beside an open exception park) the run is `running` AND still holds `gate{exception}`
4283
+ // until the tick tail parks it back; projecting it only on gated|suspended hid that park from R4 / the CLI /
4284
+ // the desktop (prod 2026-09-05: `status: running, gate: null`). A terminal doc carries no gate by contract
4285
+ // (`terminalizeRun` drops `gate` / `suspendedFor` in every terminal write), but a row terminalized before that
4286
+ // held — pre-LUA-677/694 docs, a script-tier backstop that passed no `unset` — may still carry a stale one:
4287
+ // hidden here, so a `failed` run never reads "Needs a decision" on R3/R4 or the CLI (#2476 review).
4288
+ gate: run.gate && !isTerminalRunStatus(status) ? run.gate : void 0,
3857
4289
  batchId: run.batchId,
3858
4290
  goalId: run.goalId,
3859
4291
  foreachOverflow: run.foreachOverflow,
@@ -3876,9 +4308,11 @@ function toWorkflowRunSummary(run) {
3876
4308
  principalKind: run.principalKind ?? "user",
3877
4309
  cancel: runCancelView(run.cancel),
3878
4310
  usage: runUsage(run),
4311
+ // LUA-697: a row persisted before the write seams (#2406 / #2465 / the script tier) leaves scrubbed here too —
4312
+ // idempotent on a scrubbed message, bounded input; an empty message falls back to the code.
3879
4313
  error: run.error ? {
3880
4314
  code: run.error.code ?? "error",
3881
- message: run.error.message ?? "",
4315
+ message: scrubStepErrorMessage(run.error.message) ?? run.error.code ?? "error",
3882
4316
  stepId: run.error.stepId
3883
4317
  } : void 0,
3884
4318
  kind: "run",
@@ -3897,6 +4331,49 @@ function toWorkflowRunSummary(run) {
3897
4331
  hasOutput: run.hasOutput === true || run.output !== void 0 || run.outputRef !== void 0 ? true : void 0
3898
4332
  });
3899
4333
  }
4334
+ function scrubDetailValue(value22, depth) {
4335
+ if (typeof value22 === "string") return scrubSecretText(value22);
4336
+ if (typeof value22 === "number" || typeof value22 === "boolean" || value22 === null) return value22;
4337
+ if (depth >= DETAIL_MAX_DEPTH) return void 0;
4338
+ if (Array.isArray(value22)) {
4339
+ return value22.slice(0, DETAIL_MAX_ITEMS).map((v) => scrubDetailValue(v, depth + 1)).filter((v) => v !== void 0);
4340
+ }
4341
+ if (typeof value22 === "object") {
4342
+ const out = {};
4343
+ for (const [k, v] of Object.entries(value22)) {
4344
+ const s = scrubDetailValue(v, depth + 1);
4345
+ if (s !== void 0) out[k] = s;
4346
+ }
4347
+ return out;
4348
+ }
4349
+ return void 0;
4350
+ }
4351
+ function stepErrorDetail(error) {
4352
+ if (!error || typeof error !== "object") return void 0;
4353
+ const d = error.detail;
4354
+ if (!d || typeof d !== "object" || Array.isArray(d)) return void 0;
4355
+ const bag = d;
4356
+ const out = {};
4357
+ for (const k of STEP_ERROR_DETAIL_KEYS) {
4358
+ if (!(k in bag)) continue;
4359
+ const v = scrubDetailValue(bag[k], 1);
4360
+ if (v !== void 0) out[k] = v;
4361
+ }
4362
+ if (!Object.keys(out).length) return void 0;
4363
+ let bytes;
4364
+ try {
4365
+ bytes = new TextEncoder().encode(JSON.stringify(out)).length;
4366
+ } catch {
4367
+ return void 0;
4368
+ }
4369
+ if (bytes <= STEP_ERROR_DETAIL_MAX_BYTES) return out;
4370
+ const scalars = Object.fromEntries(Object.entries(out).filter(([, v]) => v === null || typeof v !== "object"));
4371
+ return {
4372
+ ...scalars,
4373
+ __truncated: true,
4374
+ bytes
4375
+ };
4376
+ }
3900
4377
  function timeZoneSupported(tz) {
3901
4378
  if (typeof tz !== "string" || !tz) return false;
3902
4379
  const intl = Intl;
@@ -4360,6 +4837,22 @@ function rebaseItemPointer(pointer, itemsPath, index) {
4360
4837
  const base = `/${itemsPath.split(".").map(escapePointer).join("/")}/${index}`;
4361
4838
  return pointer === "/" || pointer === "" ? base : `${base}${pointer}`;
4362
4839
  }
4840
+ function describeApproverSpecRefusal(spec) {
4841
+ const raw = spec === void 0 ? "undefined" : JSON.stringify(spec) ?? String(spec);
4842
+ const written = raw.length > APPROVER_WRITTEN_MAX ? `${raw.slice(0, APPROVER_WRITTEN_MAX - 1)}\u2026` : raw;
4843
+ const users = typeof spec === "object" && spec !== null ? spec.users : void 0;
4844
+ const approver = typeof users === "string" && USER_ID_SHAPED_RE.test(users) ? {
4845
+ users: [
4846
+ users
4847
+ ]
4848
+ } : "creator";
4849
+ const message = `approver ${written} is not an approver \u2014 legal: ${APPROVER_SPEC_SHAPES.join(" | ")}. 'creator' is the person who started the run: write approver:'creator' for "ask me" / "I approve"; {users:[\u2026]} takes user ids, never emails, names or {type:'user'}` + (approver === "creator" ? "" : `; here: approver:${JSON.stringify(approver)}`);
4850
+ return {
4851
+ approver,
4852
+ written,
4853
+ message
4854
+ };
4855
+ }
4363
4856
  function bindingRootsOk(template22) {
4364
4857
  const refs = [
4365
4858
  ...template22.matchAll(/\$\{\s*([A-Za-z_$][\w$]*)/g)
@@ -4384,7 +4877,19 @@ function validateApproverBlock(node, opts = {
4384
4877
  if (!r.success) {
4385
4878
  const users = spec?.users;
4386
4879
  if (Array.isArray(users) && users.length > APPROVER_SPEC_MAX_USERS) push("cap-exceeded", path3, `at most ${APPROVER_SPEC_MAX_USERS} users`);
4387
- else push("approver-invalid", path3, r.error.issues[0]?.message ?? "invalid approver");
4880
+ else {
4881
+ const refusal = describeApproverSpecRefusal(spec);
4882
+ issues.push({
4883
+ code: "approver-invalid",
4884
+ path: path3,
4885
+ severity: "error",
4886
+ message: refusal.message,
4887
+ repair: {
4888
+ approver: refusal.approver,
4889
+ written: refusal.written
4890
+ }
4891
+ });
4892
+ }
4388
4893
  return;
4389
4894
  }
4390
4895
  const s = r.data;
@@ -4452,7 +4957,7 @@ function liftRenderedApprover(row, rendered) {
4452
4957
  }
4453
4958
  function collectEnvTemplateKeys(value22) {
4454
4959
  const keys = /* @__PURE__ */ new Set();
4455
- const walk2 = /* @__PURE__ */ __name3((v) => {
4960
+ const walk22 = /* @__PURE__ */ __name3((v) => {
4456
4961
  if (isEnvRef(v)) {
4457
4962
  keys.add(v.__envRef);
4458
4963
  return;
@@ -4460,26 +4965,26 @@ function collectEnvTemplateKeys(value22) {
4460
4965
  if (typeof v === "string") {
4461
4966
  if (looksLikeEmbeddedJson(v)) {
4462
4967
  try {
4463
- walk2(JSON.parse(v));
4968
+ walk22(JSON.parse(v));
4464
4969
  } catch {
4465
4970
  }
4466
4971
  }
4467
4972
  return;
4468
4973
  }
4469
4974
  if (Array.isArray(v)) {
4470
- for (const e of v) walk2(e);
4975
+ for (const e of v) walk22(e);
4471
4976
  return;
4472
4977
  }
4473
- if (v && typeof v === "object") for (const e of Object.values(v)) walk2(e);
4978
+ if (v && typeof v === "object") for (const e of Object.values(v)) walk22(e);
4474
4979
  }, "walk");
4475
- walk2(value22);
4980
+ walk22(value22);
4476
4981
  return [
4477
4982
  ...keys
4478
4983
  ].sort();
4479
4984
  }
4480
4985
  function substituteEnvRefs(value22, overlay) {
4481
4986
  const missing = /* @__PURE__ */ new Set();
4482
- const walk2 = /* @__PURE__ */ __name3((v, slot = false) => {
4987
+ const walk22 = /* @__PURE__ */ __name3((v, slot = false) => {
4483
4988
  if (isEnvRef(v)) {
4484
4989
  if (Object.prototype.hasOwnProperty.call(overlay, v.__envRef)) {
4485
4990
  const s = overlay[v.__envRef];
@@ -4496,22 +5001,22 @@ function substituteEnvRefs(value22, overlay) {
4496
5001
  const cfg = JSON.parse(v);
4497
5002
  if (!cfg || typeof cfg !== "object" || Array.isArray(cfg)) return v;
4498
5003
  const out = {};
4499
- for (const [k, e] of Object.entries(cfg)) out[k] = walk2(e, true);
5004
+ for (const [k, e] of Object.entries(cfg)) out[k] = walk22(e, true);
4500
5005
  return canonicalJson(out);
4501
5006
  } catch {
4502
5007
  return v;
4503
5008
  }
4504
5009
  }
4505
- if (Array.isArray(v)) return v.map((e) => walk2(e));
5010
+ if (Array.isArray(v)) return v.map((e) => walk22(e));
4506
5011
  if (v && typeof v === "object") {
4507
5012
  const out = {};
4508
- for (const [k, e] of Object.entries(v)) out[k] = walk2(e);
5013
+ for (const [k, e] of Object.entries(v)) out[k] = walk22(e);
4509
5014
  return out;
4510
5015
  }
4511
5016
  return v;
4512
5017
  }, "walk");
4513
5018
  return {
4514
- value: walk2(value22),
5019
+ value: walk22(value22),
4515
5020
  missing: [
4516
5021
  ...missing
4517
5022
  ].sort()
@@ -4740,26 +5245,27 @@ function needsInheritedWorkspace(graph) {
4740
5245
  }
4741
5246
  return false;
4742
5247
  }
4743
- var __defProp3, __name3, WORKFLOW_SIDE_EFFECTS, WORKFLOW_JOB_RESOURCES, SideEffectsSchema, JobResourcesSchema, WORKFLOW_ARM_SUBRUN_ID, SLEEP_UNTIL_REPLACEMENT, WORKFLOW_CAPS_DEFAULT, WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS, WORKFLOW_AGENT_DEFAULT_TIMEOUT_SECONDS, WORKFLOW_JOB_DEFAULT_TIMEOUT_SECONDS, WORKFLOW_FOREACH_DEFAULT_CONCURRENCY, WORKFLOW_FOREACH_DEFAULT_MAX_ITEMS, WORKFLOW_LOOP_DEFAULT_MAX_ITERATIONS, WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS, WORKFLOW_SIGNAL_DEFAULT_SOURCES, clone, CONNECTION_ID_HEX_RE, WORKFLOW_JOB_TOOLS, WORKFLOW_JOB_MAX_WORKTREE_ARMS, workspaceOf, mountsWorkspace, isJobTier, jobToolsOf, schemaIsArray, singleId, armId, TEMPLATE_STEP_REF, EDITABLE_PATH_RE, PREDICATE_OPS, isPredicateScalar, GRAPH_HASH_PREFIX, WorkflowPlanError, SINGLE_STEP_KINDS, isSingleStep, singleStepId, joinIdOf, containerIdOf, PATH_PLACEHOLDER, MISSING, stepIdOf, cmp, eq, ne, gt, gte, lt, lte, inSet, notIn, exists, notExists, truthy, falsy, and, or, not, WorkflowTemplateError, TEMPLATE_PLACEHOLDER, TEMPLATE_NAMESPACES, fromInit, fromStep, value, template, fromRequest, rows, fromKnowledge, CONTINUED_FAILURE_TAG, CONTINUED_FAILURE_DEFAULT_CODE, CONTINUED_FAILURE_OUTPUT_SCHEMA, CONTINUED_FAILURE_LEAF_PATHS, nodeIdOf, branchArmId, canonical, sortKeys, JOIN, entryOfJoin, FORCE_CANCEL_STALE_MS, TERMINAL, IN_FLIGHT, n, MAX_HOLIDAYS, MAX_WALK_DAYS, HHMM, YMD, MS_PER_MIN, MS_PER_DAY, MON_FRI, supportedTz, fmtCache, WEEKDAYS, JSON_PATCH_OPS, JSON_PATCH_MAX_OPS, JSON_PATCH_MAX_VALUE_BYTES, JSON_PATCH_MAX_TOTAL_BYTES, SEGMENT_RE, APPROVER_SPEC_MAX_USERS, ESCALATION_MAX_HOPS, TemplateBindingSchema, ApproverSpecSchema, FourEyesSchema, EscalationHopSchema, TerminalOutcomeSchema, ApprovalOnTimeoutSchema, BINDING_ROOTS, WORKFLOW_ENV_OVERLAY_MAX_KEYS, WORKFLOW_ENV_OVERLAY_MAX_VALUE_BYTES, WORKFLOW_ENV_TEMPLATE_SECRET_KEY_RE, isEnvRef, looksLikeEmbeddedJson, ZERO, isRecord2;
5248
+ var __defProp3, __name3, SideEffectsSchema, JobResourcesSchema, WORKFLOW_ARM_SUBRUN_ID, WORKSPACE_TEMPLATE_EXPR_RE, SLEEP_UNTIL_REPLACEMENT, WORKFLOW_CAPS_DEFAULT, WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS, WORKFLOW_AGENT_DEFAULT_TIMEOUT_SECONDS, WORKFLOW_JOB_DEFAULT_TIMEOUT_SECONDS, WORKFLOW_FOREACH_DEFAULT_CONCURRENCY, WORKFLOW_FOREACH_DEFAULT_MAX_ITEMS, WORKFLOW_LOOP_DEFAULT_MAX_ITERATIONS, WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS, WORKFLOW_SIGNAL_DEFAULT_SOURCES, clone, CONNECTION_ID_HEX_RE, WORKFLOW_JOB_TOOLS, WORKFLOW_JOB_MAX_WORKTREE_ARMS, workspaceOf, mountsWorkspace, isJobTier, jobToolsOf, schemaIsArray, isHitlNode, isSingleStep, singleId, armId, TEMPLATE_STEP_REF, EDITABLE_PATH_RE, PREDICATE_OPS, isPredicateScalar, GRAPH_HASH_PREFIX, WorkflowPlanError, isArmStep, armStepId, armStepKind, joinIdOf, containerIdOf, PATH_PLACEHOLDER, MISSING, stepIdOf, cmp, eq, ne, gt, gte, lt, lte, inSet, notIn, exists, notExists, truthy, falsy, and, or, not, WorkflowTemplateError, TEMPLATE_PLACEHOLDER, TEMPLATE_NAMESPACES, fromInit, fromStep, value, template, fromRequest, rows, fromKnowledge, CONTINUED_FAILURE_TAG, CONTINUED_FAILURE_DEFAULT_CODE, CONTINUED_FAILURE_OUTPUT_SCHEMA, CONTINUED_FAILURE_LEAF_PATHS, isHitlNode2, nodeIdOf, GOAL_JUDGE_STEP_ID, NON_LEAF_KINDS, CONDITIONAL_JOIN_ID, branchArmId, canonical, sortKeys, JOIN, entryOfJoin, FORCE_CANCEL_STALE_MS, TERMINAL, IN_FLIGHT, n, STEP_ERROR_DETAIL_KEYS, STEP_ERROR_DETAIL_MAX_BYTES, DETAIL_MAX_DEPTH, DETAIL_MAX_ITEMS, MAX_HOLIDAYS, MAX_WALK_DAYS, HHMM, YMD, MS_PER_MIN, MS_PER_DAY, MON_FRI, supportedTz, fmtCache, WEEKDAYS, JSON_PATCH_OPS, JSON_PATCH_MAX_OPS, JSON_PATCH_MAX_VALUE_BYTES, JSON_PATCH_MAX_TOTAL_BYTES, SEGMENT_RE, APPROVER_SPEC_MAX_USERS, ESCALATION_MAX_HOPS, TemplateBindingSchema, ApproverSpecSchema, FourEyesSchema, EscalationHopSchema, TerminalOutcomeSchema, ApprovalOnTimeoutSchema, APPROVER_SPEC_SHAPES, APPROVER_WRITTEN_MAX, USER_ID_SHAPED_RE, BINDING_ROOTS, WORKFLOW_ENV_OVERLAY_MAX_KEYS, WORKFLOW_ENV_OVERLAY_MAX_VALUE_BYTES, WORKFLOW_ENV_TEMPLATE_SECRET_KEY_RE, isEnvRef, looksLikeEmbeddedJson, ZERO, isRecord2;
4744
5249
  var init_dist2 = __esm({
4745
5250
  "../workflow-graph/dist/index.mjs"() {
4746
5251
  "use strict";
4747
5252
  init_dist();
4748
5253
  init_dist();
5254
+ init_dist();
5255
+ init_dist();
5256
+ init_dist();
5257
+ init_dist();
5258
+ init_dist();
4749
5259
  __defProp3 = Object.defineProperty;
4750
5260
  __name3 = /* @__PURE__ */ __name((target, value22) => __defProp3(target, "name", { value: value22, configurable: true }), "__name");
4751
- WORKFLOW_SIDE_EFFECTS = [
4752
- "none",
4753
- "external"
4754
- ];
4755
- WORKFLOW_JOB_RESOURCES = [
4756
- "small",
4757
- "medium",
4758
- "large"
4759
- ];
4760
5261
  SideEffectsSchema = z4.enum(WORKFLOW_SIDE_EFFECTS);
4761
5262
  JobResourcesSchema = z4.enum(WORKFLOW_JOB_RESOURCES);
4762
5263
  WORKFLOW_ARM_SUBRUN_ID = "$arm";
5264
+ WORKSPACE_TEMPLATE_EXPR_RE = /^\$\{\s*(?:initData|input)\.([^}]+?)\s*\}$/;
5265
+ __name(workspaceTemplatePath, "workspaceTemplatePath");
5266
+ __name3(workspaceTemplatePath, "workspaceTemplatePath");
5267
+ __name(retryBackoffs, "retryBackoffs");
5268
+ __name3(retryBackoffs, "retryBackoffs");
4763
5269
  SLEEP_UNTIL_REPLACEMENT = Object.freeze({
4764
5270
  type: "sleep",
4765
5271
  duration: 6e4
@@ -4795,6 +5301,8 @@ var init_dist2 = __esm({
4795
5301
  __name3(fillPolicy, "fillPolicy");
4796
5302
  __name(fillSingle, "fillSingle");
4797
5303
  __name3(fillSingle, "fillSingle");
5304
+ __name(fillHitl, "fillHitl");
5305
+ __name3(fillHitl, "fillHitl");
4798
5306
  __name(fillArm, "fillArm");
4799
5307
  __name3(fillArm, "fillArm");
4800
5308
  __name(fillEntry, "fillEntry");
@@ -4838,11 +5346,15 @@ var init_dist2 = __esm({
4838
5346
  if (t === void 0) return void 0;
4839
5347
  return Array.isArray(t) ? t.includes("array") : t === "array";
4840
5348
  }, "schemaIsArray");
5349
+ isHitlNode = /* @__PURE__ */ __name3((n2) => isWorkflowHitlEntryType(n2.type), "isHitlNode");
5350
+ isSingleStep = /* @__PURE__ */ __name3((n2) => !isHitlNode(n2), "isSingleStep");
4841
5351
  singleId = /* @__PURE__ */ __name3((s) => s.type === "step" ? s.step.id : s.id, "singleId");
4842
5352
  armId = /* @__PURE__ */ __name3((a) => a.type === "mapping" ? a.id : singleId(a), "armId");
4843
5353
  TEMPLATE_STEP_REF = /\$\{\s*stepResults\.([A-Za-z0-9_\-]+)/g;
4844
5354
  __name(templateStepRefs, "templateStepRefs");
4845
5355
  __name3(templateStepRefs, "templateStepRefs");
5356
+ __name(readMapConfig, "readMapConfig");
5357
+ __name3(readMapConfig, "readMapConfig");
4846
5358
  __name(mapConfigStepRefs, "mapConfigStepRefs");
4847
5359
  __name3(mapConfigStepRefs, "mapConfigStepRefs");
4848
5360
  __name(nodeStepRefs, "nodeStepRefs");
@@ -4892,14 +5404,9 @@ var init_dist2 = __esm({
4892
5404
  this.name = "WorkflowPlanError";
4893
5405
  }
4894
5406
  };
4895
- SINGLE_STEP_KINDS = {
4896
- step: "code",
4897
- agent: "agent",
4898
- tool: "tool",
4899
- workflow: "subrun"
4900
- };
4901
- isSingleStep = /* @__PURE__ */ __name3((e) => e.type === "step" || e.type === "agent" || e.type === "tool" || e.type === "workflow", "isSingleStep");
4902
- singleStepId = /* @__PURE__ */ __name3((e) => e.type === "step" ? e.step.id : e.id, "singleStepId");
5407
+ isArmStep = /* @__PURE__ */ __name3((e) => isWorkflowArmEntryType(e.type), "isArmStep");
5408
+ armStepId = /* @__PURE__ */ __name3((e) => e.type === "step" ? e.step.id : e.id, "armStepId");
5409
+ armStepKind = /* @__PURE__ */ __name3((e) => WORKFLOW_ARM_ENTRY_STEP_KINDS[e.type], "armStepKind");
4903
5410
  joinIdOf = /* @__PURE__ */ __name3((entryId) => `${entryId}.join`, "joinIdOf");
4904
5411
  containerIdOf = /* @__PURE__ */ __name3((type, entryIndex) => `${type}@${entryIndex}`, "containerIdOf");
4905
5412
  __name(compilePlan, "compilePlan");
@@ -5007,8 +5514,12 @@ var init_dist2 = __esm({
5007
5514
  this.name = "WorkflowTemplateError";
5008
5515
  }
5009
5516
  };
5517
+ __name(isMapConfigObject, "isMapConfigObject");
5518
+ __name3(isMapConfigObject, "isMapConfigObject");
5010
5519
  __name(parseMapConfig, "parseMapConfig");
5011
5520
  __name3(parseMapConfig, "parseMapConfig");
5521
+ __name(mapConfigWire, "mapConfigWire");
5522
+ __name3(mapConfigWire, "mapConfigWire");
5012
5523
  TEMPLATE_PLACEHOLDER = /\$\{([^}]*)\}/g;
5013
5524
  TEMPLATE_NAMESPACES = [
5014
5525
  "initData",
@@ -5113,6 +5624,7 @@ var init_dist2 = __esm({
5113
5624
  __name3(continuedFailureValue, "continuedFailureValue");
5114
5625
  __name(isContinuedFailureValue, "isContinuedFailureValue");
5115
5626
  __name3(isContinuedFailureValue, "isContinuedFailureValue");
5627
+ isHitlNode2 = /* @__PURE__ */ __name3((n2) => isWorkflowHitlEntryType(n2.type), "isHitlNode");
5116
5628
  __name(lowerContainerArm, "lowerContainerArm");
5117
5629
  __name3(lowerContainerArm, "lowerContainerArm");
5118
5630
  nodeIdOf = /* @__PURE__ */ __name3((n2) => n2.type === "step" ? n2.step.id : n2.id, "nodeIdOf");
@@ -5120,6 +5632,24 @@ var init_dist2 = __esm({
5120
5632
  __name3(entryIds, "entryIds");
5121
5633
  __name(resolvePlacements, "resolvePlacements");
5122
5634
  __name3(resolvePlacements, "resolvePlacements");
5635
+ GOAL_JUDGE_STEP_ID = "__goal_judge";
5636
+ NON_LEAF_KINDS = /* @__PURE__ */ new Set([
5637
+ "foreach",
5638
+ "branch"
5639
+ ]);
5640
+ CONDITIONAL_JOIN_ID = /^conditional@\d+\.join$/;
5641
+ __name(isConditionalJoinId, "isConditionalJoinId");
5642
+ __name3(isConditionalJoinId, "isConditionalJoinId");
5643
+ __name(isPlainObject, "isPlainObject");
5644
+ __name3(isPlainObject, "isPlainObject");
5645
+ __name(leafValue, "leafValue");
5646
+ __name3(leafValue, "leafValue");
5647
+ __name(runOutputLeaves, "runOutputLeaves");
5648
+ __name3(runOutputLeaves, "runOutputLeaves");
5649
+ __name(deriveRunOutput, "deriveRunOutput");
5650
+ __name3(deriveRunOutput, "deriveRunOutput");
5651
+ __name(subrunSettledOutput, "subrunSettledOutput");
5652
+ __name3(subrunSettledOutput, "subrunSettledOutput");
5123
5653
  __name(seedLedgerFromRun, "seedLedgerFromRun");
5124
5654
  __name3(seedLedgerFromRun, "seedLedgerFromRun");
5125
5655
  branchArmId = /* @__PURE__ */ __name3((arm) => arm.type === "step" ? arm.step.id : arm.id, "branchArmId");
@@ -5176,6 +5706,43 @@ var init_dist2 = __esm({
5176
5706
  __name3(runWorkspaceView, "runWorkspaceView");
5177
5707
  __name(toWorkflowRunSummary, "toWorkflowRunSummary");
5178
5708
  __name3(toWorkflowRunSummary, "toWorkflowRunSummary");
5709
+ STEP_ERROR_DETAIL_KEYS = [
5710
+ "reason",
5711
+ "key",
5712
+ "integrationType",
5713
+ "candidates",
5714
+ "connectionId",
5715
+ "status",
5716
+ "code",
5717
+ "providerStatus",
5718
+ "model",
5719
+ "turnIndex",
5720
+ "message",
5721
+ // LUA-655: `output_schema_invalid` — the Ajv issues ({path, message}, ≤ 20, scrubbed at the source too) and the
5722
+ // in-session repair rounds the attempt spent.
5723
+ "issues",
5724
+ "repairRounds",
5725
+ // LUA-669 (#2446 review 4): the subrun failures — `subrun_<status>` names the child run and how it ended
5726
+ // (`childStatus`, `childReason: 'max_duration'` under `subrun_timed_out`), `subrun_depth_exceeded` its `depth` /
5727
+ // `max`, and every refusal the target `workflowId`. Short scalars only: the child's whole `childError` and the
5728
+ // cycle walk's `ancestors` stay off the wire — the child run's own R4 carries its error.
5729
+ "childRunId",
5730
+ "childStatus",
5731
+ "childReason",
5732
+ "max",
5733
+ "depth",
5734
+ "workflowId",
5735
+ // LUA-696 (review 2): the `ctx.once` key of an `effect_in_doubt` park — the step site stamps it here (scrubbed)
5736
+ // beside `park.effectKey`; a key is user text and leaves scrubbed like every other string leaf.
5737
+ "effectKey"
5738
+ ];
5739
+ STEP_ERROR_DETAIL_MAX_BYTES = 8 * 1024;
5740
+ DETAIL_MAX_DEPTH = 4;
5741
+ DETAIL_MAX_ITEMS = 100;
5742
+ __name(scrubDetailValue, "scrubDetailValue");
5743
+ __name3(scrubDetailValue, "scrubDetailValue");
5744
+ __name(stepErrorDetail, "stepErrorDetail");
5745
+ __name3(stepErrorDetail, "stepErrorDetail");
5179
5746
  MAX_HOLIDAYS = 366;
5180
5747
  MAX_WALK_DAYS = 400;
5181
5748
  HHMM = /^([01]\d|2[0-3]):([0-5]\d)$/;
@@ -5321,6 +5888,18 @@ var init_dist2 = __esm({
5321
5888
  EscalationHopSchema
5322
5889
  ])).min(1).max(ESCALATION_MAX_HOPS + 1)
5323
5890
  ]);
5891
+ APPROVER_SPEC_SHAPES = [
5892
+ "'creator'",
5893
+ "'org-admins'",
5894
+ "{users:[userId, \u2026]}",
5895
+ "{role:roleName}",
5896
+ "{group:groupName}",
5897
+ "{governance:{policyId}}"
5898
+ ];
5899
+ APPROVER_WRITTEN_MAX = 120;
5900
+ USER_ID_SHAPED_RE = /^[^\s@]{1,128}$/;
5901
+ __name(describeApproverSpecRefusal, "describeApproverSpecRefusal");
5902
+ __name3(describeApproverSpecRefusal, "describeApproverSpecRefusal");
5324
5903
  BINDING_ROOTS = [
5325
5904
  "initData",
5326
5905
  "stepResults",
@@ -5476,7 +6055,12 @@ function materializeEntry(entry, steps) {
5476
6055
  }
5477
6056
  }
5478
6057
  function graphHasHitl(graph, steps) {
5479
- if (graph.some((e) => e.type === "approval" || e.type === "waitForSignal")) return true;
6058
+ for (const e of graph) {
6059
+ if (isHitlEntry(e)) return true;
6060
+ if (e.type === "parallel" && e.steps.some(isHitlEntry)) return true;
6061
+ if (e.type === "conditional" && (e.steps.some(isHitlEntry) || isHitlEntry(e.otherwise))) return true;
6062
+ if ((e.type === "foreach" || e.type === "loop") && isHitlEntry(e.step)) return true;
6063
+ }
5480
6064
  return Object.values(steps).some((s) => s.suspendSchema !== void 0);
5481
6065
  }
5482
6066
  function createWorkflow(cfg) {
@@ -5510,10 +6094,11 @@ function defineWorkflow(cfg, build) {
5510
6094
  if (!(wf instanceof LuaWorkflow)) throw new LuaWorkflowBuildError("invalid-envelope", "defineWorkflow: the build callback must return `wf\u2026.commit()`");
5511
6095
  return wf;
5512
6096
  }
5513
- var init2, state2, lit2, eq2, ne2, gt2, gte2, lt2, lte2, inSet2, notIn2, exists2, notExists2, truthy2, falsy2, and2, or2, not2, fromInit2, fromStep2, value2, template2, fromRequest2, rows2, fromKnowledge2, LuaWorkflowBuildError, STEP_ID_RE, WORKFLOW_NAME_RE, WORKFLOW_MAX_PARALLEL_ARMS, WORKFLOW_MAX_FOREACH_CONCURRENCY, WORKFLOW_MAX_FOREACH_ITEMS, WORKFLOW_WORKER_MAX_TIMEOUT_SECONDS, WORKFLOW_JOB_SEGMENT_MAX_SECONDS, WORKFLOW_JOB_MAX_TIMEOUT_SECONDS, WORKFLOW_LOOP_INTERVAL_MAX_SECONDS, WORKFLOW_FOREACH_RATE_MAX_PER_SECOND, WORKFLOW_SPECIALIST_ROLE_MAX_INSTRUCTIONS, WORKFLOW_DEFAULT_MAX_DURATION_SECONDS, WORKFLOW_HITL_MAX_DURATION_SECONDS, SECRET_KEY_RE, isZod, defined, templateText, assertNoClosure, assertPredicate, assertRetry, assertTimeout, envRefKeys, refToDescriptor, __workflowCommitHook, LuaWorkflow, WorkflowBuilderImpl, EDITABLE_PATH_RE2;
6097
+ var init2, state2, lit2, eq2, ne2, gt2, gte2, lt2, lte2, inSet2, notIn2, exists2, notExists2, truthy2, falsy2, and2, or2, not2, fromInit2, fromStep2, value2, template2, fromRequest2, rows2, fromKnowledge2, LuaWorkflowBuildError, STEP_ID_RE, WORKFLOW_NAME_RE, WORKFLOW_MAX_PARALLEL_ARMS, WORKFLOW_MAX_FOREACH_CONCURRENCY, WORKFLOW_MAX_FOREACH_ITEMS, WORKFLOW_WORKER_MAX_TIMEOUT_SECONDS, WORKFLOW_JOB_SEGMENT_MAX_SECONDS, WORKFLOW_JOB_MAX_TIMEOUT_SECONDS, WORKFLOW_LOOP_INTERVAL_MAX_SECONDS, WORKFLOW_FOREACH_RATE_MAX_PER_SECOND, WORKFLOW_SPECIALIST_ROLE_MAX_INSTRUCTIONS, WORKFLOW_DEFAULT_MAX_DURATION_SECONDS, WORKFLOW_HITL_MAX_DURATION_SECONDS, SECRET_KEY_RE, isZod, defined, templateText, assertNoClosure, assertPredicate, assertRetry, assertTimeout, envRefKeys, refToDescriptor, __workflowCommitHook, LuaWorkflow, isHitlEntry, WorkflowBuilderImpl, EDITABLE_PATH_RE2;
5514
6098
  var init_workflow = __esm({
5515
6099
  "src/types/workflow.ts"() {
5516
6100
  "use strict";
6101
+ init_dist();
5517
6102
  init_dist2();
5518
6103
  __name(createStep, "createStep");
5519
6104
  __name(step2, "step");
@@ -5596,7 +6181,7 @@ var init_workflow = __esm({
5596
6181
  }, "assertPredicate");
5597
6182
  assertRetry = /* @__PURE__ */ __name((r, id) => {
5598
6183
  if (!r) return;
5599
- if (r.backoff !== void 0 && r.backoff !== "fixed" && r.backoff !== "exponential") throw new LuaWorkflowBuildError("backoff-invalid", `"${id}": retry.backoff must be 'fixed' | 'exponential'`);
6184
+ if (r.backoff !== void 0 && !WORKFLOW_RETRY_BACKOFFS.includes(r.backoff)) throw new LuaWorkflowBuildError("backoff-invalid", `"${id}": retry.backoff must be ${WORKFLOW_RETRY_BACKOFFS.map((b) => `'${b}'`).join(" | ")}`);
5600
6185
  if (r.maxBackoffSeconds !== void 0) {
5601
6186
  if (r.backoff !== "exponential") throw new LuaWorkflowBuildError("backoff-invalid", `"${id}": retry.maxBackoffSeconds is only meaningful with backoff:'exponential'`);
5602
6187
  if (r.maxBackoffSeconds <= 0 || r.backoffSeconds !== void 0 && r.maxBackoffSeconds < r.backoffSeconds) throw new LuaWorkflowBuildError("backoff-invalid", `"${id}": retry.maxBackoffSeconds must be > 0 and \u2265 backoffSeconds`);
@@ -5718,6 +6303,7 @@ var init_workflow = __esm({
5718
6303
  };
5719
6304
  __name(stepNodeOf, "stepNodeOf");
5720
6305
  __name(materializeEntry, "materializeEntry");
6306
+ isHitlEntry = /* @__PURE__ */ __name((n2) => isWorkflowHitlEntryType(n2?.type), "isHitlEntry");
5721
6307
  __name(graphHasHitl, "graphHasHitl");
5722
6308
  WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
5723
6309
  static {
@@ -5770,7 +6356,6 @@ var init_workflow = __esm({
5770
6356
  const [mapping, target] = arm;
5771
6357
  if (target === void 0 || arm.length < 2) throw new LuaWorkflowBuildError("container-arm-empty", `${where}: a bare mapping arm has nothing to run`);
5772
6358
  if (!mapping || typeof mapping !== "object" || Array.isArray(mapping)) throw new LuaWorkflowBuildError("mapping-placement", `${where}: the arm head must be a map config object`);
5773
- if (mapping.type === "approval" || target.type === "approval") throw new LuaWorkflowBuildError("approval-inside-container", `${where}: approval / waitForSignal are top-level only in v1`);
5774
6359
  assertNoClosure(mapping, `${where} arm map`);
5775
6360
  this.recordEnvRefs(mapping);
5776
6361
  const inner = this.armRef(target, where);
@@ -5788,8 +6373,9 @@ var init_workflow = __esm({
5788
6373
  if (typeof arm === "string") return {
5789
6374
  ref: arm
5790
6375
  };
5791
- if (arm && typeof arm === "object" && arm.type === "approval") {
5792
- throw new LuaWorkflowBuildError("approval-inside-container", `${where}: approval / waitForSignal are top-level only in v1`);
6376
+ if (arm && typeof arm === "object" && isHitlEntry(arm)) {
6377
+ const id = arm.id;
6378
+ throw new LuaWorkflowBuildError("invalid-step", `${where}: an approval / waitForSignal arm is placed by id \u2014 declare it with .approval(${JSON.stringify(id ?? "id")}, \u2026) / .waitForSignal(\u2026) and pass the id string`);
5793
6379
  }
5794
6380
  return {
5795
6381
  node: this.registerStep(arm, where)
@@ -5990,17 +6576,13 @@ var init_workflow = __esm({
5990
6576
  if (opts.workspace && opts.tier !== void 0 && opts.tier !== "job") throw new LuaWorkflowBuildError("workspace-requires-job-tier", `"${id}": a step mounting a workspace must be tier:'job'`);
5991
6577
  if (opts.harness !== void 0 && tier !== "job") throw new LuaWorkflowBuildError("harness-requires-job-tier", `"${id}": harness is only legal on a tier:'job' agent step`);
5992
6578
  if (opts.toolScope?.jobTools && tier !== "job") throw new LuaWorkflowBuildError("cap-exceeded", `"${id}": toolScope.jobTools require tier:'job' (job-tools-require-job-tier)`);
5993
- if (opts.maxTurns !== void 0) {
5994
- if (tier !== "job") throw new LuaWorkflowBuildError("max-turns-requires-job-tier", `"${id}": maxTurns is only legal on a tier:'job' agent step`);
5995
- if (!Number.isInteger(opts.maxTurns) || opts.maxTurns < 1 || opts.maxTurns > 500) throw new LuaWorkflowBuildError("max-turns-invalid", `"${id}": maxTurns must be an integer 1..500`);
5996
- }
5997
- if (opts.maxMessages !== void 0) {
5998
- if (tier !== "job") throw new LuaWorkflowBuildError("max-turns-requires-job-tier", `"${id}": maxMessages is only legal on a tier:'job' agent step`);
5999
- if (!Number.isInteger(opts.maxMessages) || opts.maxMessages < 1 || opts.maxMessages > 5e3) throw new LuaWorkflowBuildError("max-turns-invalid", `"${id}": maxMessages must be an integer 1..5000`);
6000
- }
6001
- if (opts.maxInputTokens !== void 0) {
6002
- if (tier !== "job") throw new LuaWorkflowBuildError("max-turns-requires-job-tier", `"${id}": maxInputTokens is only legal on a tier:'job' agent step`);
6003
- if (!Number.isInteger(opts.maxInputTokens) || opts.maxInputTokens < 1e6 || opts.maxInputTokens > 5e8) throw new LuaWorkflowBuildError("max-turns-invalid", `"${id}": maxInputTokens must be an integer 1000000..500000000`);
6579
+ for (const m of WORKFLOW_JOB_RANGE_MEMBERS) {
6580
+ if (opts[m] === void 0) continue;
6581
+ if (tier !== "job") throw new LuaWorkflowBuildError("max-turns-requires-job-tier", `"${id}": ${m} is only legal on a tier:'job' agent step`);
6582
+ if (!isWithinWorkflowJobRange(m, opts[m])) {
6583
+ const { min, max } = WORKFLOW_JOB_RANGES[m];
6584
+ throw new LuaWorkflowBuildError("max-turns-invalid", `"${id}": ${m} must be an integer ${min}..${max}`);
6585
+ }
6004
6586
  }
6005
6587
  assertTimeout({
6006
6588
  id,
@@ -6152,8 +6734,8 @@ var init_workflow = __esm({
6152
6734
  itemTimeout: opts.itemTimeout
6153
6735
  });
6154
6736
  return this.push({
6155
- kind: "entry",
6156
- entry: node
6737
+ kind: "declare",
6738
+ node
6157
6739
  });
6158
6740
  }
6159
6741
  waitForSignal(id, opts) {
@@ -6171,12 +6753,13 @@ var init_workflow = __esm({
6171
6753
  acceptedSources: opts.acceptedSources
6172
6754
  });
6173
6755
  return this.push({
6174
- kind: "entry",
6175
- entry: node
6756
+ kind: "declare",
6757
+ node
6176
6758
  });
6177
6759
  }
6178
6760
  workflow(id, ref, input, opts) {
6179
6761
  this.assertId(id, "workflow()");
6762
+ assertRetry(opts?.retry, id);
6180
6763
  const name = typeof ref === "string" ? ref : ref instanceof LuaWorkflow ? ref.getName() : void 0;
6181
6764
  if (!name) throw new LuaWorkflowBuildError("invalid-envelope", `workflow("${id}") needs a LuaWorkflow or a workflow name`);
6182
6765
  if (opts?.workspace === "inherit") {
@@ -6198,7 +6781,8 @@ var init_workflow = __esm({
6198
6781
  id,
6199
6782
  workflowId: name,
6200
6783
  input,
6201
- workspace: opts?.workspace
6784
+ workspace: opts?.workspace,
6785
+ retry: opts?.retry
6202
6786
  });
6203
6787
  return this.push({
6204
6788
  kind: "declare",
@@ -6212,7 +6796,7 @@ var init_workflow = __esm({
6212
6796
  const { graph, issues } = resolvePlacements(this.calls);
6213
6797
  const fatal = issues[0];
6214
6798
  if (fatal) {
6215
- const hint = fatal.code === "unknown-step-ref" ? "a string StepRef must name an entry declared by agentStep/specialistStep/toolStep/map(\u2026, { id })/workflow(\u2026) somewhere in the chain \u2014 before OR after the reference" : void 0;
6799
+ const hint = fatal.code === "unknown-step-ref" ? "a string StepRef must name an entry declared by agentStep/specialistStep/toolStep/map(\u2026, { id })/workflow(\u2026)/approval(\u2026)/waitForSignal(\u2026) somewhere in the chain \u2014 before OR after the reference" : void 0;
6216
6800
  throw new LuaWorkflowBuildError(fatal.code, fatal.message, hint);
6217
6801
  }
6218
6802
  if (graph.length === 0) throw new LuaWorkflowBuildError("empty-graph", `workflow "${this.config.name}" has no entries`);
@@ -6610,7 +7194,7 @@ var init_firebase_session_store = __esm({
6610
7194
  }), "currentFirebaseSessionEnvironment");
6611
7195
  __name(environmentKey, "environmentKey");
6612
7196
  __name(isMissing, "isMissing");
6613
- wait = /* @__PURE__ */ __name((milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), "wait");
7197
+ wait = /* @__PURE__ */ __name((milliseconds) => new Promise((resolve3) => setTimeout(resolve3, milliseconds)), "wait");
6614
7198
  FirebaseSessionStore = class {
6615
7199
  static {
6616
7200
  __name(this, "FirebaseSessionStore");
@@ -6878,13 +7462,13 @@ async function* parseSseStream(body, signal) {
6878
7462
  buffer += decoder.decode(value3, {
6879
7463
  stream: true
6880
7464
  });
6881
- let sep = buffer.search(/\r?\n\r?\n/);
6882
- while (sep !== -1) {
6883
- const block = buffer.slice(0, sep);
6884
- buffer = buffer.slice(sep).replace(/^\r?\n\r?\n/, "");
7465
+ let sep4 = buffer.search(/\r?\n\r?\n/);
7466
+ while (sep4 !== -1) {
7467
+ const block = buffer.slice(0, sep4);
7468
+ buffer = buffer.slice(sep4).replace(/^\r?\n\r?\n/, "");
6885
7469
  const frame = flush(block);
6886
7470
  if (frame) yield frame;
6887
- sep = buffer.search(/\r?\n\r?\n/);
7471
+ sep4 = buffer.search(/\r?\n\r?\n/);
6888
7472
  }
6889
7473
  }
6890
7474
  if (buffer.trim()) {
@@ -7103,7 +7687,7 @@ Check that your Lua login has access to this agent or organization.`);
7103
7687
  if (attempt < maxRetries) {
7104
7688
  const serverDelay = Number(lastResult?.error?.retryAfterSeconds ?? 0) * 1e3;
7105
7689
  const backoff = Math.max(this.calculateBackoff(attempt), serverDelay);
7106
- await new Promise((resolve) => setTimeout(resolve, backoff));
7690
+ await new Promise((resolve3) => setTimeout(resolve3, backoff));
7107
7691
  }
7108
7692
  }
7109
7693
  return lastResult;
@@ -7152,7 +7736,7 @@ Check that your Lua login has access to this agent or organization.`);
7152
7736
  async httpPostCoreDrainRetry(url, data, headers) {
7153
7737
  const first = await this.httpPostOnce(url, data, headers);
7154
7738
  if (!isCoreDrainApiError(first.error)) return first;
7155
- await new Promise((resolve) => setTimeout(resolve, coreDrainApiRetryDelayMs(first.error)));
7739
+ await new Promise((resolve3) => setTimeout(resolve3, coreDrainApiRetryDelayMs(first.error)));
7156
7740
  return this.httpPostOnce(url, data, headers);
7157
7741
  }
7158
7742
  /**
@@ -7526,11 +8110,560 @@ var init_artifact_loader = __esm({
7526
8110
  }
7527
8111
  });
7528
8112
 
8113
+ // ../shared-source-sync/dist/index.mjs
8114
+ import { createHash as createHash4 } from "crypto";
8115
+ import { extname } from "path";
8116
+ import { readdirSync, readFileSync as readFileSync3, statSync } from "fs";
8117
+ import { join as join4, sep } from "path";
8118
+ import { gunzipSync, gzipSync } from "zlib";
8119
+ import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync22, statSync as statSync2, writeFileSync } from "fs";
8120
+ import { dirname as dirname2, join as join22, resolve, sep as sep2 } from "path";
8121
+ import { posix } from "path";
8122
+ import { mkdirSync as mkdirSync2, readdirSync as readdirSync2, readFileSync as readFileSync32, statSync as statSync3, writeFileSync as writeFileSync2 } from "fs";
8123
+ import { dirname as dirname22, join as join32, resolve as resolve2, sep as sep3 } from "path";
8124
+ import { gunzipSync as gunzipSync2, gzipSync as gzipSync2 } from "zlib";
8125
+ function hashContentTruncated(content) {
8126
+ return createHash4("sha256").update(content).digest("hex").slice(0, FILE_HASH_LENGTH);
8127
+ }
8128
+ function sha256Hex(content) {
8129
+ return createHash4("sha256").update(content).digest("hex");
8130
+ }
8131
+ function matchesFileHash(hash, plaintext) {
8132
+ if (!/^(?:[a-f0-9]{16}|[a-f0-9]{64})$/.test(hash)) return false;
8133
+ if (sha256Hex(plaintext).startsWith(hash)) return true;
8134
+ return sha256Hex(plaintext.toString("utf-8")).startsWith(hash);
8135
+ }
8136
+ function combineFileHashes(files) {
8137
+ const sorted = [
8138
+ ...files
8139
+ ].sort((a, b) => a.relativePath.localeCompare(b.relativePath));
8140
+ return sha256Hex(sorted.map((f) => f.hash).join("|"));
8141
+ }
8142
+ function shouldSkipDirectory(name) {
8143
+ return SKIP_DIRECTORIES.has(name);
8144
+ }
8145
+ function shouldSkipFile(filePathOrName) {
8146
+ return filePathOrName.includes("node_modules") || filePathOrName.includes(".test.") || filePathOrName.includes(".spec.") || filePathOrName.includes("__tests__") || filePathOrName.endsWith(".d.ts") || filePathOrName.endsWith(".map") || filePathOrName.startsWith(".") || filePathOrName === "package-lock.json" || filePathOrName === "yarn.lock" || filePathOrName === "pnpm-lock.yaml";
8147
+ }
8148
+ function classifyFile(relPath) {
8149
+ return KIND_BY_EXT[extname(relPath)] ?? "other";
8150
+ }
8151
+ function walkWorkspace(rootDir, opts = {}) {
8152
+ const maxBytes = opts.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES;
8153
+ const refs = [];
8154
+ const contentByHash = /* @__PURE__ */ new Map();
8155
+ let totalSize = 0;
8156
+ const visit = /* @__PURE__ */ __name4((relPrefix) => {
8157
+ const absDir = relPrefix ? join4(rootDir, relPrefix) : rootDir;
8158
+ let entries;
8159
+ try {
8160
+ entries = readdirSync(absDir, {
8161
+ withFileTypes: true
8162
+ });
8163
+ } catch {
8164
+ return;
8165
+ }
8166
+ for (const entry of entries) {
8167
+ if (entry.isDirectory()) {
8168
+ if (shouldSkipDirectory(entry.name)) continue;
8169
+ if (shouldSkipFile(entry.name)) continue;
8170
+ visit(relPrefix ? `${relPrefix}${sep}${entry.name}` : entry.name);
8171
+ continue;
8172
+ }
8173
+ if (!entry.isFile()) continue;
8174
+ if (shouldSkipFile(entry.name)) continue;
8175
+ const rel = (relPrefix ? `${relPrefix}${sep}${entry.name}` : entry.name).split(sep).join("/");
8176
+ const abs = join4(rootDir, rel);
8177
+ let stats;
8178
+ try {
8179
+ stats = statSync(abs);
8180
+ } catch {
8181
+ continue;
8182
+ }
8183
+ if (stats.size > maxBytes) continue;
8184
+ let content;
8185
+ try {
8186
+ content = readFileSync3(abs);
8187
+ } catch {
8188
+ continue;
8189
+ }
8190
+ const hash = hashContentTruncated(content.toString("utf-8"));
8191
+ refs.push({
8192
+ relativePath: rel,
8193
+ hash,
8194
+ size: stats.size,
8195
+ type: classifyFile(rel)
8196
+ });
8197
+ if (!contentByHash.has(hash)) contentByHash.set(hash, content);
8198
+ totalSize += stats.size;
8199
+ }
8200
+ }, "visit");
8201
+ visit("");
8202
+ refs.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
8203
+ const projectHash = combineFileHashes(refs);
8204
+ return {
8205
+ files: refs,
8206
+ projectHash,
8207
+ totalSize,
8208
+ contentByHash
8209
+ };
8210
+ }
8211
+ async function uploadBlobs(opts) {
8212
+ const fetchFn = opts.fetch ?? fetch;
8213
+ const concurrency = opts.concurrency ?? DEFAULT_CONCURRENCY;
8214
+ const hashes = Object.keys(opts.uploadUrls);
8215
+ for (let i = 0; i < hashes.length; i += concurrency) {
8216
+ const batch = hashes.slice(i, i + concurrency);
8217
+ await Promise.all(batch.map(async (hash) => {
8218
+ const buf = opts.contentByHash.get(hash);
8219
+ if (!buf) {
8220
+ throw new Error(`uploadBlobs: no content for hash ${hash.slice(0, 12)}\u2026`);
8221
+ }
8222
+ const compressed = gzipSync(buf);
8223
+ const res = await fetchFn(opts.uploadUrls[hash], {
8224
+ method: "PUT",
8225
+ body: compressed,
8226
+ headers: {
8227
+ "Content-Type": "application/octet-stream"
8228
+ }
8229
+ });
8230
+ if (!res.ok) {
8231
+ throw new Error(`S3 upload failed for ${hash.slice(0, 12)}\u2026: ${res.status} ${res.statusText}`);
8232
+ }
8233
+ }));
8234
+ }
8235
+ return hashes.length;
8236
+ }
8237
+ function decodeBlob(buf) {
8238
+ if (buf.length >= 2 && buf[0] === 31 && buf[1] === 139) {
8239
+ try {
8240
+ return gunzipSync(buf);
8241
+ } catch {
8242
+ return buf;
8243
+ }
8244
+ }
8245
+ return buf;
8246
+ }
8247
+ function verifyDownloaded(hash, plaintext) {
8248
+ if (!matchesFileHash(hash, plaintext)) {
8249
+ throw new Error(`Blob ${hash.slice(0, 12)}\u2026 failed integrity verification: its content does not hash to its key (refusing to restore it)`);
8250
+ }
8251
+ return plaintext;
8252
+ }
8253
+ async function downloadBlobs(opts) {
8254
+ const fetchFn = opts.fetch ?? fetch;
8255
+ const concurrency = opts.concurrency ?? DEFAULT_CONCURRENCY;
8256
+ const out = /* @__PURE__ */ new Map();
8257
+ const entries = Object.entries(opts.urls);
8258
+ for (let i = 0; i < entries.length; i += concurrency) {
8259
+ const batch = entries.slice(i, i + concurrency);
8260
+ const downloaded = await Promise.all(batch.map(async ([hash, url]) => {
8261
+ const res = await fetchFn(url);
8262
+ if (!res.ok) {
8263
+ throw new Error(`S3 download failed for ${hash.slice(0, 12)}\u2026: ${res.status} ${res.statusText}`);
8264
+ }
8265
+ const ab = await res.arrayBuffer();
8266
+ const buf = Buffer.from(ab);
8267
+ return [
8268
+ hash,
8269
+ verifyDownloaded(hash, decodeBlob(buf))
8270
+ ];
8271
+ }));
8272
+ for (const [hash, buf] of downloaded) out.set(hash, buf);
8273
+ }
8274
+ return out;
8275
+ }
8276
+ function resolveBackupFileTarget(file, targetDir) {
8277
+ const base = resolve(targetDir);
8278
+ const sandboxed = file.external ? join22(base, ".lua", "external", file.relativePath) : join22(base, file.relativePath);
8279
+ const resolved = resolve(sandboxed);
8280
+ if (resolved !== base && !resolved.startsWith(base + sep2)) {
8281
+ throw new Error(`Backup entry escapes target directory: ${file.relativePath}`);
8282
+ }
8283
+ return resolved;
8284
+ }
8285
+ function restoreFromBlobs(manifest, blobs, targetDir, opts = {}) {
8286
+ let filesWritten = 0;
8287
+ let filesUnchanged = 0;
8288
+ let filesSkipped = 0;
8289
+ for (const file of manifest.files) {
8290
+ const content = blobs.get(file.hash);
8291
+ if (!content) {
8292
+ throw new Error(`Blob not found for hash: ${file.hash} (${file.relativePath})`);
8293
+ }
8294
+ const targetPath = resolveBackupFileTarget(file, targetDir);
8295
+ if (existsSync2(targetPath)) {
8296
+ const sameSize = statSync2(targetPath).size === content.length;
8297
+ if (sameSize && readFileSync22(targetPath).equals(content)) {
8298
+ filesUnchanged++;
8299
+ continue;
8300
+ }
8301
+ if (!opts.overwrite) {
8302
+ filesSkipped++;
8303
+ continue;
8304
+ }
8305
+ }
8306
+ mkdirSync(dirname2(targetPath), {
8307
+ recursive: true
8308
+ });
8309
+ writeFileSync(targetPath, content);
8310
+ filesWritten++;
8311
+ }
8312
+ return {
8313
+ filesWritten,
8314
+ filesUnchanged,
8315
+ filesSkipped
8316
+ };
8317
+ }
8318
+ function normalizeWorkspaceRelativePath(value3) {
8319
+ if (!value3 || value3.includes("\0")) return void 0;
8320
+ const withPortableSeparators = value3.replace(/\\/g, "/");
8321
+ if (withPortableSeparators.startsWith("/") || WINDOWS_ABSOLUTE_PATH.test(withPortableSeparators)) return void 0;
8322
+ const normalized = posix.normalize(withPortableSeparators);
8323
+ if (!normalized || normalized === "." || normalized === ".." || normalized.startsWith("../")) return void 0;
8324
+ return normalized;
8325
+ }
8326
+ function isCredentialPersistencePath(value3) {
8327
+ const normalized = normalizeWorkspaceRelativePath(value3);
8328
+ return normalized !== void 0 && CREDENTIAL_PATHS.has(normalized.toLowerCase());
8329
+ }
8330
+ async function pushAgentBackup(opts) {
8331
+ const snapshot = walkWorkspace(opts.workspaceDir, opts.walkOptions);
8332
+ const client = new BackupHttpClient(opts.http);
8333
+ const uniqueHashes = [
8334
+ ...new Set(snapshot.files.map((f) => f.hash))
8335
+ ];
8336
+ let filesUploaded = 0;
8337
+ if (uniqueHashes.length > 0) {
8338
+ const checked = await client.checkBlobsExist(uniqueHashes);
8339
+ if (checked.missing.length > 0) {
8340
+ const urls = await client.getBlobUploadUrls(checked.missing);
8341
+ filesUploaded = await uploadBlobs({
8342
+ uploadUrls: urls.urls,
8343
+ contentByHash: snapshot.contentByHash,
8344
+ fetch: opts.http.fetch,
8345
+ concurrency: opts.concurrency
8346
+ });
8347
+ }
8348
+ }
8349
+ const metadata = await client.saveManifest({
8350
+ projectHash: snapshot.projectHash,
8351
+ files: snapshot.files,
8352
+ version: opts.version,
8353
+ orgId: opts.orgId,
8354
+ createdBy: opts.createdBy ?? "cli",
8355
+ triggeredBy: opts.triggeredBy
8356
+ });
8357
+ return {
8358
+ projectHash: snapshot.projectHash,
8359
+ fileCount: snapshot.files.length,
8360
+ filesUploaded,
8361
+ activeVersion: metadata.activeVersion,
8362
+ metadata,
8363
+ files: snapshot.files
8364
+ };
8365
+ }
8366
+ async function pullAgentBackup(opts) {
8367
+ const client = new BackupHttpClient(opts.http);
8368
+ const manifest = await client.getManifest();
8369
+ const uniqueHashes = [
8370
+ ...new Set(manifest.files.map((f) => f.hash))
8371
+ ];
8372
+ const blobs = uniqueHashes.length ? await (async () => {
8373
+ const urls = await client.getBlobUrls(uniqueHashes);
8374
+ return downloadBlobs({
8375
+ urls: urls.urls,
8376
+ fetch: opts.http.fetch,
8377
+ concurrency: opts.concurrency
8378
+ });
8379
+ })() : /* @__PURE__ */ new Map();
8380
+ const result = restoreFromBlobs(manifest, blobs, opts.targetDir, opts.restore);
8381
+ return {
8382
+ ...result,
8383
+ manifest
8384
+ };
8385
+ }
8386
+ function encodeWorkspaceArchive(workspaceDir) {
8387
+ const files = {};
8388
+ try {
8389
+ walk2(workspaceDir, "", files);
8390
+ } catch {
8391
+ return null;
8392
+ }
8393
+ if (Object.keys(files).length === 0) return null;
8394
+ const gz = gzipSync2(Buffer.from(JSON.stringify(files), "utf8"));
8395
+ return gz.toString("base64");
8396
+ }
8397
+ function decodeWorkspaceArchive(archive, schemaVersion) {
8398
+ if (schemaVersion !== void 0 && schemaVersion !== ARCHIVE_SCHEMA_VERSION) {
8399
+ throw new Error(`Unsupported archive schema version: ${schemaVersion} (expected ${ARCHIVE_SCHEMA_VERSION})`);
8400
+ }
8401
+ const raw = gunzipSync2(Buffer.from(archive, "base64")).toString("utf8");
8402
+ const parsed = JSON.parse(raw);
8403
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
8404
+ throw new Error("Decoded archive is not a JSON object map");
8405
+ }
8406
+ return parsed;
8407
+ }
8408
+ function writeArchiveToWorkspace(workspaceDir, files) {
8409
+ const writes = [];
8410
+ for (const [relPath, content] of Object.entries(files)) {
8411
+ const normalized = normalizeWorkspaceRelativePath(relPath);
8412
+ if (!normalized) throw new Error(`Refusing to write invalid archived path: ${relPath}`);
8413
+ if (isCredentialPersistencePath(normalized)) {
8414
+ throw new Error(`Refusing to restore credential file: ${normalized}`);
8415
+ }
8416
+ writes.push({
8417
+ path: resolve2(workspaceDir, normalized),
8418
+ content
8419
+ });
8420
+ }
8421
+ for (const write of writes) {
8422
+ mkdirSync2(dirname22(write.path), {
8423
+ recursive: true
8424
+ });
8425
+ writeFileSync2(write.path, write.content, "utf8");
8426
+ }
8427
+ }
8428
+ function walk2(root, prefix, out) {
8429
+ const dir = prefix ? join32(root, prefix) : root;
8430
+ const entries = readdirSync2(dir, {
8431
+ withFileTypes: true
8432
+ });
8433
+ for (const entry of entries) {
8434
+ if (entry.isDirectory()) {
8435
+ if (shouldSkipDirectory(entry.name) || ARCHIVE_ONLY_SKIP_DIRECTORIES.has(entry.name) || shouldSkipFile(entry.name)) continue;
8436
+ walk2(root, prefix ? `${prefix}${sep3}${entry.name}` : entry.name, out);
8437
+ continue;
8438
+ }
8439
+ if (!entry.isFile()) continue;
8440
+ if (shouldSkipFile(entry.name)) continue;
8441
+ const relPath = (prefix ? `${prefix}${sep3}${entry.name}` : entry.name).split(sep3).join("/");
8442
+ const abs = join32(dir, entry.name);
8443
+ if (statSync3(abs).size > DEFAULT_MAX_FILE_BYTES) continue;
8444
+ try {
8445
+ out[relPath] = readFileSync32(abs, "utf8");
8446
+ } catch {
8447
+ }
8448
+ }
8449
+ }
8450
+ var __defProp4, __name4, FILE_HASH_LENGTH, SKIP_DIRECTORIES, ARCHIVE_ONLY_SKIP_DIRECTORIES, DEFAULT_MAX_FILE_BYTES, KIND_BY_EXT, CHECK_BLOBS_MAX_HASHES, BackupHttpError, BackupHttpClient, DEFAULT_CONCURRENCY, CREDENTIAL_PATHS, WINDOWS_ABSOLUTE_PATH, ARCHIVE_SCHEMA_VERSION;
8451
+ var init_dist3 = __esm({
8452
+ "../shared-source-sync/dist/index.mjs"() {
8453
+ "use strict";
8454
+ __defProp4 = Object.defineProperty;
8455
+ __name4 = /* @__PURE__ */ __name((target, value3) => __defProp4(target, "name", { value: value3, configurable: true }), "__name");
8456
+ FILE_HASH_LENGTH = 16;
8457
+ __name(hashContentTruncated, "hashContentTruncated");
8458
+ __name4(hashContentTruncated, "hashContentTruncated");
8459
+ __name(sha256Hex, "sha256Hex");
8460
+ __name4(sha256Hex, "sha256Hex");
8461
+ __name(matchesFileHash, "matchesFileHash");
8462
+ __name4(matchesFileHash, "matchesFileHash");
8463
+ __name(combineFileHashes, "combineFileHashes");
8464
+ __name4(combineFileHashes, "combineFileHashes");
8465
+ SKIP_DIRECTORIES = /* @__PURE__ */ new Set([
8466
+ "node_modules",
8467
+ "dist",
8468
+ "dist-v2",
8469
+ ".git",
8470
+ ".lua",
8471
+ ".temp",
8472
+ "coverage",
8473
+ ".next",
8474
+ ".turbo"
8475
+ ]);
8476
+ ARCHIVE_ONLY_SKIP_DIRECTORIES = /* @__PURE__ */ new Set([
8477
+ "build"
8478
+ ]);
8479
+ DEFAULT_MAX_FILE_BYTES = 256 * 1024;
8480
+ __name(shouldSkipDirectory, "shouldSkipDirectory");
8481
+ __name4(shouldSkipDirectory, "shouldSkipDirectory");
8482
+ __name(shouldSkipFile, "shouldSkipFile");
8483
+ __name4(shouldSkipFile, "shouldSkipFile");
8484
+ KIND_BY_EXT = {
8485
+ ".ts": "source",
8486
+ ".tsx": "source",
8487
+ ".js": "source",
8488
+ ".jsx": "source",
8489
+ ".yaml": "config",
8490
+ ".yml": "config",
8491
+ ".json": "config",
8492
+ ".toml": "config"
8493
+ };
8494
+ __name(classifyFile, "classifyFile");
8495
+ __name4(classifyFile, "classifyFile");
8496
+ __name(walkWorkspace, "walkWorkspace");
8497
+ __name4(walkWorkspace, "walkWorkspace");
8498
+ CHECK_BLOBS_MAX_HASHES = 500;
8499
+ BackupHttpError = class extends Error {
8500
+ static {
8501
+ __name(this, "BackupHttpError");
8502
+ }
8503
+ static {
8504
+ __name4(this, "BackupHttpError");
8505
+ }
8506
+ status;
8507
+ endpoint;
8508
+ body;
8509
+ constructor(message, status, endpoint, body) {
8510
+ super(message), this.status = status, this.endpoint = endpoint, this.body = body;
8511
+ this.name = "BackupHttpError";
8512
+ }
8513
+ };
8514
+ BackupHttpClient = class {
8515
+ static {
8516
+ __name(this, "BackupHttpClient");
8517
+ }
8518
+ static {
8519
+ __name4(this, "BackupHttpClient");
8520
+ }
8521
+ options;
8522
+ fetchFn;
8523
+ constructor(options) {
8524
+ this.options = options;
8525
+ this.fetchFn = options.fetch ?? fetch;
8526
+ }
8527
+ url(path3) {
8528
+ const base = this.options.baseUrl.replace(/\/$/, "");
8529
+ return `${base}/developer/agents/${encodeURIComponent(this.options.agentId)}${path3}`;
8530
+ }
8531
+ async json(method, path3, body) {
8532
+ const endpoint = this.url(path3);
8533
+ const res = await this.fetchFn(endpoint, {
8534
+ method,
8535
+ headers: {
8536
+ Authorization: this.options.authHeader,
8537
+ ...body !== void 0 ? {
8538
+ "Content-Type": "application/json"
8539
+ } : {},
8540
+ Accept: "application/json"
8541
+ },
8542
+ body: body !== void 0 ? JSON.stringify(body) : void 0
8543
+ });
8544
+ if (!res.ok) {
8545
+ let text2;
8546
+ try {
8547
+ text2 = await res.text();
8548
+ } catch {
8549
+ text2 = void 0;
8550
+ }
8551
+ throw new BackupHttpError(`Backup request failed: ${method} ${path3} \u2192 ${res.status} ${res.statusText}`, res.status, endpoint, text2);
8552
+ }
8553
+ const text = await res.text();
8554
+ if (!text) return void 0;
8555
+ return JSON.parse(text);
8556
+ }
8557
+ /**
8558
+ * `POST /backup/check-blobs` — returns existing vs missing partition.
8559
+ *
8560
+ * LUA-675: the server caps one request at `CHECK_BLOBS_MAX_HASHES`; a
8561
+ * larger set is sent in sequential chunks and the partitions merged, so a
8562
+ * big workspace still pushes and the client never fans out on its own.
8563
+ */
8564
+ async checkBlobsExist(hashes) {
8565
+ if (hashes.length <= CHECK_BLOBS_MAX_HASHES) {
8566
+ return this.json("POST", "/backup/check-blobs", {
8567
+ hashes
8568
+ });
8569
+ }
8570
+ const merged = {
8571
+ missing: [],
8572
+ existing: [],
8573
+ results: {}
8574
+ };
8575
+ let unverified;
8576
+ for (let i = 0; i < hashes.length; i += CHECK_BLOBS_MAX_HASHES) {
8577
+ const part = await this.json("POST", "/backup/check-blobs", {
8578
+ hashes: hashes.slice(i, i + CHECK_BLOBS_MAX_HASHES)
8579
+ });
8580
+ merged.missing.push(...part.missing);
8581
+ merged.existing.push(...part.existing);
8582
+ Object.assign(merged.results, part.results);
8583
+ if (part.unverified) unverified = [
8584
+ ...unverified ?? [],
8585
+ ...part.unverified
8586
+ ];
8587
+ }
8588
+ return unverified ? {
8589
+ ...merged,
8590
+ unverified
8591
+ } : merged;
8592
+ }
8593
+ /** `POST /backup/blob-upload-urls` — presigned S3 PUT URLs. */
8594
+ getBlobUploadUrls(hashes) {
8595
+ return this.json("POST", "/backup/blob-upload-urls", {
8596
+ hashes
8597
+ });
8598
+ }
8599
+ /** `POST /backup/blob-urls` — presigned S3 GET URLs (for restore). */
8600
+ getBlobUrls(hashes) {
8601
+ return this.json("POST", "/backup/blob-urls", {
8602
+ hashes
8603
+ });
8604
+ }
8605
+ /** `POST /backup/manifest` — final step in a push; returns server metadata. */
8606
+ saveManifest(data) {
8607
+ return this.json("POST", "/backup/manifest", data);
8608
+ }
8609
+ /** `GET /backup` — metadata only, no file list. */
8610
+ getMetadata() {
8611
+ return this.json("GET", "/backup");
8612
+ }
8613
+ /** `GET /backup/manifest` — metadata + file list. */
8614
+ getManifest() {
8615
+ return this.json("GET", "/backup/manifest");
8616
+ }
8617
+ /** `GET /backup/check/:hash` — fast freshness probe. */
8618
+ checkBackupExists(hash) {
8619
+ return this.json("GET", `/backup/check/${encodeURIComponent(hash)}`);
8620
+ }
8621
+ };
8622
+ DEFAULT_CONCURRENCY = 10;
8623
+ __name(uploadBlobs, "uploadBlobs");
8624
+ __name4(uploadBlobs, "uploadBlobs");
8625
+ __name(decodeBlob, "decodeBlob");
8626
+ __name4(decodeBlob, "decodeBlob");
8627
+ __name(verifyDownloaded, "verifyDownloaded");
8628
+ __name4(verifyDownloaded, "verifyDownloaded");
8629
+ __name(downloadBlobs, "downloadBlobs");
8630
+ __name4(downloadBlobs, "downloadBlobs");
8631
+ __name(resolveBackupFileTarget, "resolveBackupFileTarget");
8632
+ __name4(resolveBackupFileTarget, "resolveBackupFileTarget");
8633
+ __name(restoreFromBlobs, "restoreFromBlobs");
8634
+ __name4(restoreFromBlobs, "restoreFromBlobs");
8635
+ CREDENTIAL_PATHS = /* @__PURE__ */ new Set([
8636
+ ".env",
8637
+ ".lua/config.json",
8638
+ ".claude/settings.local.json"
8639
+ ]);
8640
+ WINDOWS_ABSOLUTE_PATH = /^[a-z]:\//i;
8641
+ __name(normalizeWorkspaceRelativePath, "normalizeWorkspaceRelativePath");
8642
+ __name4(normalizeWorkspaceRelativePath, "normalizeWorkspaceRelativePath");
8643
+ __name(isCredentialPersistencePath, "isCredentialPersistencePath");
8644
+ __name4(isCredentialPersistencePath, "isCredentialPersistencePath");
8645
+ __name(pushAgentBackup, "pushAgentBackup");
8646
+ __name4(pushAgentBackup, "pushAgentBackup");
8647
+ __name(pullAgentBackup, "pullAgentBackup");
8648
+ __name4(pullAgentBackup, "pullAgentBackup");
8649
+ ARCHIVE_SCHEMA_VERSION = 1;
8650
+ __name(encodeWorkspaceArchive, "encodeWorkspaceArchive");
8651
+ __name4(encodeWorkspaceArchive, "encodeWorkspaceArchive");
8652
+ __name(decodeWorkspaceArchive, "decodeWorkspaceArchive");
8653
+ __name4(decodeWorkspaceArchive, "decodeWorkspaceArchive");
8654
+ __name(writeArchiveToWorkspace, "writeArchiveToWorkspace");
8655
+ __name4(writeArchiveToWorkspace, "writeArchiveToWorkspace");
8656
+ __name(walk2, "walk");
8657
+ __name4(walk2, "walk");
8658
+ }
8659
+ });
8660
+
7529
8661
  // src/api/backup.api.service.ts
7530
8662
  var init_backup_api_service = __esm({
7531
8663
  "src/api/backup.api.service.ts"() {
7532
8664
  "use strict";
7533
8665
  init_http_client();
8666
+ init_dist3();
7534
8667
  }
7535
8668
  });
7536
8669