lua-cli 3.32.2 → 3.32.3

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.
@@ -653,6 +653,48 @@ function scheduledTimeKey(scheduledTime) {
653
653
  function scheduledWorkflowRunIdForTime(jobId, scheduledTime) {
654
654
  return scheduledWorkflowRunId(jobId, scheduledTime);
655
655
  }
656
+ function workflowRetryMaxAttemptsMessage(got) {
657
+ const tail = got === void 0 ? "" : ` (got ${JSON.stringify(got)})`;
658
+ return `\`retry.maxAttempts\` must be an integer ${WORKFLOW_RETRY_MIN_ATTEMPTS}..${WORKFLOW_RETRY_MAX_ATTEMPTS}${tail}`;
659
+ }
660
+ function isWithinWorkflowRetryAttempts(value3) {
661
+ return typeof value3 === "number" && Number.isInteger(value3) && value3 >= WORKFLOW_RETRY_MIN_ATTEMPTS && value3 <= WORKFLOW_RETRY_MAX_ATTEMPTS;
662
+ }
663
+ function workflowRetryUnknownMembersMessage(keys) {
664
+ const named = keys.map((k) => {
665
+ const engine = WORKFLOW_RETRY_ENGINE_KEYS.includes(k);
666
+ return `\`${k}\`${engine ? " (engine-owned \u2014 stamped by resetAttempts, never authored)" : ""}`;
667
+ });
668
+ return `\`retry\` has no member ${named.join(", ")}; members: ${WORKFLOW_RETRY_POLICY_KEYS.join(", ")}`;
669
+ }
670
+ function unknownWorkflowRetryMembers(retry) {
671
+ if (!retry || typeof retry !== "object" || Array.isArray(retry)) return [];
672
+ return Object.keys(retry).filter((k) => !WORKFLOW_RETRY_POLICY_KEYS.includes(k));
673
+ }
674
+ function authoredRetryPolicy(retry) {
675
+ if (!retry || typeof retry !== "object" || Array.isArray(retry)) return void 0;
676
+ const src = retry;
677
+ const out = {};
678
+ for (const k of WORKFLOW_RETRY_POLICY_KEYS) if (src[k] !== void 0) out[k] = src[k];
679
+ return Object.keys(out).length ? out : void 0;
680
+ }
681
+ function retryBudgetBaseAttempt(row) {
682
+ const base = row.retry?.budgetBaseAttempt;
683
+ return typeof base === "number" && Number.isSafeInteger(base) && base > 0 ? base : 0;
684
+ }
685
+ function retryBudgetAttempt(row) {
686
+ return Math.max(0, row.attempt - retryBudgetBaseAttempt(row));
687
+ }
688
+ function retryBudgetMaxAttempts(row) {
689
+ const max = row.retry?.maxAttempts;
690
+ return typeof max === "number" && Number.isFinite(max) && max >= 1 ? max : 1;
691
+ }
692
+ function retryBudgetRemaining(row) {
693
+ return retryBudgetAttempt(row) < retryBudgetMaxAttempts(row);
694
+ }
695
+ function retriesRemaining(row) {
696
+ return Math.max(0, retryBudgetMaxAttempts(row) - retryBudgetAttempt(row));
697
+ }
656
698
  function isWithinWorkflowJobRange(member, value3) {
657
699
  const { min, max } = WORKFLOW_JOB_RANGES[member];
658
700
  return typeof value3 === "number" && Number.isInteger(value3) && value3 >= min && value3 <= max;
@@ -840,7 +882,66 @@ ${PREAMBLE}
840
882
 
841
883
  ${items.join("\n\n")}`;
842
884
  }
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;
885
+ function workflowApprovalDecisionOf(resumeData) {
886
+ if (resumeData.timedOut === true) return "timed_out";
887
+ return resumeData.approved === true ? "approved" : "denied";
888
+ }
889
+ function workflowApprovalOutput(resumeData) {
890
+ const decision = typeof resumeData.decision === "string" ? resumeData.decision : workflowApprovalDecisionOf(resumeData);
891
+ const note = typeof resumeData.note === "string" && resumeData.note.trim() !== "" ? resumeData.note : void 0;
892
+ const text = typeof resumeData.text === "string" ? resumeData.text : note ?? decision;
893
+ return {
894
+ ...resumeData,
895
+ decision,
896
+ text
897
+ };
898
+ }
899
+ function isWorkflowApprovalOutput(value3) {
900
+ if (typeof value3 !== "object" || value3 === null || Array.isArray(value3)) return false;
901
+ const v = value3;
902
+ return typeof v.approved === "boolean" && WORKFLOW_APPROVAL_OUTPUT_DECISIONS.includes(v.decision) && typeof v.text === "string";
903
+ }
904
+ function extractSingleJsonValue(text) {
905
+ const trimmed = (text ?? "").trim();
906
+ if (!trimmed) return {
907
+ reason: "reply is empty"
908
+ };
909
+ const fenced = [
910
+ ...trimmed.matchAll(JSON_FENCE_RE)
911
+ ];
912
+ if (fenced.length > 1) return {
913
+ reason: "reply carries more than one fenced block"
914
+ };
915
+ const candidate = fenced.length === 1 ? fenced[0][1].trim() : trimmed;
916
+ try {
917
+ return {
918
+ value: JSON.parse(candidate)
919
+ };
920
+ } catch {
921
+ if (fenced.length === 1) return {
922
+ reason: "fenced block is not valid JSON"
923
+ };
924
+ }
925
+ const opens = [
926
+ trimmed.indexOf("{"),
927
+ trimmed.indexOf("[")
928
+ ].filter((i) => i !== -1);
929
+ const start = opens.length ? Math.min(...opens) : -1;
930
+ const end = Math.max(trimmed.lastIndexOf("}"), trimmed.lastIndexOf("]"));
931
+ if (start === -1 || end <= start) return {
932
+ reason: "reply is not JSON"
933
+ };
934
+ try {
935
+ return {
936
+ value: JSON.parse(trimmed.slice(start, end + 1))
937
+ };
938
+ } catch {
939
+ return {
940
+ reason: "reply does not contain a single JSON value"
941
+ };
942
+ }
943
+ }
944
+ 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_RETRY_MIN_ATTEMPTS, WORKFLOW_RETRY_POLICY_KEYS, WORKFLOW_RETRY_MAX_ATTEMPTS, WORKFLOW_RETRY_ENGINE_KEYS, 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, WORKFLOW_APPROVAL_OUTPUT_DECISIONS, WORKFLOW_APPROVAL_OUTPUT_SCHEMA, JSON_FENCE_RE;
844
945
  var init_dist = __esm({
845
946
  "../shared-types/dist/index.mjs"() {
846
947
  "use strict";
@@ -1928,6 +2029,37 @@ This text is who you are for this person. As you learn them, their name, their w
1928
2029
  "fixed",
1929
2030
  "exponential"
1930
2031
  ];
2032
+ WORKFLOW_RETRY_MIN_ATTEMPTS = 1;
2033
+ WORKFLOW_RETRY_POLICY_KEYS = [
2034
+ "maxAttempts",
2035
+ "backoffSeconds",
2036
+ "backoff",
2037
+ "maxBackoffSeconds"
2038
+ ];
2039
+ WORKFLOW_RETRY_MAX_ATTEMPTS = 20;
2040
+ __name(workflowRetryMaxAttemptsMessage, "workflowRetryMaxAttemptsMessage");
2041
+ __name2(workflowRetryMaxAttemptsMessage, "workflowRetryMaxAttemptsMessage");
2042
+ __name(isWithinWorkflowRetryAttempts, "isWithinWorkflowRetryAttempts");
2043
+ __name2(isWithinWorkflowRetryAttempts, "isWithinWorkflowRetryAttempts");
2044
+ WORKFLOW_RETRY_ENGINE_KEYS = [
2045
+ "budgetBaseAttempt"
2046
+ ];
2047
+ __name(workflowRetryUnknownMembersMessage, "workflowRetryUnknownMembersMessage");
2048
+ __name2(workflowRetryUnknownMembersMessage, "workflowRetryUnknownMembersMessage");
2049
+ __name(unknownWorkflowRetryMembers, "unknownWorkflowRetryMembers");
2050
+ __name2(unknownWorkflowRetryMembers, "unknownWorkflowRetryMembers");
2051
+ __name(authoredRetryPolicy, "authoredRetryPolicy");
2052
+ __name2(authoredRetryPolicy, "authoredRetryPolicy");
2053
+ __name(retryBudgetBaseAttempt, "retryBudgetBaseAttempt");
2054
+ __name2(retryBudgetBaseAttempt, "retryBudgetBaseAttempt");
2055
+ __name(retryBudgetAttempt, "retryBudgetAttempt");
2056
+ __name2(retryBudgetAttempt, "retryBudgetAttempt");
2057
+ __name(retryBudgetMaxAttempts, "retryBudgetMaxAttempts");
2058
+ __name2(retryBudgetMaxAttempts, "retryBudgetMaxAttempts");
2059
+ __name(retryBudgetRemaining, "retryBudgetRemaining");
2060
+ __name2(retryBudgetRemaining, "retryBudgetRemaining");
2061
+ __name(retriesRemaining, "retriesRemaining");
2062
+ __name2(retriesRemaining, "retriesRemaining");
1931
2063
  WORKFLOW_JOB_RESOURCES = [
1932
2064
  "small",
1933
2065
  "medium",
@@ -2200,6 +2332,8 @@ This text is who you are for this person. As you learn them, their name, their w
2200
2332
  "workflow.goal.resumed",
2201
2333
  "workflow.goal.done",
2202
2334
  "workflow.goal.closed",
2335
+ // LUA-760: an ended goal's cadence Job retired (deleted) — inline on done / closed, by R21 / R28, or by sweep #30
2336
+ "workflow.goal.job_retired",
2203
2337
  // --- org policy (02 §2.10 / 09 R23) ---
2204
2338
  "workflow.policy.retention_changed",
2205
2339
  "workflow.policy.pacing_changed",
@@ -2249,6 +2383,79 @@ listed here; never invent a target.`;
2249
2383
  __name2(reachingIt, "reachingIt");
2250
2384
  __name(renderTargetsBlock, "renderTargetsBlock");
2251
2385
  __name2(renderTargetsBlock, "renderTargetsBlock");
2386
+ WORKFLOW_APPROVAL_OUTPUT_DECISIONS = [
2387
+ "approved",
2388
+ "denied",
2389
+ "timed_out"
2390
+ ];
2391
+ WORKFLOW_APPROVAL_OUTPUT_SCHEMA = {
2392
+ type: "object",
2393
+ properties: {
2394
+ approved: {
2395
+ type: "boolean"
2396
+ },
2397
+ decision: {
2398
+ type: "string",
2399
+ enum: [
2400
+ ...WORKFLOW_APPROVAL_OUTPUT_DECISIONS
2401
+ ]
2402
+ },
2403
+ /** the approver's note when given, else the decision word — what `${stepResults.<id>.text}` reads */
2404
+ text: {
2405
+ type: "string"
2406
+ },
2407
+ note: {
2408
+ type: "string"
2409
+ },
2410
+ editedPayload: {},
2411
+ editRevision: {
2412
+ type: "integer"
2413
+ },
2414
+ decidedBy: {
2415
+ type: "object",
2416
+ properties: {
2417
+ id: {
2418
+ type: "string"
2419
+ },
2420
+ kind: {
2421
+ type: "string"
2422
+ }
2423
+ }
2424
+ },
2425
+ timedOut: {
2426
+ type: "boolean"
2427
+ },
2428
+ escalations: {
2429
+ type: "integer"
2430
+ },
2431
+ evidence: {
2432
+ type: "array",
2433
+ items: {
2434
+ type: "string"
2435
+ }
2436
+ },
2437
+ items: {
2438
+ type: "array",
2439
+ items: {
2440
+ type: "object"
2441
+ }
2442
+ }
2443
+ },
2444
+ required: [
2445
+ "approved",
2446
+ "decision",
2447
+ "text"
2448
+ ]
2449
+ };
2450
+ __name(workflowApprovalDecisionOf, "workflowApprovalDecisionOf");
2451
+ __name2(workflowApprovalDecisionOf, "workflowApprovalDecisionOf");
2452
+ __name(workflowApprovalOutput, "workflowApprovalOutput");
2453
+ __name2(workflowApprovalOutput, "workflowApprovalOutput");
2454
+ __name(isWorkflowApprovalOutput, "isWorkflowApprovalOutput");
2455
+ __name2(isWorkflowApprovalOutput, "isWorkflowApprovalOutput");
2456
+ JSON_FENCE_RE = /```(?:json)?[ \t]*\r?\n([\s\S]*?)\r?\n?```/g;
2457
+ __name(extractSingleJsonValue, "extractSingleJsonValue");
2458
+ __name2(extractSingleJsonValue, "extractSingleJsonValue");
2252
2459
  }
2253
2460
  });
