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.
- package/dist/api-exports.d.ts +339 -102
- package/dist/api-exports.js +1334 -201
- package/dist/api-exports.js.map +1 -1
- package/dist/index.js +3287 -1634
- package/dist/index.js.map +1 -1
- package/dist/voice/test/index.d.ts +54 -54
- package/dist/workflow-builder.d.ts +224 -45
- package/dist/workflow-builder.js +747 -171
- package/dist/workflow-builder.js.map +1 -1
- package/docs/README.md +2 -2
- package/docs/api/LuaWorkflow.md +16 -16
- package/docs/api/Workflows.md +10 -0
- package/docs/workflows/correlation-keys.md +1 -0
- package/docs/workflows/limits.md +6 -0
- package/docs/workflows/script-form.md +20 -10
- package/docs/workflows/testing-offline.md +22 -20
- package/docs/workflows/workspaces-and-long-steps.md +36 -2
- package/package.json +3 -3
- package/template/examples/workflows/pr-review-round.ts +7 -3
- package/template/examples/workflows/ticket-to-pr.ts +43 -36
- package/template/package.json +1 -1
package/dist/api-exports.js
CHANGED
|
@@ -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
|
|
94
|
-
if (
|
|
95
|
-
const action = tool.slice(
|
|
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((
|
|
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
|
-
|
|
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-]
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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 "
|
|
2078
|
-
|
|
2079
|
-
|
|
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
|
|
2128
|
-
if (!raw) return
|
|
2129
|
-
|
|
2405
|
+
function readMapConfig(raw) {
|
|
2406
|
+
if (!raw) return void 0;
|
|
2407
|
+
if (typeof raw !== "string") return raw;
|
|
2130
2408
|
try {
|
|
2131
|
-
cfg =
|
|
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
|
-
|
|
2258
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
-
|
|
2562
|
-
|
|
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
|
-
|
|
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 (
|
|
2597
|
-
|
|
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 (
|
|
2615
|
-
|
|
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
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
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 (
|
|
2749
|
-
const id =
|
|
3065
|
+
if (isArmStep(entry)) {
|
|
3066
|
+
const id = armStepId(entry);
|
|
2750
3067
|
addNode(id, {
|
|
2751
|
-
kind:
|
|
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
|
-
|
|
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 =
|
|
3110
|
+
const childId = armStepId(arm);
|
|
2807
3111
|
addNode(childId, {
|
|
2808
|
-
kind:
|
|
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 :
|
|
3150
|
+
const childId = arm.type === "mapping" ? arm.id : armStepId(arm);
|
|
2847
3151
|
addNode(childId, {
|
|
2848
|
-
kind: arm.type === "mapping" ? "map" :
|
|
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
|
|
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
|
-
|
|
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)
|
|
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)
|
|
3427
|
-
if (call.otherwise
|
|
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
|
-
|
|
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
|
|
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)) && !
|
|
3547
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
4146
|
+
walk22(node.dependsOn);
|
|
3737
4147
|
}
|
|
3738
4148
|
}, "walk");
|
|
3739
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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)
|
|
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))
|
|
4978
|
+
if (v && typeof v === "object") for (const e of Object.values(v)) walk22(e);
|
|
4474
4979
|
}, "walk");
|
|
4475
|
-
|
|
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
|
|
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] =
|
|
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) =>
|
|
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] =
|
|
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:
|
|
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,
|
|
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
|
-
|
|
4896
|
-
|
|
4897
|
-
|
|
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
|
-
|
|
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 &&
|
|
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
|
|
5792
|
-
|
|
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
|
-
|
|
5994
|
-
if (
|
|
5995
|
-
if (
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
5999
|
-
|
|
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: "
|
|
6156
|
-
|
|
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: "
|
|
6175
|
-
|
|
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((
|
|
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
|
|
6882
|
-
while (
|
|
6883
|
-
const block = buffer.slice(0,
|
|
6884
|
-
buffer = buffer.slice(
|
|
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
|
-
|
|
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((
|
|
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((
|
|
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
|
|