2254
2461
 
@@ -2257,6 +2464,208 @@ import { createHash } from "crypto";
2257
2464
  import { z as z4 } from "zod";
2258
2465
  import { z as z22 } from "zod";
2259
2466
  import { createHash as createHash2 } from "crypto";
2467
+ function isMapConfigObject(v) {
2468
+ return typeof v === "object" && v !== null && !Array.isArray(v);
2469
+ }
2470
+ function parseMapConfig(raw, stepId) {
2471
+ if (isMapConfigObject(raw)) return raw;
2472
+ if (typeof raw !== "string") {
2473
+ throw new Error(`Stored mapping step "${stepId}" has a mapConfig that is neither a JSON string nor an object.`);
2474
+ }
2475
+ try {
2476
+ return JSON.parse(raw);
2477
+ } catch (e) {
2478
+ throw new Error(`Stored mapping step "${stepId}" has invalid JSON mapConfig: ${e.message}`);
2479
+ }
2480
+ }
2481
+ function mapConfigWire(raw) {
2482
+ if (typeof raw === "string") return raw;
2483
+ if (isMapConfigObject(raw)) return canonicalJson(raw);
2484
+ return void 0;
2485
+ }
2486
+ function describeBadPlaceholder(template22, idx, rawExpr) {
2487
+ return `Template placeholder #${idx} (\${${rawExpr}}) in '${template22}'`;
2488
+ }
2489
+ function parseTemplatePlaceholder(rawExpr) {
2490
+ const dot = rawExpr.indexOf(".");
2491
+ return {
2492
+ scope: dot === -1 ? rawExpr : rawExpr.slice(0, dot),
2493
+ rest: dot === -1 ? "" : rawExpr.slice(dot + 1)
2494
+ };
2495
+ }
2496
+ function traverseMappingPath(root, path3, errorLabel) {
2497
+ if (path3 === "" || path3 === ".") return root;
2498
+ const parts = path3.split(".");
2499
+ let value22 = root;
2500
+ for (const part of parts) {
2501
+ if (typeof value22 === "object" && value22 !== null) value22 = value22[part];
2502
+ else throw new WorkflowTemplateError(`Invalid path ${path3} in ${errorLabel}`, path3);
2503
+ }
2504
+ return value22;
2505
+ }
2506
+ function stringifyTemplateValue(v, template22, idx, rawExpr) {
2507
+ if (v === null || v === void 0) return "";
2508
+ if (typeof v === "object") {
2509
+ try {
2510
+ return JSON.stringify(v);
2511
+ } catch (err) {
2512
+ throw new WorkflowTemplateError(`${describeBadPlaceholder(template22, idx, rawExpr)} resolved to a value that could not be JSON-stringified (${err.message}).`, rawExpr);
2513
+ }
2514
+ }
2515
+ return String(v);
2516
+ }
2517
+ function escapeFence(content) {
2518
+ return content.replace(/<\/lua-data/g, "<\\/lua-data");
2519
+ }
2520
+ function fenceBlock(name, source, content) {
2521
+ return `<lua-data name="${name}" source="${source}" untrusted="true">${escapeFence(content)}</lua-data>`;
2522
+ }
2523
+ function renderTemplate(template22, ctx, opts) {
2524
+ let idx = 0;
2525
+ return template22.replace(TEMPLATE_PLACEHOLDER, (_match, rawExpr) => {
2526
+ idx += 1;
2527
+ const { scope, rest } = parseTemplatePlaceholder(rawExpr);
2528
+ const label = describeBadPlaceholder(template22, idx, rawExpr);
2529
+ let rendered;
2530
+ let source;
2531
+ switch (scope) {
2532
+ case "initData":
2533
+ rendered = stringifyTemplateValue(traverseMappingPath(ctx.initData, rest, label), template22, idx, rawExpr);
2534
+ source = "initData";
2535
+ break;
2536
+ case "state":
2537
+ rendered = stringifyTemplateValue(traverseMappingPath(ctx.state, rest, label), template22, idx, rawExpr);
2538
+ source = "state";
2539
+ break;
2540
+ case "requestContext":
2541
+ rendered = stringifyTemplateValue(traverseMappingPath(ctx.requestContext, rest, label), template22, idx, rawExpr);
2542
+ source = "requestContext";
2543
+ break;
2544
+ case "stepResults": {
2545
+ const innerDot = rest.indexOf(".");
2546
+ const stepId = innerDot === -1 ? rest : rest.slice(0, innerDot);
2547
+ const subPath = innerDot === -1 ? "" : rest.slice(innerDot + 1);
2548
+ if (!stepId) throw new WorkflowTemplateError(`${label} must name a step: \${stepResults.<stepId>.<path>}.`, rawExpr);
2549
+ if (!(stepId in ctx.stepResults) || ctx.stepResults[stepId] == null) {
2550
+ throw new WorkflowTemplateError(`${label} references stepResults.${stepId} but step "${stepId}" has no resolvable output (not an ancestor, not run, failed, or produced no output).`, rawExpr);
2551
+ }
2552
+ rendered = stringifyTemplateValue(traverseMappingPath(ctx.stepResults[stepId], subPath, label), template22, idx, rawExpr);
2553
+ source = `step:${stepId}`;
2554
+ break;
2555
+ }
2556
+ default:
2557
+ throw new WorkflowTemplateError(`${label} references unknown namespace "${scope}". Use one of: ${TEMPLATE_NAMESPACES.join(", ")}.`, rawExpr);
2558
+ }
2559
+ return opts.fenced ? fenceBlock(rawExpr, source, rendered) : rendered;
2560
+ });
2561
+ }
2562
+ function isMapDescriptor(v) {
2563
+ if (v === null || typeof v !== "object" || Array.isArray(v)) return false;
2564
+ const d = v;
2565
+ const keys = Object.keys(d);
2566
+ const only = /* @__PURE__ */ __name3((...allowed) => keys.every((k) => allowed.includes(k)), "only");
2567
+ if ("value" in d) return keys.length === 1;
2568
+ if ("template" in d) return keys.length === 1 && typeof d.template === "string";
2569
+ if ("requestContextPath" in d) return keys.length === 1 && typeof d.requestContextPath === "string";
2570
+ if ("knowledge" in d) return keys.length === 1 && typeof d.knowledge === "object" && d.knowledge !== null;
2571
+ if ("initData" in d) return d.initData === true && typeof d.path === "string" && only("initData", "path");
2572
+ if ("step" in d) {
2573
+ const stepOk = typeof d.step === "string" || Array.isArray(d.step) && d.step.every((x) => typeof x === "string");
2574
+ return stepOk && typeof d.path === "string" && only("step", "path", "rows");
2575
+ }
2576
+ return false;
2577
+ }
2578
+ function malformedMapMembers(cfg) {
2579
+ if (!cfg || typeof cfg !== "object" || Array.isArray(cfg)) return [];
2580
+ const out = [];
2581
+ for (const [member, v] of Object.entries(cfg)) {
2582
+ if (!v || typeof v !== "object" || Array.isArray(v) || isMapDescriptor(v)) continue;
2583
+ const keys = Object.keys(v).filter((k) => MAP_DESCRIPTOR_KEYS.includes(k));
2584
+ if (keys.length > 0) out.push({
2585
+ member,
2586
+ keys
2587
+ });
2588
+ }
2589
+ return out;
2590
+ }
2591
+ function mapMemberMalformedMessage(id, m) {
2592
+ const keys = m.keys.map((k) => `\`${k}\``).join(", ");
2593
+ return `"${id}".${m.member} carries descriptor key${m.keys.length === 1 ? "" : "s"} ${keys} but is not an exact binding form ({initData:true, path} | {step, path[, rows]} | {value} | {template} | {requestContextPath} | {knowledge}) \u2014 it is passed to the step verbatim as a literal; fix the descriptor, or wrap it in {value: \u2026} if the literal is intended`;
2594
+ }
2595
+ function resolveDescriptor(key, m, ctx) {
2596
+ if (!isMapDescriptor(m)) return {
2597
+ value: m
2598
+ };
2599
+ try {
2600
+ if ("value" in m) return {
2601
+ value: m.value
2602
+ };
2603
+ if ("template" in m && typeof m.template === "string") {
2604
+ return {
2605
+ value: renderTemplate(m.template, ctx, {
2606
+ fenced: false
2607
+ })
2608
+ };
2609
+ }
2610
+ if ("knowledge" in m || "rows" in m && m.rows !== void 0) {
2611
+ return {
2612
+ error: "binding_unresolved",
2613
+ key
2614
+ };
2615
+ }
2616
+ if ("requestContextPath" in m) {
2617
+ const label = `requestContext path for key "${key}"`;
2618
+ return {
2619
+ value: traverseMappingPath(ctx.requestContext, m.requestContextPath, label)
2620
+ };
2621
+ }
2622
+ if ("path" in m) {
2623
+ const source = "initData" in m && m.initData ? "initData" : "step";
2624
+ if (source === "initData") {
2625
+ return {
2626
+ value: traverseMappingPath(ctx.initData, m.path, `initData for key "${key}"`)
2627
+ };
2628
+ }
2629
+ const stepRef = m.step;
2630
+ const candidates = Array.isArray(stepRef) ? stepRef : [
2631
+ stepRef
2632
+ ];
2633
+ const stepId = candidates.find((s) => ctx.stepResults[s] !== void 0 && ctx.stepResults[s] !== null);
2634
+ if (stepId === void 0) return {
2635
+ error: "binding_unresolved",
2636
+ key
2637
+ };
2638
+ return {
2639
+ value: traverseMappingPath(ctx.stepResults[stepId], m.path, `step ${candidates.join("|")} for key "${key}"`)
2640
+ };
2641
+ }
2642
+ return {
2643
+ error: "binding_unresolved",
2644
+ key
2645
+ };
2646
+ } catch (err) {
2647
+ if (err instanceof WorkflowTemplateError) return {
2648
+ error: "binding_unresolved",
2649
+ key
2650
+ };
2651
+ throw err;
2652
+ }
2653
+ }
2654
+ function resolveMapping(cfg, ctx) {
2655
+ const keys = Object.keys(cfg);
2656
+ if (keys.length === 1 && keys[0] === "") {
2657
+ return resolveDescriptor("", cfg[""], ctx);
2658
+ }
2659
+ const result = {};
2660
+ for (const key of keys) {
2661
+ const resolved = resolveDescriptor(key, cfg[key], ctx);
2662
+ if ("error" in resolved) return resolved;
2663
+ result[key] = resolved.value;
2664
+ }
2665
+ return {
2666
+ value: result
2667
+ };
2668
+ }
2260
2669
  function workspaceTemplatePath(template22) {
2261
2670
  const key = template22.trim();
2262
2671
  const expr = WORKSPACE_TEMPLATE_EXPR_RE.exec(key);
@@ -2417,12 +2826,11 @@ function mapConfigStepRefs(raw) {
2417
2826
  if (!cfg) return [];
2418
2827
  const ids = [];
2419
2828
  for (const d of Object.values(cfg)) {
2420
- if (!d || typeof d !== "object") continue;
2421
- const desc = d;
2422
- if (desc.step !== void 0) ids.push(...Array.isArray(desc.step) ? desc.step : [
2423
- desc.step
2829
+ if (!isMapDescriptor(d)) continue;
2830
+ if ("step" in d) ids.push(...Array.isArray(d.step) ? d.step : [
2831
+ d.step
2424
2832
  ]);
2425
- if (typeof desc.template === "string") ids.push(...templateStepRefs(desc.template));
2833
+ if ("template" in d) ids.push(...templateStepRefs(d.template));
2426
2834
  }
2427
2835
  return ids;
2428
2836
  }
@@ -2547,6 +2955,12 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2547
2955
  const r = node.retry;
2548
2956
  if (!r) return;
2549
2957
  const id = singleId(node);
2958
+ const unknown = unknownWorkflowRetryMembers(r);
2959
+ if (unknown.length) err("invalid-envelope", workflowRetryUnknownMembersMessage(unknown), `${path3}.retry`, id);
2960
+ if (r.maxAttempts !== void 0 && !isWithinWorkflowRetryAttempts(r.maxAttempts)) {
2961
+ const over = typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS;
2962
+ err(over ? "cap-exceeded" : "invalid-envelope", workflowRetryMaxAttemptsMessage(r.maxAttempts), `${path3}.retry.maxAttempts`, id);
2963
+ }
2550
2964
  const backoffs = retryBackoffs();
2551
2965
  if (r.backoff !== void 0 && !backoffs.includes(r.backoff)) {
2552
2966
  const list = backoffs.map((b) => `'${b}'`).join(" | ");
@@ -2689,6 +3103,21 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2689
3103
  const schema = node.type === "step" ? node.step.outputSchema : node.type === "agent" ? node.outputSchema : void 0;
2690
3104
  if (schema !== void 0) outputSchemas.set(singleId(node), schema);
2691
3105
  }, "recordOutputSchema");
3106
+ const checkMapMembers = /* @__PURE__ */ __name3((cfg, basePath, id) => {
3107
+ for (const m of malformedMapMembers(cfg)) {
3108
+ warn(MAP_MEMBER_MALFORMED_CODE, mapMemberMalformedMessage(id, m), `${basePath}.${m.member}`, id);
3109
+ }
3110
+ }, "checkMapMembers");
3111
+ const checkInputShape = /* @__PURE__ */ __name3((node, path3) => {
3112
+ if (node.type !== "tool" && node.type !== "workflow") return;
3113
+ const input = node.input;
3114
+ if (input === void 0) return;
3115
+ if (input !== null && typeof input === "object" && !Array.isArray(input)) {
3116
+ checkMapMembers(input, `${path3}.input`, node.id);
3117
+ return;
3118
+ }
3119
+ err("invalid-envelope", `\`input\` must be an object map \u2014 each member a binding descriptor ({initData:true, path} | {step, path} | {value} | {template} | {requestContextPath}) or a JSON literal (got ${JSON.stringify(input)})`, `${path3}.input`, node.id);
3120
+ }, "checkInputShape");
2692
3121
  const checkSingle = /* @__PURE__ */ __name3((node, path3, depth) => {
2693
3122
  recordOutputSchema(node);
2694
3123
  if (node.type === "workflow" && node.workflowId === WORKFLOW_ARM_SUBRUN_ID) {
@@ -2716,6 +3145,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2716
3145
  }
2717
3146
  checkId(singleId(node), path3);
2718
3147
  checkPolicyEnums(node, path3);
3148
+ checkInputShape(node, path3);
2719
3149
  checkTimeout(node, path3);
2720
3150
  checkTier(node, path3);
2721
3151
  checkRetry(node, path3);
@@ -2796,6 +3226,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2796
3226
  const checkArm = /* @__PURE__ */ __name3((arm, path3, depth, container) => {
2797
3227
  if (arm.type === "mapping") {
2798
3228
  checkId(arm.id, path3);
3229
+ checkMapMembers(readMapConfig(arm.mapConfig), `${path3}.mapConfig`, arm.id);
2799
3230
  for (const ref of nodeStepRefs(arm)) {
2800
3231
  if (!upstream.has(ref)) err("template-reference-unresolved", `"${arm.id}" references stepResults.${ref}, which is not upstream`, path3, arm.id);
2801
3232
  }
@@ -2820,6 +3251,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
2820
3251
  break;
2821
3252
  case "mapping":
2822
3253
  checkId(entry.id, path3);
3254
+ checkMapMembers(readMapConfig(entry.mapConfig), `${path3}.mapConfig`, entry.id);
2823
3255
  for (const ref of nodeStepRefs(entry)) {
2824
3256
  if (!upstream.has(ref)) err("template-reference-unresolved", `"${entry.id}" references stepResults.${ref}, which is not upstream`, path3, entry.id);
2825
3257
  }
@@ -3361,227 +3793,61 @@ function renderPredicate(pred) {
3361
3793
  case "eq":
3362
3794
  return `${renderRef(pred.left)} == ${renderRef(pred.right)}`;
3363
3795
  case "ne":
3364
- return `${renderRef(pred.left)} != ${renderRef(pred.right)}`;
3365
- case "lt":
3366
- return `${renderRef(pred.left)} < ${renderRef(pred.right)}`;
3367
- case "lte":
3368
- return `${renderRef(pred.left)} <= ${renderRef(pred.right)}`;
3369
- case "gt":
3370
- return `${renderRef(pred.left)} > ${renderRef(pred.right)}`;
3371
- case "gte":
3372
- return `${renderRef(pred.left)} >= ${renderRef(pred.right)}`;
3373
- }
3374
- }
3375
- function wrapLabel(child, rendered) {
3376
- return child.op === "and" || child.op === "or" || child.op === "not" ? `(${rendered})` : rendered;
3377
- }
3378
- function renderRef(ref) {
3379
- if ("literal" in ref) return JSON.stringify(ref.literal);
3380
- return ref.path;
3381
- }
3382
- function step(s) {
3383
- const id = stepIdOf(s);
3384
- return {
3385
- path: /* @__PURE__ */ __name3((p) => ({
3386
- path: p === "" ? `stepResults.${id}` : `stepResults.${id}.${p}`
3387
- }), "path")
3388
- };
3389
- }
3390
- function stepOf(id) {
3391
- return step(id);
3392
- }
3393
- function init(path3) {
3394
- return {
3395
- path: path3 === "" ? "initData" : `initData.${path3}`
3396
- };
3397
- }
3398
- function state(path3) {
3399
- return {
3400
- path: path3 === "" ? "state" : `state.${path3}`
3401
- };
3402
- }
3403
- function lit(v) {
3404
- return {
3405
- literal: v
3406
- };
3407
- }
3408
- function toPathOrLiteral(v) {
3409
- if (typeof v === "object" && v !== null) {
3410
- if ("path" in v) return {
3411
- path: v.path
3412
- };
3413
- if ("literal" in v) return {
3414
- literal: v.literal
3415
- };
3416
- }
3417
- return {
3418
- literal: v
3419
- };
3420
- }
3421
- function isMapConfigObject(v) {
3422
- return typeof v === "object" && v !== null && !Array.isArray(v);
3423
- }
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
- }
3429
- try {
3430
- return JSON.parse(raw);
3431
- } catch (e) {
3432
- throw new Error(`Stored mapping step "${stepId}" has invalid JSON mapConfig: ${e.message}`);
3433
- }
3434
- }
3435
- function mapConfigWire(raw) {
3436
- if (typeof raw === "string") return raw;
3437
- if (isMapConfigObject(raw)) return canonicalJson(raw);
3438
- return void 0;
3439
- }
3440
- function describeBadPlaceholder(template22, idx, rawExpr) {
3441
- return `Template placeholder #${idx} (\${${rawExpr}}) in '${template22}'`;
3442
- }
3443
- function parseTemplatePlaceholder(rawExpr) {
3444
- const dot = rawExpr.indexOf(".");
3445
- return {
3446
- scope: dot === -1 ? rawExpr : rawExpr.slice(0, dot),
3447
- rest: dot === -1 ? "" : rawExpr.slice(dot + 1)
3448
- };
3449
- }
3450
- function traverseMappingPath(root, path3, errorLabel) {
3451
- if (path3 === "" || path3 === ".") return root;
3452
- const parts = path3.split(".");
3453
- let value22 = root;
3454
- for (const part of parts) {
3455
- if (typeof value22 === "object" && value22 !== null) value22 = value22[part];
3456
- else throw new WorkflowTemplateError(`Invalid path ${path3} in ${errorLabel}`, path3);
3457
- }
3458
- return value22;
3459
- }
3460
- function stringifyTemplateValue(v, template22, idx, rawExpr) {
3461
- if (v === null || v === void 0) return "";
3462
- if (typeof v === "object") {
3463
- try {
3464
- return JSON.stringify(v);
3465
- } catch (err) {
3466
- throw new WorkflowTemplateError(`${describeBadPlaceholder(template22, idx, rawExpr)} resolved to a value that could not be JSON-stringified (${err.message}).`, rawExpr);
3467
- }
3468
- }
3469
- return String(v);
3470
- }
3471
- function escapeFence(content) {
3472
- return content.replace(/<\/lua-data/g, "<\\/lua-data");
3473
- }
3474
- function fenceBlock(name, source, content) {
3475
- return `<lua-data name="${name}" source="${source}" untrusted="true">${escapeFence(content)}</lua-data>`;
3476
- }
3477
- function renderTemplate(template22, ctx, opts) {
3478
- let idx = 0;
3479
- return template22.replace(TEMPLATE_PLACEHOLDER, (_match, rawExpr) => {
3480
- idx += 1;
3481
- const { scope, rest } = parseTemplatePlaceholder(rawExpr);
3482
- const label = describeBadPlaceholder(template22, idx, rawExpr);
3483
- let rendered;
3484
- let source;
3485
- switch (scope) {
3486
- case "initData":
3487
- rendered = stringifyTemplateValue(traverseMappingPath(ctx.initData, rest, label), template22, idx, rawExpr);
3488
- source = "initData";
3489
- break;
3490
- case "state":
3491
- rendered = stringifyTemplateValue(traverseMappingPath(ctx.state, rest, label), template22, idx, rawExpr);
3492
- source = "state";
3493
- break;
3494
- case "requestContext":
3495
- rendered = stringifyTemplateValue(traverseMappingPath(ctx.requestContext, rest, label), template22, idx, rawExpr);
3496
- source = "requestContext";
3497
- break;
3498
- case "stepResults": {
3499
- const innerDot = rest.indexOf(".");
3500
- const stepId = innerDot === -1 ? rest : rest.slice(0, innerDot);
3501
- const subPath = innerDot === -1 ? "" : rest.slice(innerDot + 1);
3502
- if (!stepId) throw new WorkflowTemplateError(`${label} must name a step: \${stepResults.<stepId>.<path>}.`, rawExpr);
3503
- if (!(stepId in ctx.stepResults) || ctx.stepResults[stepId] == null) {
3504
- throw new WorkflowTemplateError(`${label} references stepResults.${stepId} but step "${stepId}" has no resolvable output (not an ancestor, not run, failed, or produced no output).`, rawExpr);
3505
- }
3506
- rendered = stringifyTemplateValue(traverseMappingPath(ctx.stepResults[stepId], subPath, label), template22, idx, rawExpr);
3507
- source = `step:${stepId}`;
3508
- break;
3509
- }
3510
- default:
3511
- throw new WorkflowTemplateError(`${label} references unknown namespace "${scope}". Use one of: ${TEMPLATE_NAMESPACES.join(", ")}.`, rawExpr);
3512
- }
3513
- return opts.fenced ? fenceBlock(rawExpr, source, rendered) : rendered;
3514
- });
3515
- }
3516
- function resolveDescriptor(key, m, ctx) {
3517
- try {
3518
- if ("value" in m) return {
3519
- value: m.value
3520
- };
3521
- if ("template" in m && typeof m.template === "string") {
3522
- return {
3523
- value: renderTemplate(m.template, ctx, {
3524
- fenced: false
3525
- })
3526
- };
3527
- }
3528
- if ("knowledge" in m || "rows" in m && m.rows !== void 0) {
3529
- return {
3530
- error: "binding_unresolved",
3531
- key
3532
- };
3533
- }
3534
- if ("requestContextPath" in m) {
3535
- const label = `requestContext path for key "${key}"`;
3536
- return {
3537
- value: traverseMappingPath(ctx.requestContext, m.requestContextPath, label)
3538
- };
3539
- }
3540
- if ("path" in m) {
3541
- const source = "initData" in m && m.initData ? "initData" : "step";
3542
- if (source === "initData") {
3543
- return {
3544
- value: traverseMappingPath(ctx.initData, m.path, `initData for key "${key}"`)
3545
- };
3546
- }
3547
- const stepRef = m.step;
3548
- const candidates = Array.isArray(stepRef) ? stepRef : [
3549
- stepRef
3550
- ];
3551
- const stepId = candidates.find((s) => ctx.stepResults[s] !== void 0 && ctx.stepResults[s] !== null);
3552
- if (stepId === void 0) return {
3553
- error: "binding_unresolved",
3554
- key
3555
- };
3556
- return {
3557
- value: traverseMappingPath(ctx.stepResults[stepId], m.path, `step ${candidates.join("|")} for key "${key}"`)
3558
- };
3559
- }
3560
- return {
3561
- error: "binding_unresolved",
3562
- key
3563
- };
3564
- } catch (err) {
3565
- if (err instanceof WorkflowTemplateError) return {
3566
- error: "binding_unresolved",
3567
- key
3568
- };
3569
- throw err;
3796
+ return `${renderRef(pred.left)} != ${renderRef(pred.right)}`;
3797
+ case "lt":
3798
+ return `${renderRef(pred.left)} < ${renderRef(pred.right)}`;
3799
+ case "lte":
3800
+ return `${renderRef(pred.left)} <= ${renderRef(pred.right)}`;
3801
+ case "gt":
3802
+ return `${renderRef(pred.left)} > ${renderRef(pred.right)}`;
3803
+ case "gte":
3804
+ return `${renderRef(pred.left)} >= ${renderRef(pred.right)}`;
3570
3805
  }
3571
3806
  }
3572
- function resolveMapping(cfg, ctx) {
3573
- const keys = Object.keys(cfg);
3574
- if (keys.length === 1 && keys[0] === "") {
3575
- return resolveDescriptor("", cfg[""], ctx);
3576
- }
3577
- const result = {};
3578
- for (const key of keys) {
3579
- const resolved = resolveDescriptor(key, cfg[key], ctx);
3580
- if ("error" in resolved) return resolved;
3581
- result[key] = resolved.value;
3807
+ function wrapLabel(child, rendered) {
3808
+ return child.op === "and" || child.op === "or" || child.op === "not" ? `(${rendered})` : rendered;
3809
+ }
3810
+ function renderRef(ref) {
3811
+ if ("literal" in ref) return JSON.stringify(ref.literal);
3812
+ return ref.path;
3813
+ }
3814
+ function step(s) {
3815
+ const id = stepIdOf(s);
3816
+ return {
3817
+ path: /* @__PURE__ */ __name3((p) => ({
3818
+ path: p === "" ? `stepResults.${id}` : `stepResults.${id}.${p}`
3819
+ }), "path")
3820
+ };
3821
+ }
3822
+ function stepOf(id) {
3823
+ return step(id);
3824
+ }
3825
+ function init(path3) {
3826
+ return {
3827
+ path: path3 === "" ? "initData" : `initData.${path3}`
3828
+ };
3829
+ }
3830
+ function state(path3) {
3831
+ return {
3832
+ path: path3 === "" ? "state" : `state.${path3}`
3833
+ };
3834
+ }
3835
+ function lit(v) {
3836
+ return {
3837
+ literal: v
3838
+ };
3839
+ }
3840
+ function toPathOrLiteral(v) {
3841
+ if (typeof v === "object" && v !== null) {
3842
+ if ("path" in v) return {
3843
+ path: v.path
3844
+ };
3845
+ if ("literal" in v) return {
3846
+ literal: v.literal
3847
+ };
3582
3848
  }
3583
3849
  return {
3584
- value: result
3850
+ literal: v
3585
3851
  };
3586
3852
  }
3587
3853
  function continuedFailureValue(error, killReason) {
@@ -4218,15 +4484,64 @@ function runCounts(counts) {
4218
4484
  pending: n(c.pending) + n(c.ready) + n(c.waiting)
4219
4485
  };
4220
4486
  }
4221
- function runUsage(run) {
4487
+ function isPricedStepReceipt(receipt) {
4488
+ return typeof receipt?.multiplier === "number" && Number.isFinite(receipt.multiplier);
4489
+ }
4490
+ function receiptEngine(engine) {
4491
+ if (engine === "actions") return "seat";
4492
+ if (engine === "credits") return "legacy";
4493
+ return void 0;
4494
+ }
4495
+ function receiptTier(tier) {
4496
+ return tier === "light" || tier === "standard" || tier === "heavy" ? tier : void 0;
4497
+ }
4498
+ function stepBillingView(receipt) {
4499
+ const engine = receiptEngine(receipt?.engine);
4500
+ if (!receipt || engine === void 0) return void 0;
4501
+ return pruneUndefined({
4502
+ engine,
4503
+ attempt: typeof receipt.attempt === "number" ? receipt.attempt : void 0,
4504
+ credits: typeof receipt.credits === "number" ? receipt.credits : void 0,
4505
+ actions: typeof receipt.actionsEstimate === "number" ? receipt.actionsEstimate : void 0,
4506
+ model: typeof receipt.model === "string" ? receipt.model : void 0,
4507
+ tier: receiptTier(receipt.tier),
4508
+ multiplier: typeof receipt.multiplier === "number" ? receipt.multiplier : void 0,
4509
+ byok: typeof receipt.byok === "boolean" ? receipt.byok : void 0,
4510
+ calibrated: typeof receipt.calibrated === "boolean" ? receipt.calibrated : void 0
4511
+ });
4512
+ }
4513
+ function runUsage(run, receipts) {
4514
+ const actions = n(run.budget?.spent?.actionsEstimate);
4515
+ const stamped = run.budget?.engine;
4516
+ const priced = (receipts ?? []).filter(isPricedStepReceipt);
4517
+ const engine = stamped === "seat" || stamped === "legacy" ? stamped : actions > 0 || priced.some((r) => r.engine === "actions") ? "seat" : priced.some((r) => r.engine === "credits") ? "legacy" : void 0;
4518
+ const seat = engine === "seat";
4519
+ const metering = engine ? "priced" : "flat";
4222
4520
  return {
4223
4521
  creditsUsed: run.budget?.spent?.credits ?? 0,
4224
4522
  actionsEstimate: run.budget?.spent?.actionsEstimate ?? 0,
4523
+ ...seat ? {
4524
+ actionsUsed: actions
4525
+ } : {},
4526
+ metering,
4527
+ ...engine ? {
4528
+ engine
4529
+ } : {},
4225
4530
  steps: run.budget?.spent?.steps ?? 0,
4226
4531
  inputTokens: run.usage?.inputTokens ?? 0,
4227
4532
  outputTokens: run.usage?.outputTokens ?? 0
4228
4533
  };
4229
4534
  }
4535
+ function runBudgetCap(budget) {
4536
+ const cap = budget?.maxCredits;
4537
+ return typeof cap === "number" && Number.isFinite(cap) && cap > 0 ? cap : void 0;
4538
+ }
4539
+ function runBudgetRemaining(budget) {
4540
+ const cap = runBudgetCap(budget);
4541
+ if (cap === void 0) return void 0;
4542
+ const spent = budget?.spent;
4543
+ return Math.max(0, cap - n(spent?.credits) - n(spent?.actionsEstimate) - n(budget?.reserved));
4544
+ }
4230
4545
  function runCancelView(cancel) {
4231
4546
  if (!cancel) return void 0;
4232
4547
  return {
@@ -5245,7 +5560,7 @@ function needsInheritedWorkspace(graph) {
5245
5560
  }
5246
5561
  return false;
5247
5562
  }
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;
5563
+ var __defProp3, __name3, WorkflowTemplateError, TEMPLATE_PLACEHOLDER, TEMPLATE_NAMESPACES, MAP_DESCRIPTOR_KEYS, MAP_MEMBER_MALFORMED_CODE, fromInit, fromStep, value, template, fromRequest, rows, fromKnowledge, 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, 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;
5249
5564
  var init_dist2 = __esm({
5250
5565
  "../workflow-graph/dist/index.mjs"() {
5251
5566
  "use strict";
@@ -5258,6 +5573,94 @@ var init_dist2 = __esm({
5258
5573
  init_dist();
5259
5574
  __defProp3 = Object.defineProperty;
5260
5575
  __name3 = /* @__PURE__ */ __name((target, value22) => __defProp3(target, "name", { value: value22, configurable: true }), "__name");
5576
+ WorkflowTemplateError = class extends Error {
5577
+ static {
5578
+ __name(this, "WorkflowTemplateError");
5579
+ }
5580
+ static {
5581
+ __name3(this, "WorkflowTemplateError");
5582
+ }
5583
+ placeholder;
5584
+ constructor(message, placeholder) {
5585
+ super(message), this.placeholder = placeholder;
5586
+ this.name = "WorkflowTemplateError";
5587
+ }
5588
+ };
5589
+ __name(isMapConfigObject, "isMapConfigObject");
5590
+ __name3(isMapConfigObject, "isMapConfigObject");
5591
+ __name(parseMapConfig, "parseMapConfig");
5592
+ __name3(parseMapConfig, "parseMapConfig");
5593
+ __name(mapConfigWire, "mapConfigWire");
5594
+ __name3(mapConfigWire, "mapConfigWire");
5595
+ TEMPLATE_PLACEHOLDER = /\$\{([^}]*)\}/g;
5596
+ TEMPLATE_NAMESPACES = [
5597
+ "initData",
5598
+ "state",
5599
+ "requestContext",
5600
+ "stepResults"
5601
+ ];
5602
+ __name(describeBadPlaceholder, "describeBadPlaceholder");
5603
+ __name3(describeBadPlaceholder, "describeBadPlaceholder");
5604
+ __name(parseTemplatePlaceholder, "parseTemplatePlaceholder");
5605
+ __name3(parseTemplatePlaceholder, "parseTemplatePlaceholder");
5606
+ __name(traverseMappingPath, "traverseMappingPath");
5607
+ __name3(traverseMappingPath, "traverseMappingPath");
5608
+ __name(stringifyTemplateValue, "stringifyTemplateValue");
5609
+ __name3(stringifyTemplateValue, "stringifyTemplateValue");
5610
+ __name(escapeFence, "escapeFence");
5611
+ __name3(escapeFence, "escapeFence");
5612
+ __name(fenceBlock, "fenceBlock");
5613
+ __name3(fenceBlock, "fenceBlock");
5614
+ __name(renderTemplate, "renderTemplate");
5615
+ __name3(renderTemplate, "renderTemplate");
5616
+ __name(isMapDescriptor, "isMapDescriptor");
5617
+ __name3(isMapDescriptor, "isMapDescriptor");
5618
+ MAP_DESCRIPTOR_KEYS = [
5619
+ "step",
5620
+ "path",
5621
+ "initData",
5622
+ "value",
5623
+ "template",
5624
+ "requestContextPath",
5625
+ "knowledge"
5626
+ ];
5627
+ MAP_MEMBER_MALFORMED_CODE = "map-member-malformed";
5628
+ __name(malformedMapMembers, "malformedMapMembers");
5629
+ __name3(malformedMapMembers, "malformedMapMembers");
5630
+ __name(mapMemberMalformedMessage, "mapMemberMalformedMessage");
5631
+ __name3(mapMemberMalformedMessage, "mapMemberMalformedMessage");
5632
+ __name(resolveDescriptor, "resolveDescriptor");
5633
+ __name3(resolveDescriptor, "resolveDescriptor");
5634
+ __name(resolveMapping, "resolveMapping");
5635
+ __name3(resolveMapping, "resolveMapping");
5636
+ fromInit = /* @__PURE__ */ __name3((path3) => ({
5637
+ initData: true,
5638
+ path: path3
5639
+ }), "fromInit");
5640
+ fromStep = /* @__PURE__ */ __name3((s, path3 = "") => {
5641
+ const idOf = /* @__PURE__ */ __name3((x) => typeof x === "string" ? x : x.id, "idOf");
5642
+ return {
5643
+ step: Array.isArray(s) ? s.map(idOf) : idOf(s),
5644
+ path: path3
5645
+ };
5646
+ }, "fromStep");
5647
+ value = /* @__PURE__ */ __name3((v) => ({
5648
+ value: v
5649
+ }), "value");
5650
+ template = /* @__PURE__ */ __name3((s) => ({
5651
+ template: s
5652
+ }), "template");
5653
+ fromRequest = /* @__PURE__ */ __name3((path3) => ({
5654
+ requestContextPath: path3
5655
+ }), "fromRequest");
5656
+ rows = /* @__PURE__ */ __name3((s, path3, page) => ({
5657
+ step: typeof s === "string" ? s : s.id,
5658
+ path: path3,
5659
+ rows: page
5660
+ }), "rows");
5661
+ fromKnowledge = /* @__PURE__ */ __name3((k) => ({
5662
+ knowledge: k
5663
+ }), "fromKnowledge");
5261
5664
  SideEffectsSchema = z4.enum(WORKFLOW_SIDE_EFFECTS);
5262
5665
  JobResourcesSchema = z4.enum(WORKFLOW_JOB_RESOURCES);
5263
5666
  WORKFLOW_ARM_SUBRUN_ID = "$arm";
@@ -5501,78 +5904,6 @@ var init_dist2 = __esm({
5501
5904
  op: "not",
5502
5905
  arg
5503
5906
  }), "not");
5504
- WorkflowTemplateError = class extends Error {
5505
- static {
5506
- __name(this, "WorkflowTemplateError");
5507
- }
5508
- static {
5509
- __name3(this, "WorkflowTemplateError");
5510
- }
5511
- placeholder;
5512
- constructor(message, placeholder) {
5513
- super(message), this.placeholder = placeholder;
5514
- this.name = "WorkflowTemplateError";
5515
- }
5516
- };
5517
- __name(isMapConfigObject, "isMapConfigObject");
5518
- __name3(isMapConfigObject, "isMapConfigObject");
5519
- __name(parseMapConfig, "parseMapConfig");
5520
- __name3(parseMapConfig, "parseMapConfig");
5521
- __name(mapConfigWire, "mapConfigWire");
5522
- __name3(mapConfigWire, "mapConfigWire");
5523
- TEMPLATE_PLACEHOLDER = /\$\{([^}]*)\}/g;
5524
- TEMPLATE_NAMESPACES = [
5525
- "initData",
5526
- "state",
5527
- "requestContext",
5528
- "stepResults"
5529
- ];
5530
- __name(describeBadPlaceholder, "describeBadPlaceholder");
5531
- __name3(describeBadPlaceholder, "describeBadPlaceholder");
5532
- __name(parseTemplatePlaceholder, "parseTemplatePlaceholder");
5533
- __name3(parseTemplatePlaceholder, "parseTemplatePlaceholder");
5534
- __name(traverseMappingPath, "traverseMappingPath");
5535
- __name3(traverseMappingPath, "traverseMappingPath");
5536
- __name(stringifyTemplateValue, "stringifyTemplateValue");
5537
- __name3(stringifyTemplateValue, "stringifyTemplateValue");
5538
- __name(escapeFence, "escapeFence");
5539
- __name3(escapeFence, "escapeFence");
5540
- __name(fenceBlock, "fenceBlock");
5541
- __name3(fenceBlock, "fenceBlock");
5542
- __name(renderTemplate, "renderTemplate");
5543
- __name3(renderTemplate, "renderTemplate");
5544
- __name(resolveDescriptor, "resolveDescriptor");
5545
- __name3(resolveDescriptor, "resolveDescriptor");
5546
- __name(resolveMapping, "resolveMapping");
5547
- __name3(resolveMapping, "resolveMapping");
5548
- fromInit = /* @__PURE__ */ __name3((path3) => ({
5549
- initData: true,
5550
- path: path3
5551
- }), "fromInit");
5552
- fromStep = /* @__PURE__ */ __name3((s, path3 = "") => {
5553
- const idOf = /* @__PURE__ */ __name3((x) => typeof x === "string" ? x : x.id, "idOf");
5554
- return {
5555
- step: Array.isArray(s) ? s.map(idOf) : idOf(s),
5556
- path: path3
5557
- };
5558
- }, "fromStep");
5559
- value = /* @__PURE__ */ __name3((v) => ({
5560
- value: v
5561
- }), "value");
5562
- template = /* @__PURE__ */ __name3((s) => ({
5563
- template: s
5564
- }), "template");
5565
- fromRequest = /* @__PURE__ */ __name3((path3) => ({
5566
- requestContextPath: path3
5567
- }), "fromRequest");
5568
- rows = /* @__PURE__ */ __name3((s, path3, page) => ({
5569
- step: typeof s === "string" ? s : s.id,
5570
- path: path3,
5571
- rows: page
5572
- }), "rows");
5573
- fromKnowledge = /* @__PURE__ */ __name3((k) => ({
5574
- knowledge: k
5575
- }), "fromKnowledge");
5576
5907
  CONTINUED_FAILURE_TAG = "continued_failure";
5577
5908
  CONTINUED_FAILURE_DEFAULT_CODE = "step_failed";
5578
5909
  CONTINUED_FAILURE_OUTPUT_SCHEMA = Object.freeze({
@@ -5698,8 +6029,20 @@ var init_dist2 = __esm({
5698
6029
  n = /* @__PURE__ */ __name3((v) => typeof v === "number" && Number.isFinite(v) ? v : 0, "n");
5699
6030
  __name(runCounts, "runCounts");
5700
6031
  __name3(runCounts, "runCounts");
6032
+ __name(isPricedStepReceipt, "isPricedStepReceipt");
6033
+ __name3(isPricedStepReceipt, "isPricedStepReceipt");
6034
+ __name(receiptEngine, "receiptEngine");
6035
+ __name3(receiptEngine, "receiptEngine");
6036
+ __name(receiptTier, "receiptTier");
6037
+ __name3(receiptTier, "receiptTier");
6038
+ __name(stepBillingView, "stepBillingView");
6039
+ __name3(stepBillingView, "stepBillingView");
5701
6040
  __name(runUsage, "runUsage");
5702
6041
  __name3(runUsage, "runUsage");
6042
+ __name(runBudgetCap, "runBudgetCap");
6043
+ __name3(runBudgetCap, "runBudgetCap");
6044
+ __name(runBudgetRemaining, "runBudgetRemaining");
6045
+ __name3(runBudgetRemaining, "runBudgetRemaining");
5703
6046
  __name(runCancelView, "runCancelView");
5704
6047
  __name3(runCancelView, "runCancelView");
5705
6048
  __name(runWorkspaceView, "runWorkspaceView");
@@ -6181,6 +6524,7 @@ var init_workflow = __esm({
6181
6524
  }, "assertPredicate");
6182
6525
  assertRetry = /* @__PURE__ */ __name((r, id) => {
6183
6526
  if (!r) return;
6527
+ if (typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS) throw new LuaWorkflowBuildError("cap-exceeded", `"${id}": ${workflowRetryMaxAttemptsMessage(r.maxAttempts)}`);
6184
6528
  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(" | ")}`);
6185
6529
  if (r.maxBackoffSeconds !== void 0) {
6186
6530
  if (r.backoff !== "exponential") throw new LuaWorkflowBuildError("backoff-invalid", `"${id}": retry.maxBackoffSeconds is only meaningful with backoff:'exponential'`);
@@ -6950,6 +7294,74 @@ var init_auth_error = __esm({
6950
7294
  }
6951
7295
  });
6952
7296
 
7297
+ // src/errors/cli.error.ts
7298
+ function isAccessDeniedError(error) {
7299
+ if (CliError.isCliError(error)) return error.statusCode === 403;
7300
+ return error instanceof Error && error.message.startsWith("Access denied (403)");
7301
+ }
7302
+ var CLI_EXIT, CliError;
7303
+ var init_cli_error = __esm({
7304
+ "src/errors/cli.error.ts"() {
7305
+ "use strict";
7306
+ init_auth_error();
7307
+ CLI_EXIT = {
7308
+ OK: 0,
7309
+ ERROR: 1,
7310
+ USAGE: 2,
7311
+ NOT_FOUND: 3,
7312
+ AUTH: 9,
7313
+ FORBIDDEN: 10,
7314
+ UNAVAILABLE: 11
7315
+ };
7316
+ CliError = class _CliError extends Error {
7317
+ static {
7318
+ __name(this, "CliError");
7319
+ }
7320
+ isCliError = true;
7321
+ code;
7322
+ exitCode;
7323
+ hint;
7324
+ statusCode;
7325
+ constructor(code, message, options = {}) {
7326
+ super(message);
7327
+ this.name = "CliError";
7328
+ this.code = code;
7329
+ this.exitCode = options.exitCode ?? CLI_EXIT.ERROR;
7330
+ this.hint = options.hint;
7331
+ this.statusCode = options.statusCode;
7332
+ if (Error.captureStackTrace) Error.captureStackTrace(this, _CliError);
7333
+ }
7334
+ /** Bad arguments, an unknown action, no project — exit 2. */
7335
+ static usage(message, hint) {
7336
+ return new _CliError("usage", message, {
7337
+ exitCode: CLI_EXIT.USAGE,
7338
+ hint
7339
+ });
7340
+ }
7341
+ /** The named thing does not exist — exit 3. */
7342
+ static notFound(message, hint) {
7343
+ return new _CliError("not_found", message, {
7344
+ exitCode: CLI_EXIT.NOT_FOUND,
7345
+ hint,
7346
+ statusCode: 404
7347
+ });
7348
+ }
7349
+ /** The credential may not do this — exit 10. */
7350
+ static forbidden(message, hint) {
7351
+ return new _CliError("forbidden", message, {
7352
+ exitCode: CLI_EXIT.FORBIDDEN,
7353
+ hint,
7354
+ statusCode: 403
7355
+ });
7356
+ }
7357
+ static isCliError(error) {
7358
+ return error instanceof _CliError || typeof error === "object" && error !== null && error.isCliError === true;
7359
+ }
7360
+ };
7361
+ __name(isAccessDeniedError, "isAccessDeniedError");
7362
+ }
7363
+ });
7364
+
6953
7365
  // src/utils/package-root.ts
6954
7366
  import { readFileSync, existsSync } from "fs";
6955
7367
  import { fileURLToPath, pathToFileURL } from "url";
@@ -7476,6 +7888,10 @@ async function* parseSseStream(body, signal) {
7476
7888
  if (frame) yield frame;
7477
7889
  }
7478
7890
  } finally {
7891
+ try {
7892
+ await reader.cancel();
7893
+ } catch {
7894
+ }
7479
7895
  try {
7480
7896
  reader.releaseLock();
7481
7897
  } catch {
@@ -7505,6 +7921,7 @@ var init_http_client = __esm({
7505
7921
  "use strict";
7506
7922
  init_dist();
7507
7923
  init_auth_error();
7924
+ init_cli_error();
7508
7925
  init_lua_fetch();
7509
7926
  init_request_credential();
7510
7927
  DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
@@ -7568,7 +7985,7 @@ var init_http_client = __esm({
7568
7985
  if (AuthenticationError.isAuthenticationError(error)) {
7569
7986
  throw error;
7570
7987
  }
7571
- if (error instanceof Error && error.message.startsWith("Access denied (403)")) {
7988
+ if (isAccessDeniedError(error)) {
7572
7989
  throw error;
7573
7990
  }
7574
7991
  if (error instanceof DOMException && error.name === "AbortError") {
@@ -7616,8 +8033,11 @@ var init_http_client = __esm({
7616
8033
  }
7617
8034
  if (response.status === 403) {
7618
8035
  const detail = errorData.message || "You do not have permission to access this resource.";
7619
- throw new Error(`Access denied (403): ${detail}
7620
- Check that your Lua login has access to this agent or organization.`);
8036
+ throw new CliError("forbidden", `Access denied (403): ${detail}`, {
8037
+ exitCode: CLI_EXIT.FORBIDDEN,
8038
+ statusCode: 403,
8039
+ hint: "Check that your Lua login has access to this agent or organization."
8040
+ });
7621
8041
  }
7622
8042
  return {
7623
8043
  success: false,
@@ -7859,6 +8279,7 @@ var init_auth = __esm({
7859
8279
  init_auth_api_service();
7860
8280
  init_constants();
7861
8281
  init_auth_error();
8282
+ init_cli_error();
7862
8283
  }
7863
8284
  });
7864
8285
 
@@ -8086,6 +8507,9 @@ function buildSourceArchive(files) {
8086
8507
  const gz = zlib.gzipSync(Buffer.from(json, "utf-8"));
8087
8508
  return gz.toString("base64");
8088
8509
  }
8510
+ function getPrimitivesByKind(manifest, kind) {
8511
+ return manifest.primitives.filter((p) => p.kind === kind);
8512
+ }
8089
8513
  function findPrimitive(manifest, name, kind) {
8090
8514
  return manifest.primitives.find((p) => {
8091
8515
  if (kind && p.kind !== kind) return false;
@@ -8106,6 +8530,7 @@ var init_artifact_loader = __esm({
8106
8530
  __name(loadOriginalSource, "loadOriginalSource");
8107
8531
  __name(normalizeEntryFile, "normalizeEntryFile");
8108
8532
  __name(buildSourceArchive, "buildSourceArchive");
8533
+ __name(getPrimitivesByKind, "getPrimitivesByKind");
8109
8534
  __name(findPrimitive, "findPrimitive");
8110
8535
  }
8111
8536
  });
@@ -8752,6 +9177,7 @@ var init_base_handler = __esm({
8752
9177
  init_bundle_upload();
8753
9178
  init_semver();
8754
9179
  init_auth_error();
9180
+ init_cli_error();
8755
9181
  DEFAULT_VERSION = SKILL_DEFAULTS.VERSION;
8756
9182
  BaseVersionedHandler = class {
8757
9183
  static {
@@ -8833,7 +9259,7 @@ var init_base_handler = __esm({
8833
9259
  serverItems
8834
9260
  };
8835
9261
  } catch (error) {
8836
- if (AuthenticationError.isAuthenticationError(error)) throw error;
9262
+ if (AuthenticationError.isAuthenticationError(error) || isAccessDeniedError(error)) throw error;
8837
9263
  return {
8838
9264
  serverItems: null,
8839
9265
  fetchError: error instanceof Error ? error.message : String(error)
@@ -8863,13 +9289,24 @@ var init_base_handler = __esm({
8863
9289
  }
8864
9290
  const yamlItems = this.getFromYaml(config);
8865
9291
  const { yamlById, yamlByName, serverByName } = this.buildMaps(serverData.serverItems, yamlItems);
9292
+ const idField = this.yamlConfig.idField;
9293
+ const manifestNames = manifest ? new Set(getPrimitivesByKind(manifest, this.kind).map((p) => p.name)) : /* @__PURE__ */ new Set();
9294
+ for (const stale of this.staleYamlRows(yamlItems, serverData.serverItems, manifestNames)) {
9295
+ const idx = yamlItems.indexOf(stale);
9296
+ if (idx < 0) continue;
9297
+ const { [idField]: goneId, ...rest } = stale;
9298
+ yamlItems[idx] = rest;
9299
+ yamlUpdated = true;
9300
+ const msg = `\u2139\uFE0F ${this.displayName} "${stale.name}" (${goneId}) no longer exists on the server \u2014 re-registering it`;
9301
+ messages.push(msg);
9302
+ console.log(msg);
9303
+ }
8866
9304
  const orphans = serverData.serverItems.filter((item) => {
8867
9305
  const id = item.id;
8868
9306
  const name = item.name;
8869
9307
  return !yamlById.has(id) && !yamlByName.has(name) && this.isActive(item) && this.shouldConsiderForOrphan(item);
8870
9308
  });
8871
9309
  if (orphans.length > 0) {
8872
- const idField = this.yamlConfig.idField;
8873
9310
  const stubs = orphans.map((item) => this.cleanItem({
8874
9311
  name: item.name,
8875
9312
  version: this.getActiveVersion(item) || DEFAULT_VERSION,
@@ -8912,6 +9349,7 @@ var init_base_handler = __esm({
8912
9349
  console.log(`\u2705 Server ${this.displayNamePlural} and YAML are fully in sync`);
8913
9350
  }
8914
9351
  } catch (error) {
9352
+ if (AuthenticationError.isAuthenticationError(error) || isAccessDeniedError(error)) throw error;
8915
9353
  console.error(`\u274C Error syncing server ${this.displayNamePlural}:`, error);
8916
9354
  }
8917
9355
  return {
@@ -8968,6 +9406,7 @@ var init_base_handler = __esm({
8968
9406
  console.error(` \u274C Failed to create "${item.name}" - no ID returned`);
8969
9407
  }
8970
9408
  } catch (error) {
9409
+ if (AuthenticationError.isAuthenticationError(error) || isAccessDeniedError(error)) throw error;
8971
9410
  console.error(` \u274C Failed to create "${item.name}": ${error instanceof Error ? error.message : error}`);
8972
9411
  }
8973
9412
  }
@@ -9102,6 +9541,15 @@ var init_base_handler = __esm({
9102
9541
  getItemId(item) {
9103
9542
  return item[this.yamlConfig.idField] || "";
9104
9543
  }
9544
+ /**
9545
+ * LUA-750: the yaml rows whose server id is gone (deleted server-side) and which `applySyncToYaml` should
9546
+ * re-register. Default none — a handler whose `fetchFromServer` lists EVERY live row of its kind for the
9547
+ * agent overrides this (a kind whose list omits inactive rows must not, or it would duplicate them).
9548
+ * `manifestNames` is the set of primitives in local code: only those are worth re-creating.
9549
+ */
9550
+ staleYamlRows(_yamlItems, _serverItems, _manifestNames) {
9551
+ return [];
9552
+ }
9105
9553
  buildMaps(serverItems, yamlItems) {
9106
9554
  const yamlById = /* @__PURE__ */ new Map();
9107
9555
  const yamlByName = /* @__PURE__ */ new Map();
@@ -9500,6 +9948,7 @@ var init_cli = __esm({
9500
9948
  "src/utils/cli.ts"() {
9501
9949
  "use strict";
9502
9950
  init_auth_error();
9951
+ init_cli_error();
9503
9952
  init_version_check();
9504
9953
  init_package_root();
9505
9954
  init_analytics();
@@ -9519,6 +9968,7 @@ var init_command_utils = __esm({
9519
9968
  init_request_credential();
9520
9969
  init_files();
9521
9970
  init_cli();
9971
+ init_cli_error();
9522
9972
  __name(requireAuth, "requireAuth");
9523
9973
  }
9524
9974
  });
@@ -13067,7 +13517,10 @@ var init_workflow_api_service = __esm({
13067
13517
  async getRunReplayBundle(runId) {
13068
13518
  return this.httpGet(`${this.runs}/${runId}/journal?format=replay`, await this.auth());
13069
13519
  }
13070
- /** R11 — cancel (`mode:'request'` default; `'force'` after `forceAvailableAt`, 409 `FORCE_NOT_YET_AVAILABLE` before). */
13520
+ /**
13521
+ * R11 — cancel (`mode:'request'` default). A `'force'` before `forceAvailableAt` is the 200 verdict
13522
+ * `{ transitioned:false, nextAction:'cancel_again', forceAvailableAt }` (PRO-979) — never a 409 (LUA-748).
13523
+ */
13071
13524
  async cancelRun(runId, data = {}) {
13072
13525
  return this.httpPost(`${this.runs}/${runId}/cancel`, data, await this.auth());
13073
13526
  }
@@ -13146,6 +13599,14 @@ var init_workflow_api_service = __esm({
13146
13599
  async closeGoal(goalId, data = {}) {
13147
13600
  return this.httpPost(`${this.goals}/${encodeURIComponent(goalId)}/close`, data, await this.auth());
13148
13601
  }
13602
+ /** LUA-749 R63 — edit (objective / judge / cadence / caps / note); a `budget` / `max_runs` park re-arms when the cap clears (`rearmed:true`). */
13603
+ async updateGoal(goalId, data) {
13604
+ return this.httpPatch(`${this.goals}/${encodeURIComponent(goalId)}`, data, await this.auth());
13605
+ }
13606
+ /** LUA-749 R64 — raise `maxTotalCredits` / `maxRuns` (increases only; 400 `GOAL_RAISE_BELOW_SPENT{field, value, spent}`). */
13607
+ async raiseGoal(goalId, data) {
13608
+ return this.httpPost(`${this.goals}/${encodeURIComponent(goalId)}/raise`, data, await this.auth());
13609
+ }
13149
13610
  // ─── Schedules (R4-MF-2 list/get + R28 delete — `/workflows/:agentId/schedules`; LUA-627 stanza) ───
13150
13611
  /** Schedule tree (09 §9.5 — the write-only R27/R56/R28 family plus the R4-MF-2 read rows). */
13151
13612
  get schedules() {
@@ -13159,7 +13620,7 @@ var init_workflow_api_service = __esm({
13159
13620
  async getSchedule(jobId) {
13160
13621
  return this.httpGet(`${this.schedules}/${encodeURIComponent(jobId)}`, await this.auth());
13161
13622
  }
13162
- /** R28 — delete a schedule Job (404 `SCHEDULE_NOT_FOUND`). The CLI refuses a goal-owned job BEFORE this call (`goal_schedule`). */
13623
+ /** R28 — delete a schedule Job (404 `SCHEDULE_NOT_FOUND`). The CLI refuses a LIVE goal's job BEFORE this call (`goal_schedule`); an ended goal's lingering Job is retired here (LUA-760). */
13163
13624
  async deleteSchedule(jobId) {
13164
13625
  return this.httpDelete(`${this.schedules}/${encodeURIComponent(jobId)}`, await this.auth());
13165
13626
  }