lua-cli 3.36.0 → 3.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api-exports.d.ts +43 -13
- package/dist/api-exports.js +295 -3
- package/dist/api-exports.js.map +1 -1
- package/dist/index.js +2320 -153
- package/dist/index.js.map +1 -1
- package/dist/workflow-builder.js +294 -1
- package/dist/workflow-builder.js.map +1 -1
- package/docs/README.md +2 -2
- package/package.json +1 -1
- package/template/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -642,7 +642,6 @@ var init_constants = __esm({
|
|
|
642
642
|
API: process.env.LUA_API_URL || "https://api.heylua.ai",
|
|
643
643
|
AUTH: process.env.LUA_AUTH_URL || "https://auth.heylua.ai",
|
|
644
644
|
CHAT: process.env.LUA_API_URL || "https://api.heylua.ai",
|
|
645
|
-
WEBHOOK: process.env.LUA_WEBHOOK_URL || "https://webhook.heylua.ai",
|
|
646
645
|
CDN: "https://cdn.heylua.ai"
|
|
647
646
|
};
|
|
648
647
|
CREDENTIALS_FILE = join(CLI_CONFIG_DIR, "credentials");
|
|
@@ -841,6 +840,12 @@ var init_package_root = __esm({
|
|
|
841
840
|
import { z } from "zod";
|
|
842
841
|
import { z as z2 } from "zod";
|
|
843
842
|
import { z as z3 } from "zod";
|
|
843
|
+
function isChannelConversationChannel(channel) {
|
|
844
|
+
return !!channel && CHANNEL_CONVERSATION_CHANNELS.includes(channel);
|
|
845
|
+
}
|
|
846
|
+
function isChannelConversationThread(threadId, channel) {
|
|
847
|
+
return !!threadId && isChannelConversationChannel(channel);
|
|
848
|
+
}
|
|
844
849
|
function isPersonaTextObject(value3) {
|
|
845
850
|
if (value3 === null || typeof value3 !== "object" || Array.isArray(value3)) return false;
|
|
846
851
|
const obj = value3;
|
|
@@ -1403,6 +1408,101 @@ function buildDefaultPersona(agentName) {
|
|
|
1403
1408
|
function buildPersonalSpaceStartingPersona(agentName) {
|
|
1404
1409
|
return PERSONAL_SPACE_STARTING_PERSONA.replace(new RegExp(AGENT_NAME_TOKEN.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"), () => agentName || "Your assistant");
|
|
1405
1410
|
}
|
|
1411
|
+
function maxDrainsForTier(tier) {
|
|
1412
|
+
return tier === "enterprise" ? LOG_DRAIN_MAX_PER_ORG_ENTERPRISE : LOG_DRAIN_MAX_PER_ORG;
|
|
1413
|
+
}
|
|
1414
|
+
function resolvePresetEndpoint(type, site) {
|
|
1415
|
+
const template3 = LOG_DRAIN_ENDPOINT_TEMPLATES[type];
|
|
1416
|
+
if (!template3 || !site) return void 0;
|
|
1417
|
+
return template3.replace("{site}", site);
|
|
1418
|
+
}
|
|
1419
|
+
function nextLogDrainQuotaResetAt(now) {
|
|
1420
|
+
return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1)).toISOString();
|
|
1421
|
+
}
|
|
1422
|
+
function logDrainQuotaWindowExpired(usage, now) {
|
|
1423
|
+
const resetsAt = Date.parse(usage?.resetsAt ?? "");
|
|
1424
|
+
if (!Number.isFinite(resetsAt)) return true;
|
|
1425
|
+
return now.getTime() >= resetsAt;
|
|
1426
|
+
}
|
|
1427
|
+
function logDrainQuotaRatio(usage, now) {
|
|
1428
|
+
if (!usage) return 0;
|
|
1429
|
+
if (now && logDrainQuotaWindowExpired(usage, now)) return 0;
|
|
1430
|
+
const dimension = /* @__PURE__ */ __name2((used, limit) => {
|
|
1431
|
+
if (!Number.isFinite(limit) || limit <= 0) return 0;
|
|
1432
|
+
if (!Number.isFinite(used) || used <= 0) return 0;
|
|
1433
|
+
return used / limit;
|
|
1434
|
+
}, "dimension");
|
|
1435
|
+
return Math.max(dimension(usage.usedEvents, usage.eventsPerDay), dimension(usage.usedBytes, usage.bytesPerDay));
|
|
1436
|
+
}
|
|
1437
|
+
function logDrainQuotaDegradationForRatio(ratio) {
|
|
1438
|
+
if (!Number.isFinite(ratio)) return "none";
|
|
1439
|
+
if (ratio >= LOG_DRAIN_QUOTA_PAUSE_RATIO) return "paused";
|
|
1440
|
+
if (ratio >= LOG_DRAIN_QUOTA_DROP_INFO_RATIO) return "info_dropped";
|
|
1441
|
+
if (ratio >= LOG_DRAIN_QUOTA_DROP_DEBUG_RATIO) return "debug_dropped";
|
|
1442
|
+
return "none";
|
|
1443
|
+
}
|
|
1444
|
+
function logDrainQuotaDegradation(usage, now) {
|
|
1445
|
+
return logDrainQuotaDegradationForRatio(logDrainQuotaRatio(usage, now));
|
|
1446
|
+
}
|
|
1447
|
+
function logDrainQuotaWarned(usage, now) {
|
|
1448
|
+
return logDrainQuotaRatio(usage, now) >= LOG_DRAIN_QUOTA_WARN_RATIO;
|
|
1449
|
+
}
|
|
1450
|
+
function logDrainQuotaDroppedSeverities(degradation) {
|
|
1451
|
+
switch (degradation) {
|
|
1452
|
+
case "debug_dropped":
|
|
1453
|
+
return [
|
|
1454
|
+
5
|
|
1455
|
+
];
|
|
1456
|
+
case "info_dropped":
|
|
1457
|
+
return [
|
|
1458
|
+
5,
|
|
1459
|
+
9
|
|
1460
|
+
];
|
|
1461
|
+
default:
|
|
1462
|
+
return [];
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
function encodeLogCursor(c) {
|
|
1466
|
+
return Buffer.from(JSON.stringify({
|
|
1467
|
+
t: c.t,
|
|
1468
|
+
id: c.id
|
|
1469
|
+
}), "utf8").toString("base64url");
|
|
1470
|
+
}
|
|
1471
|
+
function decodeLogCursor(raw) {
|
|
1472
|
+
if (typeof raw !== "string") return null;
|
|
1473
|
+
const trimmed2 = raw.trim();
|
|
1474
|
+
if (!trimmed2 || trimmed2.length > LOG_CURSOR_MAX_LENGTH) return null;
|
|
1475
|
+
let parsed;
|
|
1476
|
+
try {
|
|
1477
|
+
parsed = JSON.parse(Buffer.from(trimmed2, "base64url").toString("utf8"));
|
|
1478
|
+
} catch {
|
|
1479
|
+
return null;
|
|
1480
|
+
}
|
|
1481
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
1482
|
+
const { t, id } = parsed;
|
|
1483
|
+
if (typeof t !== "number" || !Number.isSafeInteger(t) || t < 0) return null;
|
|
1484
|
+
if (typeof id !== "string" || !id || id.length > LOG_CURSOR_MAX_ID_LENGTH) return null;
|
|
1485
|
+
return {
|
|
1486
|
+
t,
|
|
1487
|
+
id
|
|
1488
|
+
};
|
|
1489
|
+
}
|
|
1490
|
+
function parseLogTimeBound(raw, now = /* @__PURE__ */ new Date()) {
|
|
1491
|
+
if (typeof raw !== "string") return null;
|
|
1492
|
+
const value3 = raw.trim();
|
|
1493
|
+
if (!value3) return null;
|
|
1494
|
+
const relative3 = LOG_RELATIVE_TIME_PATTERN.exec(value3);
|
|
1495
|
+
if (relative3) {
|
|
1496
|
+
const amount = Number(relative3[1]);
|
|
1497
|
+
const unitMs = RELATIVE_UNIT_MS[relative3[2]];
|
|
1498
|
+
if (!Number.isFinite(amount) || unitMs === void 0) return null;
|
|
1499
|
+
const at2 = now.getTime() - amount * unitMs;
|
|
1500
|
+
return Number.isFinite(at2) ? new Date(at2) : null;
|
|
1501
|
+
}
|
|
1502
|
+
if (!LOG_ISO_TIME_PATTERN.test(value3)) return null;
|
|
1503
|
+
const at = Date.parse(value3);
|
|
1504
|
+
return Number.isNaN(at) ? null : new Date(at);
|
|
1505
|
+
}
|
|
1406
1506
|
function isRecord(value3) {
|
|
1407
1507
|
return typeof value3 === "object" && value3 !== null;
|
|
1408
1508
|
}
|
|
@@ -1767,6 +1867,9 @@ function workflowOccurrenceId(lineageId, stepId) {
|
|
|
1767
1867
|
function workflowOrgSlotKey(orgId, kind) {
|
|
1768
1868
|
return `wf:org:${orgId}:${kind}`;
|
|
1769
1869
|
}
|
|
1870
|
+
function workflowJobModelSourceLabel(source) {
|
|
1871
|
+
return WORKFLOW_JOB_MODEL_SOURCE_LABELS[source];
|
|
1872
|
+
}
|
|
1770
1873
|
function scheduledTimeKey(scheduledTime) {
|
|
1771
1874
|
return scheduledTime.replace(/[^0-9TZ]/g, "");
|
|
1772
1875
|
}
|
|
@@ -1970,17 +2073,17 @@ function isWorkflowApprovalOutput(value3) {
|
|
|
1970
2073
|
return typeof v.approved === "boolean" && WORKFLOW_APPROVAL_OUTPUT_DECISIONS.includes(v.decision) && typeof v.text === "string";
|
|
1971
2074
|
}
|
|
1972
2075
|
function extractSingleJsonValue(text) {
|
|
1973
|
-
const
|
|
1974
|
-
if (!
|
|
2076
|
+
const trimmed2 = (text ?? "").trim();
|
|
2077
|
+
if (!trimmed2) return {
|
|
1975
2078
|
reason: "reply is empty"
|
|
1976
2079
|
};
|
|
1977
2080
|
const fenced = [
|
|
1978
|
-
...
|
|
2081
|
+
...trimmed2.matchAll(JSON_FENCE_RE)
|
|
1979
2082
|
];
|
|
1980
2083
|
if (fenced.length > 1) return {
|
|
1981
2084
|
reason: "reply carries more than one fenced block"
|
|
1982
2085
|
};
|
|
1983
|
-
const candidate = fenced.length === 1 ? fenced[0][1].trim() :
|
|
2086
|
+
const candidate = fenced.length === 1 ? fenced[0][1].trim() : trimmed2;
|
|
1984
2087
|
try {
|
|
1985
2088
|
return {
|
|
1986
2089
|
value: JSON.parse(candidate)
|
|
@@ -1991,17 +2094,17 @@ function extractSingleJsonValue(text) {
|
|
|
1991
2094
|
};
|
|
1992
2095
|
}
|
|
1993
2096
|
const opens = [
|
|
1994
|
-
|
|
1995
|
-
|
|
2097
|
+
trimmed2.indexOf("{"),
|
|
2098
|
+
trimmed2.indexOf("[")
|
|
1996
2099
|
].filter((i) => i !== -1);
|
|
1997
2100
|
const start = opens.length ? Math.min(...opens) : -1;
|
|
1998
|
-
const end = Math.max(
|
|
2101
|
+
const end = Math.max(trimmed2.lastIndexOf("}"), trimmed2.lastIndexOf("]"));
|
|
1999
2102
|
if (start === -1 || end <= start) return {
|
|
2000
2103
|
reason: "reply is not JSON"
|
|
2001
2104
|
};
|
|
2002
2105
|
try {
|
|
2003
2106
|
return {
|
|
2004
|
-
value: JSON.parse(
|
|
2107
|
+
value: JSON.parse(trimmed2.slice(start, end + 1))
|
|
2005
2108
|
};
|
|
2006
2109
|
} catch {
|
|
2007
2110
|
return {
|
|
@@ -2077,12 +2180,39 @@ function effectiveAgentFeatures(base, override, rule) {
|
|
|
2077
2180
|
if (rule === "wholesale") return override || base || void 0;
|
|
2078
2181
|
return effectiveAgentFeatureRows(base, override).rows;
|
|
2079
2182
|
}
|
|
2080
|
-
var __defProp2, __name2, REVIEWABLE_ACTION_EXECUTE_TOOL_ALLOWLIST, REVIEWABLE_STANDING_START_TOOLS, 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, 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_AGENT_EFFORTS, WORKFLOW_MODEL_CLASSES, WORKFLOW_TASK_CLASSES, WORKFLOW_MODEL_TRAITS, WORKFLOW_MODEL_REASON_MAX_LENGTH, WORKFLOW_MODELS_COMPOSE_MODES, WORKFLOW_MODELS_PIN_MODES, WORKFLOW_MODELS_FALLBACK_MODES, WORKFLOW_MODELS_CONSENT_ACTIONS_MIN, WORKFLOW_DEFAULT_TASK_CLASS_MAP, WORKFLOW_MODELS_MAX_CLASS_DEFAULT, WORKFLOW_AUTONOMY_FORMS, WORKFLOW_AUTONOMY_NUMERIC_KEYS, WORKFLOW_AUTONOMY_ENVELOPE_KEYS, WORKFLOW_AUTONOMY_ENABLED_DEFAULT, WORKFLOW_AUTONOMY_DEFAULTS, WORKFLOW_AUTONOMY_CEILINGS, WORKFLOW_AUTONOMY_MAX_RUNS_PER_HOUR_ENV, WORKFLOW_AUTONOMY_MAX_RUNS_PER_HOUR_CEILING, WORKFLOW_AUTONOMY_FORMS_DEFAULT, WORKFLOW_AUTONOMY_MIN_VALUE, 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, MODEL_ID_BYOK_PROVIDERS, MODEL_CLASS_REF_PREFIX, MODEL_SNAPSHOT_SUFFIX, REASONING_EFFORT_VALUES, IMPLICIT_MODEL_SELECTION_SOURCES, PLATFORM_FALLBACK_MODEL_SOURCE, AGENT_NAME_TOKEN, DEFAULT_PERSONA_GUIDE, PERSONAL_SPACE_STARTING_PERSONA, AGENT_LOG_SOURCES, 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, EventType, LUA_JOB_DEFAULT_TIMEOUT_SECONDS, LUA_JOB_MIN_TIMEOUT_SECONDS, LUA_JOB_MAX_TIMEOUT_SECONDS, KEYS, MAX_BODY_BYTES, MAX_ID_LENGTH, UTC_ISO, TEMPLATE_TRIGGER_URL_ENV_PREFIX, TEMPLATE_INSTALL_POLICY_PER_WORKSPACE_VALUES, SUBJECT_TYPES, SubjectTypeSchema, CREDENTIAL_TYPES, CredentialTypeSchema, DEVICE_OPERATIONS, DeviceOperationSchema, DEVICE_SCOPE_BY_OPERATION, DeviceBindingSchema, TYPED_API_KEY, IdSchema, SESSION_AUTH_TIME_MAX_S, 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, LUA_SESSION_ID_CLAIM, SESSION_REVOKED_CODE, 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_RUN_GATE_KINDS, WORKFLOW_STEP_STATUSES, WORKFLOW_STEP_IN_FLIGHT, WORKFLOW_SIGNAL_EVENT_SITES, 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_SCHEDULE_KEY_MAX, WORKFLOW_SCHEDULE_IDEMPOTENCY_KEY_PREFIX, WORKFLOW_OPERATION_ID_PREFIX, WORKFLOW_JOURNAL_PROTOCOL_VERSION, WORKFLOW_CONNECTION_KEY_RE, WORKFLOW_SUSPEND_KINDS, WORKFLOW_RUN_NOTIFICATION_SUSPENDED_KINDS, WORKFLOW_SIGNAL_PAYLOAD_MAX_BYTES, WORKFLOW_RESOLVE_OUTPUT_MAX_BYTES, WORKFLOW_GOAL_JUDGE_SELF, 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, DEFAULT_ON_AGENT_FEATURES, SUBAGENT_PER_KEY_FLAG_ENV, PER_KEY_FLAG_VALUES;
|
|
2183
|
+
var __defProp2, __name2, PLUMBING_THREAD_CHANNELS, CHANNEL_CONVERSATION_CHANNELS, HIDDEN_THREAD_CHANNELS, REVIEWABLE_ACTION_EXECUTE_TOOL_ALLOWLIST, REVIEWABLE_STANDING_START_TOOLS, 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, 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_AGENT_EFFORTS, WORKFLOW_MODEL_CLASSES, WORKFLOW_TASK_CLASSES, WORKFLOW_MODEL_TRAITS, WORKFLOW_MODEL_REASON_MAX_LENGTH, WORKFLOW_MODELS_COMPOSE_MODES, WORKFLOW_MODELS_PIN_MODES, WORKFLOW_MODELS_FALLBACK_MODES, WORKFLOW_MODELS_CONSENT_ACTIONS_MIN, WORKFLOW_DEFAULT_TASK_CLASS_MAP, WORKFLOW_MODELS_MAX_CLASS_DEFAULT, WORKFLOW_AUTONOMY_FORMS, WORKFLOW_AUTONOMY_NUMERIC_KEYS, WORKFLOW_AUTONOMY_ENVELOPE_KEYS, WORKFLOW_AUTONOMY_ENABLED_DEFAULT, WORKFLOW_AUTONOMY_DEFAULTS, WORKFLOW_AUTONOMY_CEILINGS, WORKFLOW_AUTONOMY_MAX_RUNS_PER_HOUR_ENV, WORKFLOW_AUTONOMY_MAX_RUNS_PER_HOUR_CEILING, WORKFLOW_AUTONOMY_FORMS_DEFAULT, WORKFLOW_AUTONOMY_MIN_VALUE, 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, MODEL_ID_BYOK_PROVIDERS, MODEL_CLASS_REF_PREFIX, MODEL_SNAPSHOT_SUFFIX, REASONING_EFFORT_VALUES, IMPLICIT_MODEL_SELECTION_SOURCES, PLATFORM_FALLBACK_MODEL_SOURCE, AGENT_NAME_TOKEN, DEFAULT_PERSONA_GUIDE, PERSONAL_SPACE_STARTING_PERSONA, AGENT_LOG_SOURCES, AGENT_LOG_ENVIRONMENTS, LOG_DRAIN_TYPES_PHASE1, LOG_DRAIN_FORMATS, LOG_DRAIN_SEVERITIES, LOG_DRAIN_SOURCES, LOG_DRAIN_CONTENT_SOURCES, LOG_DRAIN_DEFAULT_SOURCES, LOG_DRAIN_MAX_PER_ORG, LOG_DRAIN_MAX_PER_ORG_ENTERPRISE, LOG_DRAIN_DATADOG_SITES, LOG_DRAIN_ENDPOINT_TEMPLATES, LOG_DRAIN_QUOTAS, LOG_DRAIN_QUOTA_WARN_RATIO, LOG_DRAIN_QUOTA_DROP_DEBUG_RATIO, LOG_DRAIN_QUOTA_DROP_INFO_RATIO, LOG_DRAIN_QUOTA_PAUSE_RATIO, LOG_CURSOR_MAX_LENGTH, LOG_CURSOR_MAX_ID_LENGTH, LOG_RELATIVE_TIME_PATTERN, LOG_ISO_TIME_PATTERN, RELATIVE_UNIT_MS, 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, EventType, LUA_JOB_DEFAULT_TIMEOUT_SECONDS, LUA_JOB_MIN_TIMEOUT_SECONDS, LUA_JOB_MAX_TIMEOUT_SECONDS, KEYS, MAX_BODY_BYTES, MAX_ID_LENGTH, UTC_ISO, TEMPLATE_TRIGGER_URL_ENV_PREFIX, TEMPLATE_INSTALL_POLICY_PER_WORKSPACE_VALUES, SUBJECT_TYPES, SubjectTypeSchema, CREDENTIAL_TYPES, CredentialTypeSchema, DEVICE_OPERATIONS, DeviceOperationSchema, DEVICE_SCOPE_BY_OPERATION, DeviceBindingSchema, TYPED_API_KEY, IdSchema, SESSION_AUTH_TIME_MAX_S, 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, LUA_SESSION_ID_CLAIM, SESSION_REVOKED_CODE, 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_RUN_GATE_KINDS, WORKFLOW_STEP_STATUSES, WORKFLOW_STEP_IN_FLIGHT, WORKFLOW_SIGNAL_EVENT_SITES, 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_SCHEDULE_KEY_MAX, WORKFLOW_SCHEDULE_IDEMPOTENCY_KEY_PREFIX, WORKFLOW_OPERATION_ID_PREFIX, WORKFLOW_JOURNAL_PROTOCOL_VERSION, WORKFLOW_CONNECTION_KEY_RE, WORKFLOW_JOB_MODEL_SOURCE_LABELS, WORKFLOW_SUSPEND_KINDS, WORKFLOW_RUN_NOTIFICATION_SUSPENDED_KINDS, WORKFLOW_SIGNAL_PAYLOAD_MAX_BYTES, WORKFLOW_RESOLVE_OUTPUT_MAX_BYTES, WORKFLOW_GOAL_JUDGE_SELF, 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, DEFAULT_ON_AGENT_FEATURES, SUBAGENT_PER_KEY_FLAG_ENV, PER_KEY_FLAG_VALUES;
|
|
2081
2184
|
var init_dist = __esm({
|
|
2082
2185
|
"../shared-types/dist/index.mjs"() {
|
|
2083
2186
|
"use strict";
|
|
2084
2187
|
__defProp2 = Object.defineProperty;
|
|
2085
2188
|
__name2 = /* @__PURE__ */ __name((target, value3) => __defProp2(target, "name", { value: value3, configurable: true }), "__name");
|
|
2189
|
+
PLUMBING_THREAD_CHANNELS = [
|
|
2190
|
+
"trigger",
|
|
2191
|
+
"template-install",
|
|
2192
|
+
"template-uninstall"
|
|
2193
|
+
];
|
|
2194
|
+
CHANNEL_CONVERSATION_CHANNELS = [
|
|
2195
|
+
"whatsapp",
|
|
2196
|
+
"slack",
|
|
2197
|
+
"teams",
|
|
2198
|
+
"front",
|
|
2199
|
+
"email",
|
|
2200
|
+
"messagebird",
|
|
2201
|
+
"sms",
|
|
2202
|
+
"mms",
|
|
2203
|
+
"rcs",
|
|
2204
|
+
"instagram",
|
|
2205
|
+
"facebook",
|
|
2206
|
+
"imessage"
|
|
2207
|
+
];
|
|
2208
|
+
HIDDEN_THREAD_CHANNELS = [
|
|
2209
|
+
...PLUMBING_THREAD_CHANNELS,
|
|
2210
|
+
...CHANNEL_CONVERSATION_CHANNELS
|
|
2211
|
+
];
|
|
2212
|
+
__name(isChannelConversationChannel, "isChannelConversationChannel");
|
|
2213
|
+
__name2(isChannelConversationChannel, "isChannelConversationChannel");
|
|
2214
|
+
__name(isChannelConversationThread, "isChannelConversationThread");
|
|
2215
|
+
__name2(isChannelConversationThread, "isChannelConversationThread");
|
|
2086
2216
|
__name(isPersonaTextObject, "isPersonaTextObject");
|
|
2087
2217
|
__name2(isPersonaTextObject, "isPersonaTextObject");
|
|
2088
2218
|
__name(flattenPersonaText, "flattenPersonaText");
|
|
@@ -2754,6 +2884,124 @@ This text is who you are for this person. As you learn them, their name, their w
|
|
|
2754
2884
|
"workflow-script",
|
|
2755
2885
|
"workflow"
|
|
2756
2886
|
];
|
|
2887
|
+
AGENT_LOG_ENVIRONMENTS = [
|
|
2888
|
+
"production",
|
|
2889
|
+
"sandbox"
|
|
2890
|
+
];
|
|
2891
|
+
LOG_DRAIN_TYPES_PHASE1 = [
|
|
2892
|
+
"http",
|
|
2893
|
+
"otlp",
|
|
2894
|
+
"datadog",
|
|
2895
|
+
"betterstack"
|
|
2896
|
+
];
|
|
2897
|
+
LOG_DRAIN_FORMATS = [
|
|
2898
|
+
"json",
|
|
2899
|
+
"ndjson"
|
|
2900
|
+
];
|
|
2901
|
+
LOG_DRAIN_SEVERITIES = [
|
|
2902
|
+
"debug",
|
|
2903
|
+
"info",
|
|
2904
|
+
"warn",
|
|
2905
|
+
"error"
|
|
2906
|
+
];
|
|
2907
|
+
LOG_DRAIN_SOURCES = [
|
|
2908
|
+
...AGENT_LOG_SOURCES,
|
|
2909
|
+
"execution",
|
|
2910
|
+
// ── phase 2 ──
|
|
2911
|
+
"delivery",
|
|
2912
|
+
"trigger-execution",
|
|
2913
|
+
"job-execution",
|
|
2914
|
+
"workflow-run",
|
|
2915
|
+
"workflow-audit"
|
|
2916
|
+
];
|
|
2917
|
+
LOG_DRAIN_CONTENT_SOURCES = [
|
|
2918
|
+
"user_message",
|
|
2919
|
+
"agent_response"
|
|
2920
|
+
];
|
|
2921
|
+
LOG_DRAIN_DEFAULT_SOURCES = [
|
|
2922
|
+
"skill",
|
|
2923
|
+
"job",
|
|
2924
|
+
"webhook",
|
|
2925
|
+
"preprocessor",
|
|
2926
|
+
"postprocessor",
|
|
2927
|
+
"workflow-step",
|
|
2928
|
+
"workflow-script",
|
|
2929
|
+
"device",
|
|
2930
|
+
"runtime",
|
|
2931
|
+
"model-resolver",
|
|
2932
|
+
"trigger",
|
|
2933
|
+
"device-trigger",
|
|
2934
|
+
"workflow",
|
|
2935
|
+
"mcp",
|
|
2936
|
+
"rag",
|
|
2937
|
+
"execution",
|
|
2938
|
+
"agent_error"
|
|
2939
|
+
];
|
|
2940
|
+
LOG_DRAIN_MAX_PER_ORG = 5;
|
|
2941
|
+
LOG_DRAIN_MAX_PER_ORG_ENTERPRISE = 10;
|
|
2942
|
+
__name(maxDrainsForTier, "maxDrainsForTier");
|
|
2943
|
+
__name2(maxDrainsForTier, "maxDrainsForTier");
|
|
2944
|
+
LOG_DRAIN_DATADOG_SITES = [
|
|
2945
|
+
"datadoghq.com",
|
|
2946
|
+
"datadoghq.eu",
|
|
2947
|
+
"us3.datadoghq.com",
|
|
2948
|
+
"us5.datadoghq.com",
|
|
2949
|
+
"ap1.datadoghq.com",
|
|
2950
|
+
"ddog-gov.com"
|
|
2951
|
+
];
|
|
2952
|
+
LOG_DRAIN_ENDPOINT_TEMPLATES = {
|
|
2953
|
+
datadog: "https://http-intake.logs.{site}/api/v2/logs"
|
|
2954
|
+
};
|
|
2955
|
+
__name(resolvePresetEndpoint, "resolvePresetEndpoint");
|
|
2956
|
+
__name2(resolvePresetEndpoint, "resolvePresetEndpoint");
|
|
2957
|
+
LOG_DRAIN_QUOTAS = {
|
|
2958
|
+
team: {
|
|
2959
|
+
eventsPerDay: 1e6,
|
|
2960
|
+
bytesPerDay: 1 * 1024 ** 3
|
|
2961
|
+
},
|
|
2962
|
+
business: {
|
|
2963
|
+
eventsPerDay: 1e7,
|
|
2964
|
+
bytesPerDay: 10 * 1024 ** 3
|
|
2965
|
+
},
|
|
2966
|
+
enterprise: {
|
|
2967
|
+
eventsPerDay: Number.MAX_SAFE_INTEGER,
|
|
2968
|
+
bytesPerDay: Number.MAX_SAFE_INTEGER
|
|
2969
|
+
}
|
|
2970
|
+
};
|
|
2971
|
+
LOG_DRAIN_QUOTA_WARN_RATIO = 0.8;
|
|
2972
|
+
LOG_DRAIN_QUOTA_DROP_DEBUG_RATIO = 1;
|
|
2973
|
+
LOG_DRAIN_QUOTA_DROP_INFO_RATIO = 1.25;
|
|
2974
|
+
LOG_DRAIN_QUOTA_PAUSE_RATIO = 1.5;
|
|
2975
|
+
__name(nextLogDrainQuotaResetAt, "nextLogDrainQuotaResetAt");
|
|
2976
|
+
__name2(nextLogDrainQuotaResetAt, "nextLogDrainQuotaResetAt");
|
|
2977
|
+
__name(logDrainQuotaWindowExpired, "logDrainQuotaWindowExpired");
|
|
2978
|
+
__name2(logDrainQuotaWindowExpired, "logDrainQuotaWindowExpired");
|
|
2979
|
+
__name(logDrainQuotaRatio, "logDrainQuotaRatio");
|
|
2980
|
+
__name2(logDrainQuotaRatio, "logDrainQuotaRatio");
|
|
2981
|
+
__name(logDrainQuotaDegradationForRatio, "logDrainQuotaDegradationForRatio");
|
|
2982
|
+
__name2(logDrainQuotaDegradationForRatio, "logDrainQuotaDegradationForRatio");
|
|
2983
|
+
__name(logDrainQuotaDegradation, "logDrainQuotaDegradation");
|
|
2984
|
+
__name2(logDrainQuotaDegradation, "logDrainQuotaDegradation");
|
|
2985
|
+
__name(logDrainQuotaWarned, "logDrainQuotaWarned");
|
|
2986
|
+
__name2(logDrainQuotaWarned, "logDrainQuotaWarned");
|
|
2987
|
+
__name(logDrainQuotaDroppedSeverities, "logDrainQuotaDroppedSeverities");
|
|
2988
|
+
__name2(logDrainQuotaDroppedSeverities, "logDrainQuotaDroppedSeverities");
|
|
2989
|
+
LOG_CURSOR_MAX_LENGTH = 512;
|
|
2990
|
+
LOG_CURSOR_MAX_ID_LENGTH = 128;
|
|
2991
|
+
LOG_RELATIVE_TIME_PATTERN = /^(\d{1,9})([smhd])$/;
|
|
2992
|
+
LOG_ISO_TIME_PATTERN = /^\d{4}-\d{2}-\d{2}([Tt ]\d{2}:\d{2}(:\d{2}(\.\d{1,9})?)?([Zz]|[+-]\d{2}:?\d{2})?)?$/;
|
|
2993
|
+
RELATIVE_UNIT_MS = {
|
|
2994
|
+
s: 1e3,
|
|
2995
|
+
m: 6e4,
|
|
2996
|
+
h: 36e5,
|
|
2997
|
+
d: 864e5
|
|
2998
|
+
};
|
|
2999
|
+
__name(encodeLogCursor, "encodeLogCursor");
|
|
3000
|
+
__name2(encodeLogCursor, "encodeLogCursor");
|
|
3001
|
+
__name(decodeLogCursor, "decodeLogCursor");
|
|
3002
|
+
__name2(decodeLogCursor, "decodeLogCursor");
|
|
3003
|
+
__name(parseLogTimeBound, "parseLogTimeBound");
|
|
3004
|
+
__name2(parseLogTimeBound, "parseLogTimeBound");
|
|
2757
3005
|
CORE_DRAINING_CODE = "CORE_DRAINING";
|
|
2758
3006
|
CORE_DRAINING_DEFAULT_RETRY_MS = 1e3;
|
|
2759
3007
|
CORE_DRAINING_MAX_RETRY_MS = 5e3;
|
|
@@ -3520,6 +3768,16 @@ This text is who you are for this person. As you learn them, their name, their w
|
|
|
3520
3768
|
__name2(workflowOrgSlotKey, "workflowOrgSlotKey");
|
|
3521
3769
|
WORKFLOW_JOURNAL_PROTOCOL_VERSION = 1;
|
|
3522
3770
|
WORKFLOW_CONNECTION_KEY_RE = /^[a-z][a-z0-9_-]{0,63}$/;
|
|
3771
|
+
WORKFLOW_JOB_MODEL_SOURCE_LABELS = {
|
|
3772
|
+
stamp: "lease stamp",
|
|
3773
|
+
initData: "run input",
|
|
3774
|
+
default: "placeholder default",
|
|
3775
|
+
node: "node.model",
|
|
3776
|
+
env: "platform default",
|
|
3777
|
+
org: "org default"
|
|
3778
|
+
};
|
|
3779
|
+
__name(workflowJobModelSourceLabel, "workflowJobModelSourceLabel");
|
|
3780
|
+
__name2(workflowJobModelSourceLabel, "workflowJobModelSourceLabel");
|
|
3523
3781
|
__name(scheduledTimeKey, "scheduledTimeKey");
|
|
3524
3782
|
__name2(scheduledTimeKey, "scheduledTimeKey");
|
|
3525
3783
|
__name(scheduledWorkflowRunIdForTime, "scheduledWorkflowRunIdForTime");
|
|
@@ -3753,7 +4011,23 @@ This text is who you are for this person. As you learn them, their name, their w
|
|
|
3753
4011
|
* gated and nobody approved it, and conflating the two would make "who approved this run"
|
|
3754
4012
|
* unanswerable for every run of either kind (§H2 "Audit").
|
|
3755
4013
|
*/
|
|
3756
|
-
"workflow.run.autonomy_applied"
|
|
4014
|
+
"workflow.run.autonomy_applied",
|
|
4015
|
+
// --- run budget cap enforcement (Job-tier billing plan D4; BAC-677) ---
|
|
4016
|
+
/**
|
|
4017
|
+
* The audit twin of the `run.budget_exceeded` run event (WJB-B2a): the run overshot its
|
|
4018
|
+
* `budget.maxCredits` on its LAST step and completed anyway, `budget.exceeded: true`. The budget family
|
|
4019
|
+
* already mirrors run events here — `workflow.run.budget_parked` / `workflow.run.budget_raised` are the
|
|
4020
|
+
* twins of `run.budget_parked` / `run.budget_raised` — and an organisation reviewing what it was charged
|
|
4021
|
+
* needs the overshoot in the audit store beside the raise that preceded it, not only in the run's own
|
|
4022
|
+
* event stream.
|
|
4023
|
+
*
|
|
4024
|
+
* Declared with the run event rather than after it because the emitter port
|
|
4025
|
+
* (`WorkflowAuditPort.action`, typed `workflow.run.${string}`) does not check against this tuple: a name
|
|
4026
|
+
* that is NOT declared here is written to the audit store all the same and no compiler says so.
|
|
4027
|
+
* Declaring it is what makes the later emitter checkable. `workflow.run.budget_parked` is likewise
|
|
4028
|
+
* declared and not yet emitted.
|
|
4029
|
+
*/
|
|
4030
|
+
"workflow.run.budget_exceeded"
|
|
3757
4031
|
];
|
|
3758
4032
|
WORKFLOW_AUDIT_METADATA_MAX_BYTES = 4 * 1024;
|
|
3759
4033
|
__name(isWorkflowAuditEvent, "isWorkflowAuditEvent");
|
|
@@ -4763,10 +5037,10 @@ function parseModelTemplate(model) {
|
|
|
4763
5037
|
if (!looksLikeModelTemplate(model)) return {
|
|
4764
5038
|
kind: "static"
|
|
4765
5039
|
};
|
|
4766
|
-
const
|
|
4767
|
-
const m = WORKFLOW_MODEL_TEMPLATE_RE.exec(
|
|
5040
|
+
const trimmed2 = model.trim();
|
|
5041
|
+
const m = WORKFLOW_MODEL_TEMPLATE_RE.exec(trimmed2);
|
|
4768
5042
|
if (!m) {
|
|
4769
|
-
const inner = /^\$\{([^}]*)\}$/.exec(
|
|
5043
|
+
const inner = /^\$\{([^}]*)\}$/.exec(trimmed2)?.[1];
|
|
4770
5044
|
const root = inner?.split(/[.|]/, 1)[0];
|
|
4771
5045
|
const why = inner !== void 0 && root !== void 0 && root !== WORKFLOW_MODEL_TEMPLATE_ROOT ? `only the \`${WORKFLOW_MODEL_TEMPLATE_ROOT}\` root is allowed (got \`${root || "(empty)"}\`)` : inner !== void 0 && (inner === WORKFLOW_MODEL_TEMPLATE_ROOT || inner.startsWith(`${WORKFLOW_MODEL_TEMPLATE_ROOT}.`)) ? "the path after `initData.` is empty" : "the whole value must be exactly one placeholder \u2014 no prefix, suffix or second placeholder";
|
|
4772
5046
|
return {
|
|
@@ -4796,7 +5070,7 @@ function parseModelTemplate(model) {
|
|
|
4796
5070
|
return {
|
|
4797
5071
|
kind: "template",
|
|
4798
5072
|
template: {
|
|
4799
|
-
placeholder:
|
|
5073
|
+
placeholder: trimmed2,
|
|
4800
5074
|
path: path26,
|
|
4801
5075
|
default: dflt
|
|
4802
5076
|
}
|
|
@@ -4805,7 +5079,7 @@ function parseModelTemplate(model) {
|
|
|
4805
5079
|
return {
|
|
4806
5080
|
kind: "template",
|
|
4807
5081
|
template: {
|
|
4808
|
-
placeholder:
|
|
5082
|
+
placeholder: trimmed2,
|
|
4809
5083
|
path: path26
|
|
4810
5084
|
}
|
|
4811
5085
|
};
|
|
@@ -5458,9 +5732,9 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
5458
5732
|
const registry = opts.approvedModels;
|
|
5459
5733
|
if (registry === void 0) return;
|
|
5460
5734
|
if (registry === "unavailable") {
|
|
5461
|
-
const
|
|
5462
|
-
if (
|
|
5463
|
-
warn("model-unresolved", inContext(`model "${
|
|
5735
|
+
const trimmed2 = pin.trim();
|
|
5736
|
+
if (trimmed2 && !normalizeModelId(trimmed2, []).ok) {
|
|
5737
|
+
warn("model-unresolved", inContext(`model "${trimmed2}" could not be checked against the approved-model registry (unavailable at push) \u2014 it dispatches only if it resolves there (a provider/model registry code, or a bare id exactly one approved model carries)`), `${path26}.model`, id);
|
|
5464
5738
|
}
|
|
5465
5739
|
return;
|
|
5466
5740
|
}
|
|
@@ -7992,6 +8266,49 @@ function graphHasJobTierStep(envelopeOrGraph) {
|
|
|
7992
8266
|
const graph = Array.isArray(envelopeOrGraph) ? envelopeOrGraph : env.definition?.graph ?? [];
|
|
7993
8267
|
return Array.isArray(graph) && graph.some(entryHasJobTier);
|
|
7994
8268
|
}
|
|
8269
|
+
function jobTierSteps(envelopeOrGraph) {
|
|
8270
|
+
const out = [];
|
|
8271
|
+
if (!envelopeOrGraph || typeof envelopeOrGraph !== "object") return out;
|
|
8272
|
+
const env = envelopeOrGraph;
|
|
8273
|
+
const graph = Array.isArray(envelopeOrGraph) ? envelopeOrGraph : env.definition?.graph ?? [];
|
|
8274
|
+
if (!Array.isArray(graph)) return out;
|
|
8275
|
+
for (const entry of graph) collectJobTierSteps(entry, out);
|
|
8276
|
+
return out;
|
|
8277
|
+
}
|
|
8278
|
+
function jobTierStepIds(envelopeOrGraph) {
|
|
8279
|
+
return jobTierSteps(envelopeOrGraph).map((s) => s.stepId);
|
|
8280
|
+
}
|
|
8281
|
+
function collectJobTierSteps(entry, out) {
|
|
8282
|
+
const n2 = armEntry2(entry);
|
|
8283
|
+
if (!n2 || typeof n2 !== "object") return;
|
|
8284
|
+
const node = n2;
|
|
8285
|
+
const ws = node.workspace;
|
|
8286
|
+
if (node.tier === "job" || ws !== void 0 && ws !== "inherit") {
|
|
8287
|
+
const stepId = typeof node.id === "string" && node.id ? node.id : "(unnamed)";
|
|
8288
|
+
const model = typeof node.model === "string" && node.model.trim() ? node.model.trim() : void 0;
|
|
8289
|
+
out.push(model === void 0 ? {
|
|
8290
|
+
stepId
|
|
8291
|
+
} : {
|
|
8292
|
+
stepId,
|
|
8293
|
+
model
|
|
8294
|
+
});
|
|
8295
|
+
}
|
|
8296
|
+
switch (node.type) {
|
|
8297
|
+
case "parallel":
|
|
8298
|
+
if (Array.isArray(node.steps)) for (const s of node.steps) collectJobTierSteps(s, out);
|
|
8299
|
+
return;
|
|
8300
|
+
case "conditional":
|
|
8301
|
+
if (Array.isArray(node.steps)) for (const s of node.steps) collectJobTierSteps(s, out);
|
|
8302
|
+
if (node.otherwise !== void 0) collectJobTierSteps(node.otherwise, out);
|
|
8303
|
+
return;
|
|
8304
|
+
case "foreach":
|
|
8305
|
+
case "loop":
|
|
8306
|
+
collectJobTierSteps(node.step, out);
|
|
8307
|
+
return;
|
|
8308
|
+
default:
|
|
8309
|
+
return;
|
|
8310
|
+
}
|
|
8311
|
+
}
|
|
7995
8312
|
var __defProp4, __name4, WorkflowTemplateError, TEMPLATE_PLACEHOLDER, TEMPLATE_NAMESPACES, MAP_DESCRIPTOR_KEYS, MAP_MEMBER_MALFORMED_CODE, fromInit, fromStep, value, template, fromRequest, rows, fromKnowledge, SideEffectsSchema, JobResourcesSchema, WORKFLOW_MODEL_TEMPLATE_ROOT, WORKFLOW_MODEL_TEMPLATE_RE, PATH_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, 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_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, WORKFLOW_INLINE_RUN_TAG, RUN_ERROR_ISSUES_MAX, 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, WORKFLOW_SCHEDULE_TYPES, WORKFLOW_SCHEDULE_SHAPE_ISSUE, WORKFLOW_SCHEDULE_SHAPES_HINT, WORKFLOW_SCHEDULE_RUN_AS, isObject, WORKFLOW_ENV_OVERLAY_MAX_KEYS, WORKFLOW_ENV_OVERLAY_MAX_VALUE_BYTES, WORKFLOW_ENV_TEMPLATE_SECRET_KEY_RE, isEnvRef, looksLikeEmbeddedJson, ZERO, isRecord2;
|
|
7996
8313
|
var init_dist2 = __esm({
|
|
7997
8314
|
"../workflow-graph/dist/index.mjs"() {
|
|
@@ -8796,6 +9113,12 @@ var init_dist2 = __esm({
|
|
|
8796
9113
|
__name4(entryHasJobTier, "entryHasJobTier");
|
|
8797
9114
|
__name(graphHasJobTierStep, "graphHasJobTierStep");
|
|
8798
9115
|
__name4(graphHasJobTierStep, "graphHasJobTierStep");
|
|
9116
|
+
__name(jobTierSteps, "jobTierSteps");
|
|
9117
|
+
__name4(jobTierSteps, "jobTierSteps");
|
|
9118
|
+
__name(jobTierStepIds, "jobTierStepIds");
|
|
9119
|
+
__name4(jobTierStepIds, "jobTierStepIds");
|
|
9120
|
+
__name(collectJobTierSteps, "collectJobTierSteps");
|
|
9121
|
+
__name4(collectJobTierSteps, "collectJobTierSteps");
|
|
8799
9122
|
}
|
|
8800
9123
|
});
|
|
8801
9124
|
|
|
@@ -12376,8 +12699,8 @@ function ensureGitignored(rootDir, entry, afterEntry) {
|
|
|
12376
12699
|
return;
|
|
12377
12700
|
}
|
|
12378
12701
|
}
|
|
12379
|
-
const
|
|
12380
|
-
fs2.writeFileSync(gitignorePath,
|
|
12702
|
+
const trimmed2 = content.endsWith("\n") ? content : content + "\n";
|
|
12703
|
+
fs2.writeFileSync(gitignorePath, trimmed2 + entry + "\n");
|
|
12381
12704
|
}
|
|
12382
12705
|
function hasEnvFile() {
|
|
12383
12706
|
return fs2.existsSync(path2.join(process.cwd(), ".env"));
|
|
@@ -27776,6 +28099,7 @@ var init_mcp_server_handler = __esm({
|
|
|
27776
28099
|
|
|
27777
28100
|
// src/index.ts
|
|
27778
28101
|
import { Command } from "commander";
|
|
28102
|
+
import chalk5 from "chalk";
|
|
27779
28103
|
|
|
27780
28104
|
// src/cli/parse-agent-version.ts
|
|
27781
28105
|
import { InvalidArgumentError } from "commander";
|
|
@@ -29658,8 +29982,8 @@ var PostProcessorApi = class extends HttpClient {
|
|
|
29658
29982
|
// src/utils/sync-fetch.ts
|
|
29659
29983
|
init_developer_api_service();
|
|
29660
29984
|
init_mcp_server_handler();
|
|
29661
|
-
function normalizeForComparison(
|
|
29662
|
-
return
|
|
29985
|
+
function normalizeForComparison(str2) {
|
|
29986
|
+
return str2.trim().replace(/\\'/g, "'").replace(/\\"/g, '"').replace(/\\\\/g, "\\").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
29663
29987
|
}
|
|
29664
29988
|
__name(normalizeForComparison, "normalizeForComparison");
|
|
29665
29989
|
function canonicalizeForm(value3) {
|
|
@@ -31504,12 +31828,30 @@ __name(buildLogsCommand, "buildLogsCommand");
|
|
|
31504
31828
|
// src/utils/sync-display.ts
|
|
31505
31829
|
init_dist();
|
|
31506
31830
|
import { diffLines } from "diff";
|
|
31831
|
+
|
|
31832
|
+
// src/utils/color.ts
|
|
31833
|
+
function noColorEnabled(env = process.env) {
|
|
31834
|
+
return !!env.NO_COLOR;
|
|
31835
|
+
}
|
|
31836
|
+
__name(noColorEnabled, "noColorEnabled");
|
|
31837
|
+
function colorize(ansiCode, text) {
|
|
31838
|
+
if (noColorEnabled()) return text;
|
|
31839
|
+
return `${ansiCode}${text}\x1B[0m`;
|
|
31840
|
+
}
|
|
31841
|
+
__name(colorize, "colorize");
|
|
31842
|
+
function configureChalkColor(chalkLike) {
|
|
31843
|
+
if (noColorEnabled()) {
|
|
31844
|
+
chalkLike.level = 0;
|
|
31845
|
+
}
|
|
31846
|
+
}
|
|
31847
|
+
__name(configureChalkColor, "configureChalkColor");
|
|
31848
|
+
|
|
31849
|
+
// src/utils/sync-display.ts
|
|
31507
31850
|
var colors = {
|
|
31508
|
-
red: "\x1B[31m",
|
|
31509
|
-
green: "\x1B[32m",
|
|
31510
|
-
gray: "\x1B[90m",
|
|
31511
|
-
|
|
31512
|
-
bold: "\x1B[1m"
|
|
31851
|
+
red: /* @__PURE__ */ __name((s) => colorize("\x1B[31m", s), "red"),
|
|
31852
|
+
green: /* @__PURE__ */ __name((s) => colorize("\x1B[32m", s), "green"),
|
|
31853
|
+
gray: /* @__PURE__ */ __name((s) => colorize("\x1B[90m", s), "gray"),
|
|
31854
|
+
bold: /* @__PURE__ */ __name((s) => colorize("\x1B[1m", s), "bold")
|
|
31513
31855
|
};
|
|
31514
31856
|
var primitiveTypeLabels = {
|
|
31515
31857
|
skill: "SKILLS",
|
|
@@ -31521,31 +31863,31 @@ var primitiveTypeLabels = {
|
|
|
31521
31863
|
};
|
|
31522
31864
|
function showColoredDiff(oldText, newText, oldLabel = "Server", newLabel = "Local") {
|
|
31523
31865
|
if (!oldText && !newText) {
|
|
31524
|
-
console.log(colors.gray
|
|
31866
|
+
console.log(colors.gray("(both empty)"));
|
|
31525
31867
|
return;
|
|
31526
31868
|
}
|
|
31527
31869
|
if (!oldText) {
|
|
31528
|
-
console.log(colors.green
|
|
31870
|
+
console.log(colors.green(`+ (${newLabel} only - no ${oldLabel} content)`));
|
|
31529
31871
|
return;
|
|
31530
31872
|
}
|
|
31531
31873
|
if (!newText) {
|
|
31532
|
-
console.log(colors.red
|
|
31874
|
+
console.log(colors.red(`- (${oldLabel} only - no ${newLabel} content)`));
|
|
31533
31875
|
return;
|
|
31534
31876
|
}
|
|
31535
31877
|
const diff = diffLines(oldText, newText);
|
|
31536
31878
|
diff.forEach((part) => {
|
|
31537
31879
|
if (part.added) {
|
|
31538
|
-
part.value.split("\n").filter((l) => l).forEach((line) => console.log(colors.green
|
|
31880
|
+
part.value.split("\n").filter((l) => l).forEach((line) => console.log(colors.green("+ " + line)));
|
|
31539
31881
|
} else if (part.removed) {
|
|
31540
|
-
part.value.split("\n").filter((l) => l).forEach((line) => console.log(colors.red
|
|
31882
|
+
part.value.split("\n").filter((l) => l).forEach((line) => console.log(colors.red("- " + line)));
|
|
31541
31883
|
} else {
|
|
31542
31884
|
const lines = part.value.split("\n").filter((l) => l);
|
|
31543
31885
|
if (lines.length <= 6) {
|
|
31544
|
-
lines.forEach((line) => console.log(colors.gray
|
|
31886
|
+
lines.forEach((line) => console.log(colors.gray(" " + line)));
|
|
31545
31887
|
} else {
|
|
31546
|
-
lines.slice(0, 3).forEach((line) => console.log(colors.gray
|
|
31547
|
-
console.log(colors.gray
|
|
31548
|
-
lines.slice(-3).forEach((line) => console.log(colors.gray
|
|
31888
|
+
lines.slice(0, 3).forEach((line) => console.log(colors.gray(" " + line)));
|
|
31889
|
+
console.log(colors.gray(` ... (${lines.length - 6} unchanged lines) ...`));
|
|
31890
|
+
lines.slice(-3).forEach((line) => console.log(colors.gray(" " + line)));
|
|
31549
31891
|
}
|
|
31550
31892
|
}
|
|
31551
31893
|
});
|
|
@@ -31553,8 +31895,8 @@ function showColoredDiff(oldText, newText, oldLabel = "Server", newLabel = "Loca
|
|
|
31553
31895
|
__name(showColoredDiff, "showColoredDiff");
|
|
31554
31896
|
function showPersonaDiff(serverPersona, localPersona) {
|
|
31555
31897
|
console.log("\n" + "=".repeat(60));
|
|
31556
|
-
console.log(colors.bold
|
|
31557
|
-
console.log(colors.red
|
|
31898
|
+
console.log(colors.bold("PERSONA DIFF"));
|
|
31899
|
+
console.log(colors.red("- Server (deployed)") + " " + colors.green("+ Local (code)"));
|
|
31558
31900
|
console.log("=".repeat(60) + "\n");
|
|
31559
31901
|
showColoredDiff(flattenPersonaTextAll(serverPersona), flattenPersonaTextAll(localPersona), "Server", "Local");
|
|
31560
31902
|
console.log("\n" + "=".repeat(60) + "\n");
|
|
@@ -31562,19 +31904,19 @@ function showPersonaDiff(serverPersona, localPersona) {
|
|
|
31562
31904
|
__name(showPersonaDiff, "showPersonaDiff");
|
|
31563
31905
|
function showNameDiff(serverName, localName) {
|
|
31564
31906
|
console.log("\n" + "=".repeat(60));
|
|
31565
|
-
console.log(colors.bold
|
|
31907
|
+
console.log(colors.bold("NAME DIFF"));
|
|
31566
31908
|
console.log("=".repeat(60));
|
|
31567
|
-
console.log(colors.red
|
|
31568
|
-
console.log(colors.green
|
|
31909
|
+
console.log(colors.red(`- Server: "${serverName || "(none)"}"`));
|
|
31910
|
+
console.log(colors.green(`+ Local: "${localName || "(none)"}"`));
|
|
31569
31911
|
console.log("=".repeat(60) + "\n");
|
|
31570
31912
|
}
|
|
31571
31913
|
__name(showNameDiff, "showNameDiff");
|
|
31572
31914
|
function showModelDiff(serverModel, localModel) {
|
|
31573
31915
|
console.log("\n" + "=".repeat(60));
|
|
31574
|
-
console.log(colors.bold
|
|
31916
|
+
console.log(colors.bold("MODEL DIFF"));
|
|
31575
31917
|
console.log("=".repeat(60));
|
|
31576
|
-
console.log(colors.red
|
|
31577
|
-
console.log(colors.green
|
|
31918
|
+
console.log(colors.red(`- Server: "${serverModel || "(none)"}"`));
|
|
31919
|
+
console.log(colors.green(`+ Local: "${localModel || "(none)"}"`));
|
|
31578
31920
|
console.log("=".repeat(60) + "\n");
|
|
31579
31921
|
}
|
|
31580
31922
|
__name(showModelDiff, "showModelDiff");
|
|
@@ -31593,17 +31935,17 @@ function showPrimitiveDrift(items, backupAvailable) {
|
|
|
31593
31935
|
}
|
|
31594
31936
|
for (const [type, groupItems] of grouped) {
|
|
31595
31937
|
const label2 = primitiveTypeLabels[type] ?? type.toUpperCase();
|
|
31596
|
-
console.log("\n" + colors.bold
|
|
31938
|
+
console.log("\n" + colors.bold(`\u2501\u2501\u2501 ${label2} \u2501\u2501\u2501`));
|
|
31597
31939
|
for (const item of groupItems) {
|
|
31598
|
-
console.log("\n " + colors.bold
|
|
31599
|
-
const localDisplay = item.localVersion ? `v${item.localVersion}` : colors.gray
|
|
31940
|
+
console.log("\n " + colors.bold(item.name));
|
|
31941
|
+
const localDisplay = item.localVersion ? `v${item.localVersion}` : colors.gray("(not found)");
|
|
31600
31942
|
console.log(` Local: ${localDisplay}`);
|
|
31601
|
-
const serverDisplay = item.serverVersion ? `v${item.serverVersion}` : colors.gray
|
|
31943
|
+
const serverDisplay = item.serverVersion ? `v${item.serverVersion}` : colors.gray("(not found)");
|
|
31602
31944
|
console.log(` Server: ${serverDisplay}`);
|
|
31603
31945
|
}
|
|
31604
31946
|
}
|
|
31605
31947
|
if (backupAvailable !== void 0) {
|
|
31606
|
-
const backupDisplay = backupAvailable ? colors.green
|
|
31948
|
+
const backupDisplay = backupAvailable ? colors.green("available") : colors.red("not available");
|
|
31607
31949
|
console.log(`
|
|
31608
31950
|
Backup: ${backupDisplay}`);
|
|
31609
31951
|
}
|
|
@@ -31625,14 +31967,14 @@ function showPrimitiveDriftSummary(items) {
|
|
|
31625
31967
|
versionInfo = `local only${vSuffix(item.localVersion)}`;
|
|
31626
31968
|
}
|
|
31627
31969
|
const paddedLabel = label2.padEnd(16);
|
|
31628
|
-
console.log(` ${colors.red
|
|
31970
|
+
console.log(` ${colors.red(paddedLabel)} ${item.name} (${versionInfo})`);
|
|
31629
31971
|
}
|
|
31630
31972
|
}
|
|
31631
31973
|
__name(showPrimitiveDriftSummary, "showPrimitiveDriftSummary");
|
|
31632
31974
|
function showGovernanceDiff(serverGovernance, localGovernance) {
|
|
31633
31975
|
console.log("\n" + "=".repeat(60));
|
|
31634
|
-
console.log(colors.bold
|
|
31635
|
-
console.log(colors.red
|
|
31976
|
+
console.log(colors.bold("GOVERNANCE DIFF"));
|
|
31977
|
+
console.log(colors.red("- Server (deployed)") + " " + colors.green("+ Local (code)"));
|
|
31636
31978
|
console.log("=".repeat(60) + "\n");
|
|
31637
31979
|
showColoredDiff(JSON.stringify(serverGovernance, null, 2) || "(none)", JSON.stringify(localGovernance, null, 2) || "(none)", "Server", "Local");
|
|
31638
31980
|
console.log("\n" + "=".repeat(60) + "\n");
|
|
@@ -36930,6 +37272,9 @@ init_artifact_loader();
|
|
|
36930
37272
|
init_types();
|
|
36931
37273
|
init_analytics();
|
|
36932
37274
|
|
|
37275
|
+
// src/utils/aliases.ts
|
|
37276
|
+
init_dist();
|
|
37277
|
+
|
|
36933
37278
|
// src/utils/suggest.ts
|
|
36934
37279
|
function levenshtein(a, b) {
|
|
36935
37280
|
const m = a.length, n2 = b.length;
|
|
@@ -37062,21 +37407,58 @@ var ALIAS_MAP = {
|
|
|
37062
37407
|
everything: "all"
|
|
37063
37408
|
})
|
|
37064
37409
|
},
|
|
37410
|
+
// PRO-1798 (log drains) — `lua drains <action>`; the canonical list is §B.14's verb
|
|
37411
|
+
// table. `rotate-secret` keeps its hyphen: it is the route name too.
|
|
37412
|
+
"drains.action": {
|
|
37413
|
+
canonical: [
|
|
37414
|
+
"list",
|
|
37415
|
+
"status",
|
|
37416
|
+
"deliveries",
|
|
37417
|
+
"create",
|
|
37418
|
+
"update",
|
|
37419
|
+
"delete",
|
|
37420
|
+
"test",
|
|
37421
|
+
"verify",
|
|
37422
|
+
"pause",
|
|
37423
|
+
"resume",
|
|
37424
|
+
"rotate-secret"
|
|
37425
|
+
],
|
|
37426
|
+
aliases: lowerKeys({
|
|
37427
|
+
ls: "list",
|
|
37428
|
+
view: "list",
|
|
37429
|
+
show: "status",
|
|
37430
|
+
info: "status",
|
|
37431
|
+
health: "status",
|
|
37432
|
+
history: "deliveries",
|
|
37433
|
+
attempts: "deliveries",
|
|
37434
|
+
deliver: "deliveries",
|
|
37435
|
+
new: "create",
|
|
37436
|
+
add: "create",
|
|
37437
|
+
edit: "update",
|
|
37438
|
+
patch: "update",
|
|
37439
|
+
rm: "delete",
|
|
37440
|
+
remove: "delete",
|
|
37441
|
+
del: "delete",
|
|
37442
|
+
send: "test",
|
|
37443
|
+
check: "verify",
|
|
37444
|
+
off: "pause",
|
|
37445
|
+
disable: "pause",
|
|
37446
|
+
on: "resume",
|
|
37447
|
+
enable: "resume",
|
|
37448
|
+
rotate: "rotate-secret",
|
|
37449
|
+
rotatesecret: "rotate-secret",
|
|
37450
|
+
"rotate-key": "rotate-secret"
|
|
37451
|
+
})
|
|
37452
|
+
},
|
|
37065
37453
|
"logs.type": {
|
|
37454
|
+
// PRO-1838 (A5) / design D-17: DERIVED from the canonical constant, never hand-listed.
|
|
37455
|
+
// `logs.ts` already derives its own enum from `AGENT_LOG_SOURCES`, but THIS list is what
|
|
37456
|
+
// actually rejects `--type` — hand-maintaining it left the five platform sources
|
|
37457
|
+
// (trigger, model-resolver, workflow, workflow-step, workflow-script) unreachable.
|
|
37458
|
+
// `getCanonicalValues` sorts, so the order here is irrelevant to the `Valid values` hint.
|
|
37459
|
+
// `all` and `calls` are handled by the caller before the check and are not members.
|
|
37066
37460
|
canonical: [
|
|
37067
|
-
|
|
37068
|
-
"job",
|
|
37069
|
-
"webhook",
|
|
37070
|
-
"preprocessor",
|
|
37071
|
-
"postprocessor",
|
|
37072
|
-
"user_message",
|
|
37073
|
-
"agent_response",
|
|
37074
|
-
"agent_error",
|
|
37075
|
-
"mcp",
|
|
37076
|
-
"runtime",
|
|
37077
|
-
"rag",
|
|
37078
|
-
"device",
|
|
37079
|
-
"device-trigger"
|
|
37461
|
+
...AGENT_LOG_SOURCES
|
|
37080
37462
|
],
|
|
37081
37463
|
aliases: lowerKeys({
|
|
37082
37464
|
skills: "skill",
|
|
@@ -40275,8 +40657,8 @@ async function gitUserConfigured(cwd) {
|
|
|
40275
40657
|
cwd
|
|
40276
40658
|
});
|
|
40277
40659
|
if (code !== 0) return void 0;
|
|
40278
|
-
const
|
|
40279
|
-
return
|
|
40660
|
+
const trimmed2 = stdout.trim();
|
|
40661
|
+
return trimmed2.length > 0 ? trimmed2 : void 0;
|
|
40280
40662
|
} catch {
|
|
40281
40663
|
return void 0;
|
|
40282
40664
|
}
|
|
@@ -40301,8 +40683,8 @@ async function getRemoteOriginUrl(cwd) {
|
|
|
40301
40683
|
cwd
|
|
40302
40684
|
});
|
|
40303
40685
|
if (code !== 0) return null;
|
|
40304
|
-
const
|
|
40305
|
-
return
|
|
40686
|
+
const trimmed2 = stdout.trim();
|
|
40687
|
+
return trimmed2.length > 0 ? trimmed2 : null;
|
|
40306
40688
|
} catch {
|
|
40307
40689
|
return null;
|
|
40308
40690
|
}
|
|
@@ -40673,9 +41055,9 @@ async function readCurrentBranch(cwd) {
|
|
|
40673
41055
|
cwd
|
|
40674
41056
|
});
|
|
40675
41057
|
if (res.code !== 0) return null;
|
|
40676
|
-
const
|
|
40677
|
-
if (!
|
|
40678
|
-
return
|
|
41058
|
+
const trimmed2 = res.stdout.trim();
|
|
41059
|
+
if (!trimmed2 || trimmed2 === "HEAD") return null;
|
|
41060
|
+
return trimmed2;
|
|
40679
41061
|
}
|
|
40680
41062
|
__name(readCurrentBranch, "readCurrentBranch");
|
|
40681
41063
|
|
|
@@ -40793,8 +41175,8 @@ __name(reportFailure, "reportFailure");
|
|
|
40793
41175
|
var GIT_MESSAGES = {
|
|
40794
41176
|
pushStaged: "lua: push staged code",
|
|
40795
41177
|
createVersion: /* @__PURE__ */ __name((version, message) => {
|
|
40796
|
-
const
|
|
40797
|
-
return
|
|
41178
|
+
const trimmed2 = message?.trim();
|
|
41179
|
+
return trimmed2 ? `lua: create version v${version}: ${trimmed2}` : `lua: create version v${version}`;
|
|
40798
41180
|
}, "createVersion"),
|
|
40799
41181
|
promote: /* @__PURE__ */ __name((version) => `lua: promote v${version} to production`, "promote"),
|
|
40800
41182
|
delete: /* @__PURE__ */ __name((version) => `lua: delete version v${version}`, "delete"),
|
|
@@ -43411,17 +43793,22 @@ var LogsApi = class extends HttpClient {
|
|
|
43411
43793
|
}
|
|
43412
43794
|
/**
|
|
43413
43795
|
* Retrieves logs for an agent
|
|
43796
|
+
*
|
|
43797
|
+
* The signature is unchanged from before A4 — `filters` simply gained four optional
|
|
43798
|
+
* keys. When `filters.cursor` is set, `page` is NOT sent: the route refuses the two
|
|
43799
|
+
* together (docs `reference/rest/log-drains.mdx`, "Cannot be combined with `page`").
|
|
43800
|
+
*
|
|
43414
43801
|
* @param agentId - The ID of the agent
|
|
43415
43802
|
* @param limit - Number of logs per page (default: 20)
|
|
43416
|
-
* @param page - Page number (default: 1)
|
|
43803
|
+
* @param page - Page number (default: 1); ignored when `filters.cursor` is set
|
|
43417
43804
|
* @param filters - Optional filters to narrow log results
|
|
43418
|
-
* @returns Promise resolving to an ApiResponse containing logs and pagination
|
|
43805
|
+
* @returns Promise resolving to an ApiResponse containing logs, nextCursor and pagination
|
|
43419
43806
|
*/
|
|
43420
43807
|
async getAgentLogs(agentId, limit, page, filters = {}) {
|
|
43421
43808
|
const queryParams = new URLSearchParams({
|
|
43422
|
-
limit: limit.toString()
|
|
43423
|
-
page: page.toString()
|
|
43809
|
+
limit: limit.toString()
|
|
43424
43810
|
});
|
|
43811
|
+
if (!filters.cursor) queryParams.append("page", page.toString());
|
|
43425
43812
|
if (filters.logSource) queryParams.append("logSource", filters.logSource);
|
|
43426
43813
|
if (filters.primitiveId) queryParams.append("primitiveId", filters.primitiveId);
|
|
43427
43814
|
if (filters.primitiveName) queryParams.append("primitiveName", filters.primitiveName);
|
|
@@ -43429,6 +43816,10 @@ var LogsApi = class extends HttpClient {
|
|
|
43429
43816
|
if (filters.toolName) queryParams.append("toolName", filters.toolName);
|
|
43430
43817
|
if (filters.logType) queryParams.append("logType", filters.logType);
|
|
43431
43818
|
if (filters.userId) queryParams.append("userId", filters.userId);
|
|
43819
|
+
if (filters.since) queryParams.append("since", filters.since);
|
|
43820
|
+
if (filters.until) queryParams.append("until", filters.until);
|
|
43821
|
+
if (filters.environment) queryParams.append("environment", filters.environment);
|
|
43822
|
+
if (filters.cursor) queryParams.append("cursor", filters.cursor);
|
|
43432
43823
|
return this.httpGet(`/developer/agents/${agentId}/logs?${queryParams.toString()}`, {});
|
|
43433
43824
|
}
|
|
43434
43825
|
};
|
|
@@ -43729,14 +44120,14 @@ async function startChatLoop(chatEnv, probeWindow) {
|
|
|
43729
44120
|
});
|
|
43730
44121
|
rl.prompt();
|
|
43731
44122
|
rl.on("line", async (input) => {
|
|
43732
|
-
const
|
|
43733
|
-
if (!
|
|
44123
|
+
const trimmed2 = input.trim();
|
|
44124
|
+
if (!trimmed2) {
|
|
43734
44125
|
rl.prompt();
|
|
43735
44126
|
return;
|
|
43736
44127
|
}
|
|
43737
44128
|
let messages;
|
|
43738
44129
|
try {
|
|
43739
|
-
messages = await parseMessageWithAttachments(
|
|
44130
|
+
messages = await parseMessageWithAttachments(trimmed2);
|
|
43740
44131
|
} catch (error) {
|
|
43741
44132
|
console.error(`
|
|
43742
44133
|
\u274C ${error instanceof Error ? error.message : "Failed to process attachments"}
|
|
@@ -46554,8 +46945,8 @@ async function promptAreaCode() {
|
|
|
46554
46945
|
default: ""
|
|
46555
46946
|
}
|
|
46556
46947
|
]);
|
|
46557
|
-
const
|
|
46558
|
-
return
|
|
46948
|
+
const trimmed2 = pattern.trim();
|
|
46949
|
+
return trimmed2.length > 0 ? trimmed2 : void 0;
|
|
46559
46950
|
}
|
|
46560
46951
|
__name(promptAreaCode, "promptAreaCode");
|
|
46561
46952
|
function smsLabel(transportOrUndefined) {
|
|
@@ -47500,6 +47891,7 @@ var CallMetricsApi = class extends HttpClient {
|
|
|
47500
47891
|
|
|
47501
47892
|
// src/commands/logs.ts
|
|
47502
47893
|
init_cli_error();
|
|
47894
|
+
init_dist();
|
|
47503
47895
|
var ALL_VALID_SOURCES = AGENT_LOG_SOURCES;
|
|
47504
47896
|
var ENTITY_SOURCES = /* @__PURE__ */ new Set([
|
|
47505
47897
|
"skill",
|
|
@@ -47510,19 +47902,35 @@ var ENTITY_SOURCES = /* @__PURE__ */ new Set([
|
|
|
47510
47902
|
"device"
|
|
47511
47903
|
]);
|
|
47512
47904
|
var NON_ENTITY_SOURCES = new Set(ALL_VALID_SOURCES.filter((s) => !ENTITY_SOURCES.has(s)));
|
|
47905
|
+
var FOLLOW_POLL_MS = 2e3;
|
|
47906
|
+
var FOLLOW_POLL_JITTER_MS = 500;
|
|
47907
|
+
var FOLLOW_BACKOFF_MIN_MS = 1e3;
|
|
47908
|
+
var FOLLOW_BACKOFF_MAX_MS = 3e4;
|
|
47909
|
+
var FOLLOW_PAGE_CAP = 10;
|
|
47910
|
+
var RELATIVE_WINDOW = LOG_RELATIVE_TIME_PATTERN;
|
|
47911
|
+
var ISO_TIME_SHAPE = LOG_ISO_TIME_PATTERN;
|
|
47513
47912
|
async function logsCommand(cmdObj) {
|
|
47514
47913
|
return withErrorHandling(async () => {
|
|
47914
|
+
const pageGiven = cmdObj?.page !== void 0 && cmdObj?.page !== null && cmdObj?.page !== "";
|
|
47515
47915
|
const options = {
|
|
47516
47916
|
type: cmdObj?.type || null,
|
|
47517
47917
|
name: cmdObj?.name || null,
|
|
47518
47918
|
limit: cmdObj?.limit ? parseInt(cmdObj.limit, 10) : 20,
|
|
47519
|
-
page:
|
|
47919
|
+
page: pageGiven ? parseInt(cmdObj.page, 10) : 1,
|
|
47920
|
+
pageGiven,
|
|
47520
47921
|
json: cmdObj?.json || false,
|
|
47521
47922
|
userId: cmdObj?.userId || null,
|
|
47522
47923
|
agentId: cmdObj?.agentId || null,
|
|
47523
47924
|
direction: cmdObj?.direction || null,
|
|
47524
|
-
status: cmdObj?.status || null
|
|
47925
|
+
status: cmdObj?.status || null,
|
|
47926
|
+
since: cmdObj?.since ? parseWindowBound("--since", String(cmdObj.since)) : void 0,
|
|
47927
|
+
until: cmdObj?.until ? parseWindowBound("--until", String(cmdObj.until)) : void 0,
|
|
47928
|
+
follow: cmdObj?.follow || false,
|
|
47929
|
+
environment: cmdObj?.environment ? parseEnvironment(String(cmdObj.environment)) : void 0
|
|
47525
47930
|
};
|
|
47931
|
+
if (options.follow && options.pageGiven) {
|
|
47932
|
+
throw CliError.usage("lua: --follow cannot be combined with --page.", "Drop --page: --follow starts from --since (or the newest page) and keeps going.");
|
|
47933
|
+
}
|
|
47526
47934
|
const { agentId: configAgentId, apiKey } = await initializeCommand();
|
|
47527
47935
|
const effectiveAgentId = options.agentId || configAgentId;
|
|
47528
47936
|
if (options.type === "calls") {
|
|
@@ -47537,7 +47945,18 @@ async function logsCommand(cmdObj) {
|
|
|
47537
47945
|
return;
|
|
47538
47946
|
}
|
|
47539
47947
|
const logsApi = new LogsApi(BASE_URLS.API, apiKey);
|
|
47540
|
-
const hasNonInteractiveFlags = options.type || options.name || options.json || options.userId;
|
|
47948
|
+
const hasNonInteractiveFlags = Boolean(options.type || options.name || options.json || options.userId || options.since || options.until || options.environment || options.follow);
|
|
47949
|
+
trackEvent("cli_logs_action", {
|
|
47950
|
+
filter_type: options.type || null,
|
|
47951
|
+
json_output: options.json || false,
|
|
47952
|
+
non_interactive: hasNonInteractiveFlags,
|
|
47953
|
+
page_requested: options.page || 1,
|
|
47954
|
+
agent_id_override: !!options.agentId,
|
|
47955
|
+
follow: !!options.follow,
|
|
47956
|
+
has_since: !!options.since,
|
|
47957
|
+
has_until: !!options.until,
|
|
47958
|
+
environment: options.environment || null
|
|
47959
|
+
});
|
|
47541
47960
|
if (hasNonInteractiveFlags) {
|
|
47542
47961
|
await nonInteractiveLogs(logsApi, effectiveAgentId, apiKey, options);
|
|
47543
47962
|
} else {
|
|
@@ -47545,13 +47964,6 @@ async function logsCommand(cmdObj) {
|
|
|
47545
47964
|
`);
|
|
47546
47965
|
await interactiveLogs(logsApi, effectiveAgentId, apiKey);
|
|
47547
47966
|
}
|
|
47548
|
-
trackEvent("cli_logs_action", {
|
|
47549
|
-
filter_type: options.type || null,
|
|
47550
|
-
json_output: options.json || false,
|
|
47551
|
-
non_interactive: hasNonInteractiveFlags,
|
|
47552
|
-
page_requested: options.page || 1,
|
|
47553
|
-
agent_id_override: !!options.agentId
|
|
47554
|
-
});
|
|
47555
47967
|
}, "logs viewing");
|
|
47556
47968
|
}
|
|
47557
47969
|
__name(logsCommand, "logsCommand");
|
|
@@ -47603,7 +48015,7 @@ function renderLogEntry(log, isLast) {
|
|
|
47603
48015
|
const logSource = log.metadata?.logSource;
|
|
47604
48016
|
const primitiveId = log.metadata?.primitiveId;
|
|
47605
48017
|
const primitiveName = log.metadata?.primitiveName;
|
|
47606
|
-
const { toolName, channel, userId } = log.metadata;
|
|
48018
|
+
const { toolName, channel, userId, environment, agentVersion } = log.metadata;
|
|
47607
48019
|
const icon = getLogIcon(log.subType, logSource);
|
|
47608
48020
|
const color = getLogColor(log.subType, logSource);
|
|
47609
48021
|
console.log(color(`${icon} [${timestamp}] ${log.subType.toUpperCase()}`));
|
|
@@ -47626,6 +48038,12 @@ function renderLogEntry(log, isLast) {
|
|
|
47626
48038
|
console.log(chalk2.gray(` Tool Name: ${toolName}`));
|
|
47627
48039
|
}
|
|
47628
48040
|
}
|
|
48041
|
+
if (environment) {
|
|
48042
|
+
console.log(chalk2.gray(` Env: ${environment}`));
|
|
48043
|
+
}
|
|
48044
|
+
if (agentVersion) {
|
|
48045
|
+
console.log(chalk2.gray(` Version: ${agentVersion}`));
|
|
48046
|
+
}
|
|
47629
48047
|
if (log.duration !== void 0) {
|
|
47630
48048
|
console.log(chalk2.gray(` Duration: ${log.duration}ms`));
|
|
47631
48049
|
}
|
|
@@ -47635,6 +48053,13 @@ function renderLogEntry(log, isLast) {
|
|
|
47635
48053
|
}
|
|
47636
48054
|
}
|
|
47637
48055
|
__name(renderLogEntry, "renderLogEntry");
|
|
48056
|
+
function formatPageHeader(pagination) {
|
|
48057
|
+
if (pagination?.totalCountExact === false) {
|
|
48058
|
+
return `Page ${pagination.currentPage} (${pagination.totalCount}+ total logs \u2014 count capped; page with --json nextCursor)`;
|
|
48059
|
+
}
|
|
48060
|
+
return `Page ${pagination.currentPage} of ${pagination.totalPages} (${pagination.totalCount} total logs)`;
|
|
48061
|
+
}
|
|
48062
|
+
__name(formatPageHeader, "formatPageHeader");
|
|
47638
48063
|
function displayLogsCore(logs, pagination, title, clearScreen = false) {
|
|
47639
48064
|
if (clearScreen) {
|
|
47640
48065
|
console.clear();
|
|
@@ -47643,7 +48068,7 @@ function displayLogsCore(logs, pagination, title, clearScreen = false) {
|
|
|
47643
48068
|
${title}
|
|
47644
48069
|
`);
|
|
47645
48070
|
writeInfo(`${"\u2500".repeat(80)}`);
|
|
47646
|
-
writeInfo(
|
|
48071
|
+
writeInfo(`${formatPageHeader(pagination)}
|
|
47647
48072
|
`);
|
|
47648
48073
|
if (logs.length === 0) {
|
|
47649
48074
|
writeInfo("No logs found.");
|
|
@@ -47699,6 +48124,149 @@ async function resolveEntityId(apiKey, agentId, type, nameOrId) {
|
|
|
47699
48124
|
return found?.id || null;
|
|
47700
48125
|
}
|
|
47701
48126
|
__name(resolveEntityId, "resolveEntityId");
|
|
48127
|
+
function parseWindowBound(flag, raw) {
|
|
48128
|
+
const value3 = raw.trim();
|
|
48129
|
+
if (RELATIVE_WINDOW.test(value3)) return value3;
|
|
48130
|
+
if (ISO_TIME_SHAPE.test(value3)) {
|
|
48131
|
+
const parsed = Date.parse(value3);
|
|
48132
|
+
if (Number.isFinite(parsed)) return new Date(parsed).toISOString();
|
|
48133
|
+
}
|
|
48134
|
+
throw CliError.usage(`lua: ${flag} "${raw}" is not a time.`, `Use an ISO 8601 instant (2026-09-21T09:00:00Z) or a relative window: 15m, 2h, 7d.`);
|
|
48135
|
+
}
|
|
48136
|
+
__name(parseWindowBound, "parseWindowBound");
|
|
48137
|
+
function parseEnvironment(raw) {
|
|
48138
|
+
const value3 = raw.trim().toLowerCase();
|
|
48139
|
+
const valid = [
|
|
48140
|
+
...AGENT_LOG_ENVIRONMENTS
|
|
48141
|
+
].sort();
|
|
48142
|
+
if (valid.includes(value3)) return value3;
|
|
48143
|
+
throw CliError.usage(`lua: "${raw}" is not a valid --environment value.`, `Valid values: ${valid.join(", ")}`);
|
|
48144
|
+
}
|
|
48145
|
+
__name(parseEnvironment, "parseEnvironment");
|
|
48146
|
+
function followDelayMs() {
|
|
48147
|
+
const raw = Number(process.env.LUA_LOGS_FOLLOW_INTERVAL_MS);
|
|
48148
|
+
const base = Number.isFinite(raw) && raw >= 0 && raw <= 6e4 ? raw : FOLLOW_POLL_MS;
|
|
48149
|
+
const jitter = Math.min(FOLLOW_POLL_JITTER_MS, Math.floor(base / 4));
|
|
48150
|
+
return base + (jitter > 0 ? Math.floor(Math.random() * jitter) : 0);
|
|
48151
|
+
}
|
|
48152
|
+
__name(followDelayMs, "followDelayMs");
|
|
48153
|
+
function sleep2(ms, signal) {
|
|
48154
|
+
if (signal.aborted) return Promise.resolve();
|
|
48155
|
+
return new Promise((resolve7) => {
|
|
48156
|
+
const done = /* @__PURE__ */ __name(() => {
|
|
48157
|
+
clearTimeout(timer);
|
|
48158
|
+
signal.removeEventListener("abort", done);
|
|
48159
|
+
resolve7();
|
|
48160
|
+
}, "done");
|
|
48161
|
+
const timer = setTimeout(done, ms);
|
|
48162
|
+
signal.addEventListener("abort", done, {
|
|
48163
|
+
once: true
|
|
48164
|
+
});
|
|
48165
|
+
});
|
|
48166
|
+
}
|
|
48167
|
+
__name(sleep2, "sleep");
|
|
48168
|
+
function rowKey(row2) {
|
|
48169
|
+
return row2.id || row2._id;
|
|
48170
|
+
}
|
|
48171
|
+
__name(rowKey, "rowKey");
|
|
48172
|
+
async function sweepWindow(logsApi, agentId, limit, filters, pageCap) {
|
|
48173
|
+
const rows3 = [];
|
|
48174
|
+
let cursor = filters.cursor;
|
|
48175
|
+
let pagination;
|
|
48176
|
+
let pages = 0;
|
|
48177
|
+
for (; ; ) {
|
|
48178
|
+
const response = await logsApi.getAgentLogs(agentId, limit, 1, {
|
|
48179
|
+
...filters,
|
|
48180
|
+
cursor
|
|
48181
|
+
});
|
|
48182
|
+
if (!response.success) {
|
|
48183
|
+
throw CliError.fromStatus(response.error?.statusCode, response.error?.message || "Unknown error", void 0, apiErrorDetail(response.error));
|
|
48184
|
+
}
|
|
48185
|
+
const data = response.data;
|
|
48186
|
+
rows3.push(...data.logs ?? []);
|
|
48187
|
+
pagination = data.pagination;
|
|
48188
|
+
pages += 1;
|
|
48189
|
+
const next = data.nextCursor ?? null;
|
|
48190
|
+
if (!next || pages >= pageCap) {
|
|
48191
|
+
return {
|
|
48192
|
+
rows: rows3,
|
|
48193
|
+
nextCursor: next,
|
|
48194
|
+
pagination,
|
|
48195
|
+
capped: Boolean(next) && pages >= pageCap
|
|
48196
|
+
};
|
|
48197
|
+
}
|
|
48198
|
+
cursor = next;
|
|
48199
|
+
}
|
|
48200
|
+
}
|
|
48201
|
+
__name(sweepWindow, "sweepWindow");
|
|
48202
|
+
async function followLogs(logsApi, agentId, options, baseFilters) {
|
|
48203
|
+
const limit = options.limit || 20;
|
|
48204
|
+
const controller = new AbortController();
|
|
48205
|
+
const onSigint = /* @__PURE__ */ __name(() => controller.abort(), "onSigint");
|
|
48206
|
+
process.once("SIGINT", onSigint);
|
|
48207
|
+
const untilMs = options.until ? RELATIVE_WINDOW.test(options.until) ? 0 : Date.parse(options.until) : void 0;
|
|
48208
|
+
let boundarySeen = /* @__PURE__ */ new Set();
|
|
48209
|
+
let since = baseFilters.since;
|
|
48210
|
+
let backoff = 0;
|
|
48211
|
+
try {
|
|
48212
|
+
while (!controller.signal.aborted) {
|
|
48213
|
+
let sweep;
|
|
48214
|
+
try {
|
|
48215
|
+
const pageCap = since ? FOLLOW_PAGE_CAP : 1;
|
|
48216
|
+
sweep = await sweepWindow(logsApi, agentId, limit, {
|
|
48217
|
+
...baseFilters,
|
|
48218
|
+
since,
|
|
48219
|
+
cursor: void 0
|
|
48220
|
+
}, pageCap);
|
|
48221
|
+
} catch (error) {
|
|
48222
|
+
if (controller.signal.aborted) break;
|
|
48223
|
+
if (error instanceof CliError && error.exitCode === CLI_EXIT.UNAVAILABLE) {
|
|
48224
|
+
backoff = Math.min(FOLLOW_BACKOFF_MAX_MS, backoff ? backoff * 2 : FOLLOW_BACKOFF_MIN_MS);
|
|
48225
|
+
await sleep2(backoff, controller.signal);
|
|
48226
|
+
continue;
|
|
48227
|
+
}
|
|
48228
|
+
throw error;
|
|
48229
|
+
}
|
|
48230
|
+
backoff = 0;
|
|
48231
|
+
const fresh = sweep.rows.filter((row2) => !boundarySeen.has(rowKey(row2)));
|
|
48232
|
+
if (fresh.length > 0) {
|
|
48233
|
+
if (options.json) {
|
|
48234
|
+
console.log(JSON.stringify({
|
|
48235
|
+
logs: fresh,
|
|
48236
|
+
nextCursor: sweep.nextCursor ?? null,
|
|
48237
|
+
pagination: sweep.pagination ?? null
|
|
48238
|
+
}, null, 2));
|
|
48239
|
+
} else {
|
|
48240
|
+
const ordered = [
|
|
48241
|
+
...fresh
|
|
48242
|
+
].reverse();
|
|
48243
|
+
ordered.forEach((row2, index) => renderLogEntry(row2, index === ordered.length - 1));
|
|
48244
|
+
}
|
|
48245
|
+
if (sweep.capped && !options.json) {
|
|
48246
|
+
writeInfo(` \u2026 more rows remain in this window (stopped after ${FOLLOW_PAGE_CAP} pages); raising --limit catches up faster.`);
|
|
48247
|
+
}
|
|
48248
|
+
}
|
|
48249
|
+
if (sweep.rows.length > 0) {
|
|
48250
|
+
let newestMs = Number.NEGATIVE_INFINITY;
|
|
48251
|
+
for (const row2 of sweep.rows) {
|
|
48252
|
+
const ms = Date.parse(row2.timestamp);
|
|
48253
|
+
if (Number.isFinite(ms) && ms > newestMs) newestMs = ms;
|
|
48254
|
+
}
|
|
48255
|
+
if (Number.isFinite(newestMs)) {
|
|
48256
|
+
since = new Date(newestMs).toISOString();
|
|
48257
|
+
boundarySeen = new Set(sweep.rows.filter((row2) => Date.parse(row2.timestamp) === newestMs).map((row2) => rowKey(row2)));
|
|
48258
|
+
}
|
|
48259
|
+
}
|
|
48260
|
+
if (untilMs !== void 0 && Date.now() >= untilMs) break;
|
|
48261
|
+
if (controller.signal.aborted) break;
|
|
48262
|
+
await sleep2(followDelayMs(), controller.signal);
|
|
48263
|
+
}
|
|
48264
|
+
} finally {
|
|
48265
|
+
process.off("SIGINT", onSigint);
|
|
48266
|
+
if (!controller.signal.aborted) controller.abort();
|
|
48267
|
+
}
|
|
48268
|
+
}
|
|
48269
|
+
__name(followLogs, "followLogs");
|
|
47702
48270
|
async function nonInteractiveLogs(logsApi, agentId, apiKey, options) {
|
|
47703
48271
|
const filters = {};
|
|
47704
48272
|
if (options.type && options.type !== "all") {
|
|
@@ -47721,6 +48289,13 @@ async function nonInteractiveLogs(logsApi, agentId, apiKey, options) {
|
|
|
47721
48289
|
if (options.userId) {
|
|
47722
48290
|
filters.userId = options.userId;
|
|
47723
48291
|
}
|
|
48292
|
+
if (options.since) filters.since = options.since;
|
|
48293
|
+
if (options.until) filters.until = options.until;
|
|
48294
|
+
if (options.environment) filters.environment = options.environment;
|
|
48295
|
+
if (options.follow) {
|
|
48296
|
+
await followLogs(logsApi, agentId, options, filters);
|
|
48297
|
+
return;
|
|
48298
|
+
}
|
|
47724
48299
|
const response = await logsApi.getAgentLogs(agentId, options.limit || 20, options.page || 1, filters);
|
|
47725
48300
|
if (!response.success) {
|
|
47726
48301
|
throw CliError.fromStatus(response.error?.statusCode, response.error?.message || "Unknown error", void 0, apiErrorDetail(response.error));
|
|
@@ -47729,6 +48304,10 @@ async function nonInteractiveLogs(logsApi, agentId, apiKey, options) {
|
|
|
47729
48304
|
if (options.json) {
|
|
47730
48305
|
console.log(JSON.stringify({
|
|
47731
48306
|
logs: data.logs,
|
|
48307
|
+
// Always present so a script can `while (nextCursor)` without probing for the
|
|
48308
|
+
// key; `null` is the documented end-of-stream, and a server that predates A4
|
|
48309
|
+
// simply never sets it.
|
|
48310
|
+
nextCursor: data.nextCursor ?? null,
|
|
47732
48311
|
pagination: data.pagination
|
|
47733
48312
|
}, null, 2));
|
|
47734
48313
|
} else {
|
|
@@ -48017,8 +48596,8 @@ async function handleNavigation(action, pagination, setPage) {
|
|
|
48017
48596
|
}
|
|
48018
48597
|
}
|
|
48019
48598
|
__name(handleNavigation, "handleNavigation");
|
|
48020
|
-
function capitalize(
|
|
48021
|
-
return
|
|
48599
|
+
function capitalize(str2) {
|
|
48600
|
+
return str2.charAt(0).toUpperCase() + str2.slice(1);
|
|
48022
48601
|
}
|
|
48023
48602
|
__name(capitalize, "capitalize");
|
|
48024
48603
|
function getLogIcon(subType, logSource) {
|
|
@@ -48082,6 +48661,1423 @@ function getLogColor(subType, logSource) {
|
|
|
48082
48661
|
}
|
|
48083
48662
|
__name(getLogColor, "getLogColor");
|
|
48084
48663
|
|
|
48664
|
+
// src/commands/drains.ts
|
|
48665
|
+
init_cli();
|
|
48666
|
+
init_command_utils();
|
|
48667
|
+
init_files();
|
|
48668
|
+
init_credential_operational_context();
|
|
48669
|
+
init_constants();
|
|
48670
|
+
init_cli_error();
|
|
48671
|
+
init_analytics();
|
|
48672
|
+
|
|
48673
|
+
// src/api/drains.api.service.ts
|
|
48674
|
+
init_http_client();
|
|
48675
|
+
var DrainsApi = class extends HttpClient {
|
|
48676
|
+
static {
|
|
48677
|
+
__name(this, "DrainsApi");
|
|
48678
|
+
}
|
|
48679
|
+
orgId;
|
|
48680
|
+
constructor(baseUrl, credential, orgId) {
|
|
48681
|
+
super(baseUrl, credential), this.orgId = orgId;
|
|
48682
|
+
}
|
|
48683
|
+
/**
|
|
48684
|
+
* The base path every call hangs off — RELATIVE to `baseUrl`, because every
|
|
48685
|
+
* `HttpClient` verb prepends `this.baseUrl` itself (`httpGet(url) => baseUrl + url`).
|
|
48686
|
+
* The scaffolded body interpolated `baseUrl` a second time, which would have sent
|
|
48687
|
+
* every request to `<base><base>/admin/…`; the signature is unchanged.
|
|
48688
|
+
*/
|
|
48689
|
+
base() {
|
|
48690
|
+
return `/admin/orgs/${encodeURIComponent(this.orgId)}/log-drains`;
|
|
48691
|
+
}
|
|
48692
|
+
/** `…/log-drains/:drainId` with the id encoded. */
|
|
48693
|
+
drainPath(drainId, suffix = "") {
|
|
48694
|
+
return `${this.base()}/${encodeURIComponent(drainId)}${suffix}`;
|
|
48695
|
+
}
|
|
48696
|
+
async listDrains() {
|
|
48697
|
+
return this.httpGet(this.base());
|
|
48698
|
+
}
|
|
48699
|
+
async getDrain(drainId) {
|
|
48700
|
+
return this.httpGet(this.drainPath(drainId));
|
|
48701
|
+
}
|
|
48702
|
+
/** The response carries `secret` — print it ONCE and never store it. */
|
|
48703
|
+
async createDrain(input) {
|
|
48704
|
+
return this.httpPostOnce(this.base(), input);
|
|
48705
|
+
}
|
|
48706
|
+
async updateDrain(drainId, input) {
|
|
48707
|
+
return this.httpPatch(this.drainPath(drainId), input);
|
|
48708
|
+
}
|
|
48709
|
+
async deleteDrain(drainId) {
|
|
48710
|
+
return this.httpDelete(this.drainPath(drainId));
|
|
48711
|
+
}
|
|
48712
|
+
async testDrain(drainId) {
|
|
48713
|
+
return this.httpPost(this.drainPath(drainId, "/test"));
|
|
48714
|
+
}
|
|
48715
|
+
async verifyDrain(drainId) {
|
|
48716
|
+
return this.httpPost(this.drainPath(drainId, "/verify"));
|
|
48717
|
+
}
|
|
48718
|
+
async pauseDrain(drainId, reason) {
|
|
48719
|
+
return this.httpPost(this.drainPath(drainId, "/pause"), reason ? {
|
|
48720
|
+
reason
|
|
48721
|
+
} : {});
|
|
48722
|
+
}
|
|
48723
|
+
async resumeDrain(drainId) {
|
|
48724
|
+
return this.httpPost(this.drainPath(drainId, "/resume"), {});
|
|
48725
|
+
}
|
|
48726
|
+
/**
|
|
48727
|
+
* `finalize` closes an open rotation window instead of opening a new one — that
|
|
48728
|
+
* answer is a plain `LogDrainRead` and is safe to retry; minting is not.
|
|
48729
|
+
*/
|
|
48730
|
+
async rotateSecret(drainId, finalize) {
|
|
48731
|
+
const path26 = this.drainPath(drainId, `/rotate-secret${finalize ? "?finalize=true" : ""}`);
|
|
48732
|
+
return finalize ? this.httpPost(path26, {}) : this.httpPostOnce(path26, {});
|
|
48733
|
+
}
|
|
48734
|
+
async listDeliveries(drainId, opts = {}) {
|
|
48735
|
+
const query = new URLSearchParams();
|
|
48736
|
+
if (opts.limit !== void 0) query.set("limit", String(opts.limit));
|
|
48737
|
+
if (opts.cursor) query.set("cursor", opts.cursor);
|
|
48738
|
+
if (opts.kind) query.set("kind", opts.kind);
|
|
48739
|
+
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
48740
|
+
return this.httpGet(this.drainPath(drainId, `/deliveries${suffix}`));
|
|
48741
|
+
}
|
|
48742
|
+
};
|
|
48743
|
+
|
|
48744
|
+
// src/commands/drains.mutations.ts
|
|
48745
|
+
init_dist();
|
|
48746
|
+
init_cli();
|
|
48747
|
+
init_cli_error();
|
|
48748
|
+
var CONTENT_WARNING_TEXT = "These sources carry customer content: user_message and agent_response bodies, and the debug tool envelopes attached to them. Message bodies and tool inputs may contain personal data and secrets. Lua scrubs known token shapes only \u2014 anything it does not recognise leaves the platform with the record.";
|
|
48749
|
+
var CONTENT_ACKNOWLEDGEMENT_TEXT = "I understand that user messages, agent responses and debug tool envelopes may contain personal data and secrets, and that Lua scrubs known token shapes only.";
|
|
48750
|
+
var MAX_HEADERS = 10;
|
|
48751
|
+
var HEADER_NAME_PATTERN = /^[A-Za-z0-9-]{1,64}$/;
|
|
48752
|
+
var ENDPOINT_TYPES = [
|
|
48753
|
+
"http",
|
|
48754
|
+
"otlp",
|
|
48755
|
+
"betterstack"
|
|
48756
|
+
];
|
|
48757
|
+
var SITE_TYPES = [
|
|
48758
|
+
"datadog"
|
|
48759
|
+
];
|
|
48760
|
+
var PHASE2_SOURCES = [
|
|
48761
|
+
"delivery",
|
|
48762
|
+
"trigger-execution",
|
|
48763
|
+
"job-execution",
|
|
48764
|
+
"workflow-run",
|
|
48765
|
+
"workflow-audit"
|
|
48766
|
+
];
|
|
48767
|
+
var SELECTABLE_SOURCES = LOG_DRAIN_SOURCES.filter((source) => !PHASE2_SOURCES.includes(source));
|
|
48768
|
+
var NON_CONTENT_SOURCES = SELECTABLE_SOURCES.filter((source) => !LOG_DRAIN_CONTENT_SOURCES.includes(source));
|
|
48769
|
+
var TOKEN_ECHO_TYPES = [
|
|
48770
|
+
"http"
|
|
48771
|
+
];
|
|
48772
|
+
var VERIFY_OUTCOME_TEXT = {
|
|
48773
|
+
ok: "verified",
|
|
48774
|
+
no_2xx: "the endpoint did not answer 2xx",
|
|
48775
|
+
token_not_echoed: "token not echoed",
|
|
48776
|
+
ssrf_refused: "the endpoint was refused by the SSRF guard",
|
|
48777
|
+
timeout: "the endpoint did not answer in time",
|
|
48778
|
+
error: "the verification request failed"
|
|
48779
|
+
};
|
|
48780
|
+
var DRAIN_POLL = {
|
|
48781
|
+
intervalMs: 1e3,
|
|
48782
|
+
testAttempts: 30,
|
|
48783
|
+
verifyAttempts: 60,
|
|
48784
|
+
sleep: /* @__PURE__ */ __name((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)), "sleep")
|
|
48785
|
+
};
|
|
48786
|
+
function printJson(payload) {
|
|
48787
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
48788
|
+
}
|
|
48789
|
+
__name(printJson, "printJson");
|
|
48790
|
+
function emitAside(line, json) {
|
|
48791
|
+
if (json) process.stderr.write(`${line}
|
|
48792
|
+
`);
|
|
48793
|
+
else writeInfo(line);
|
|
48794
|
+
}
|
|
48795
|
+
__name(emitAside, "emitAside");
|
|
48796
|
+
function shortIso(value3) {
|
|
48797
|
+
if (typeof value3 !== "string" || value3.length === 0) return "\u2014";
|
|
48798
|
+
const date = new Date(value3);
|
|
48799
|
+
if (Number.isNaN(date.getTime())) return value3;
|
|
48800
|
+
return date.toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
48801
|
+
}
|
|
48802
|
+
__name(shortIso, "shortIso");
|
|
48803
|
+
function trimmed(value3) {
|
|
48804
|
+
if (typeof value3 !== "string") return void 0;
|
|
48805
|
+
const text = value3.trim();
|
|
48806
|
+
return text.length > 0 ? text : void 0;
|
|
48807
|
+
}
|
|
48808
|
+
__name(trimmed, "trimmed");
|
|
48809
|
+
function parseType(raw) {
|
|
48810
|
+
const value3 = trimmed(raw)?.toLowerCase();
|
|
48811
|
+
if (!value3) return void 0;
|
|
48812
|
+
if (!LOG_DRAIN_TYPES_PHASE1.includes(value3)) {
|
|
48813
|
+
throw CliError.usage(`--type "${raw}" is not available.`, listHint("Available destinations", LOG_DRAIN_TYPES_PHASE1));
|
|
48814
|
+
}
|
|
48815
|
+
return value3;
|
|
48816
|
+
}
|
|
48817
|
+
__name(parseType, "parseType");
|
|
48818
|
+
function parseFormat(raw) {
|
|
48819
|
+
const value3 = trimmed(raw)?.toLowerCase();
|
|
48820
|
+
if (!value3) return void 0;
|
|
48821
|
+
if (!LOG_DRAIN_FORMATS.includes(value3)) {
|
|
48822
|
+
throw CliError.usage(`--format "${raw}" is not a drain format.`, listHint("Valid values", LOG_DRAIN_FORMATS));
|
|
48823
|
+
}
|
|
48824
|
+
return value3;
|
|
48825
|
+
}
|
|
48826
|
+
__name(parseFormat, "parseFormat");
|
|
48827
|
+
function parseSeverity(raw) {
|
|
48828
|
+
const value3 = trimmed(raw)?.toLowerCase();
|
|
48829
|
+
if (!value3) return void 0;
|
|
48830
|
+
if (!LOG_DRAIN_SEVERITIES.includes(value3)) {
|
|
48831
|
+
throw CliError.usage(`--min-severity "${raw}" is not a severity.`, listHint("Valid values", LOG_DRAIN_SEVERITIES));
|
|
48832
|
+
}
|
|
48833
|
+
return value3;
|
|
48834
|
+
}
|
|
48835
|
+
__name(parseSeverity, "parseSeverity");
|
|
48836
|
+
function splitList(raw) {
|
|
48837
|
+
return raw.split(",").map((part) => part.trim()).filter((part) => part.length > 0);
|
|
48838
|
+
}
|
|
48839
|
+
__name(splitList, "splitList");
|
|
48840
|
+
function parseSources(raw) {
|
|
48841
|
+
const value3 = trimmed(raw);
|
|
48842
|
+
if (!value3) return void 0;
|
|
48843
|
+
const requested = splitList(value3);
|
|
48844
|
+
if (requested.length === 0) {
|
|
48845
|
+
throw CliError.usage("--sources was empty \u2014 name at least one source, or leave the flag off for the default set.");
|
|
48846
|
+
}
|
|
48847
|
+
const sources = [];
|
|
48848
|
+
for (const source of requested) {
|
|
48849
|
+
if (!SELECTABLE_SOURCES.includes(source)) {
|
|
48850
|
+
throw CliError.usage(`--sources "${source}" is not a selectable source.`, listHint("Valid values", SELECTABLE_SOURCES));
|
|
48851
|
+
}
|
|
48852
|
+
if (!sources.includes(source)) sources.push(source);
|
|
48853
|
+
}
|
|
48854
|
+
return sources;
|
|
48855
|
+
}
|
|
48856
|
+
__name(parseSources, "parseSources");
|
|
48857
|
+
function parseEnvironments(raw) {
|
|
48858
|
+
const value3 = trimmed(raw);
|
|
48859
|
+
if (!value3) return void 0;
|
|
48860
|
+
const environments = [];
|
|
48861
|
+
for (const environment of splitList(value3)) {
|
|
48862
|
+
if (!AGENT_LOG_ENVIRONMENTS.includes(environment)) {
|
|
48863
|
+
throw CliError.usage(`--environments "${environment}" is not an environment.`, listHint("Valid values", AGENT_LOG_ENVIRONMENTS));
|
|
48864
|
+
}
|
|
48865
|
+
if (!environments.includes(environment)) {
|
|
48866
|
+
environments.push(environment);
|
|
48867
|
+
}
|
|
48868
|
+
}
|
|
48869
|
+
return environments.length > 0 ? environments : void 0;
|
|
48870
|
+
}
|
|
48871
|
+
__name(parseEnvironments, "parseEnvironments");
|
|
48872
|
+
function parseAgents(raw) {
|
|
48873
|
+
const value3 = trimmed(raw);
|
|
48874
|
+
if (!value3) return void 0;
|
|
48875
|
+
if (value3.toLowerCase() === "all" || value3 === "*") return "*";
|
|
48876
|
+
const agents = splitList(value3);
|
|
48877
|
+
if (agents.length === 0) {
|
|
48878
|
+
throw CliError.usage("--agents was empty \u2014 pass 'all' or a comma-separated list of agent ids.");
|
|
48879
|
+
}
|
|
48880
|
+
return agents;
|
|
48881
|
+
}
|
|
48882
|
+
__name(parseAgents, "parseAgents");
|
|
48883
|
+
function parseSampling(raw) {
|
|
48884
|
+
const value3 = trimmed(raw);
|
|
48885
|
+
if (!value3) return void 0;
|
|
48886
|
+
const hint = "Only debug is sampleable in phase 1, e.g. --sampling debug=0.1";
|
|
48887
|
+
const eq3 = value3.indexOf("=");
|
|
48888
|
+
if (eq3 === -1) throw CliError.usage(`--sampling "${raw}" must read <key>=<fraction>.`, hint);
|
|
48889
|
+
const key = value3.slice(0, eq3).trim().toLowerCase();
|
|
48890
|
+
const fraction = Number(value3.slice(eq3 + 1).trim());
|
|
48891
|
+
if (key !== "debug") throw CliError.usage(`--sampling "${key}" is not sampleable.`, hint);
|
|
48892
|
+
if (!Number.isFinite(fraction) || fraction <= 0 || fraction > 1) {
|
|
48893
|
+
throw CliError.usage(`--sampling debug must be a fraction in (0, 1] (got "${value3.slice(eq3 + 1).trim()}").`, hint);
|
|
48894
|
+
}
|
|
48895
|
+
return {
|
|
48896
|
+
debug: fraction
|
|
48897
|
+
};
|
|
48898
|
+
}
|
|
48899
|
+
__name(parseSampling, "parseSampling");
|
|
48900
|
+
function assertHeaderName(name, flag) {
|
|
48901
|
+
if (!HEADER_NAME_PATTERN.test(name)) {
|
|
48902
|
+
throw CliError.usage(`${flag} header name "${name}" must match ^[A-Za-z0-9-]{1,64}$.`, "A header name is a token \u2014 no spaces, no colon, no newline");
|
|
48903
|
+
}
|
|
48904
|
+
}
|
|
48905
|
+
__name(assertHeaderName, "assertHeaderName");
|
|
48906
|
+
async function resolveHeaders(options) {
|
|
48907
|
+
const headers = [];
|
|
48908
|
+
const seen = /* @__PURE__ */ new Set();
|
|
48909
|
+
const remember = /* @__PURE__ */ __name((header) => {
|
|
48910
|
+
const key = header.name.toLowerCase();
|
|
48911
|
+
if (seen.has(key)) {
|
|
48912
|
+
throw CliError.usage(`Header "${header.name}" was given twice.`, "Each header name may appear once");
|
|
48913
|
+
}
|
|
48914
|
+
seen.add(key);
|
|
48915
|
+
headers.push(header);
|
|
48916
|
+
}, "remember");
|
|
48917
|
+
for (const entry of options.headerFromEnv ?? []) {
|
|
48918
|
+
const raw = `${entry}`.trim();
|
|
48919
|
+
const eq3 = raw.indexOf("=");
|
|
48920
|
+
if (eq3 <= 0 || eq3 === raw.length - 1) {
|
|
48921
|
+
throw CliError.usage(`--header-from-env "${raw}" must read <name>=<ENV_VAR>.`, "The VALUE stays in the environment \u2014 e.g. --header-from-env DD-API-KEY=DATADOG_API_KEY");
|
|
48922
|
+
}
|
|
48923
|
+
const name = raw.slice(0, eq3).trim();
|
|
48924
|
+
const variable = raw.slice(eq3 + 1).trim();
|
|
48925
|
+
assertHeaderName(name, "--header-from-env");
|
|
48926
|
+
const value3 = process.env[variable];
|
|
48927
|
+
if (value3 === void 0 || value3 === "") {
|
|
48928
|
+
throw CliError.usage(`--header-from-env ${name}=${variable}: the environment variable ${variable} is unset or empty.`, `Export ${variable} in the step that runs this command`);
|
|
48929
|
+
}
|
|
48930
|
+
remember({
|
|
48931
|
+
name,
|
|
48932
|
+
value: value3,
|
|
48933
|
+
fromEnv: variable
|
|
48934
|
+
});
|
|
48935
|
+
}
|
|
48936
|
+
for (const entry of options.header ?? []) {
|
|
48937
|
+
const raw = `${entry}`.trim();
|
|
48938
|
+
if (raw.includes("=")) {
|
|
48939
|
+
throw CliError.usage(`--header takes a header NAME, not a value ("${raw.slice(0, raw.indexOf("="))}=\u2026").`, joinHint("Header values are never flags \u2014 a shell history and a CI log both keep them.", "Interactively: --header " + raw.slice(0, raw.indexOf("=")) + " (the value is prompted)", "In --ci: --header-from-env " + raw.slice(0, raw.indexOf("=")) + "=YOUR_ENV_VAR"));
|
|
48940
|
+
}
|
|
48941
|
+
assertHeaderName(raw, "--header");
|
|
48942
|
+
if (isCiModeEnabled()) {
|
|
48943
|
+
throw CliError.usage(`--header ${raw} needs an interactive prompt for its value, and --ci is set.`, `Use --header-from-env ${raw}=YOUR_ENV_VAR so the value never reaches the command line`);
|
|
48944
|
+
}
|
|
48945
|
+
const answer = await safePrompt([
|
|
48946
|
+
{
|
|
48947
|
+
type: "password",
|
|
48948
|
+
name: "value",
|
|
48949
|
+
mask: "*",
|
|
48950
|
+
message: `Value for header ${raw}:`,
|
|
48951
|
+
validate: /* @__PURE__ */ __name((input) => input && input.length > 0 ? true : "A header value cannot be empty", "validate")
|
|
48952
|
+
}
|
|
48953
|
+
]);
|
|
48954
|
+
const value3 = answer?.value;
|
|
48955
|
+
if (!value3) throw CliError.usage(`No value was given for header ${raw}.`);
|
|
48956
|
+
remember({
|
|
48957
|
+
name: raw,
|
|
48958
|
+
value: value3
|
|
48959
|
+
});
|
|
48960
|
+
}
|
|
48961
|
+
if (headers.length > MAX_HEADERS) {
|
|
48962
|
+
throw CliError.usage(`A drain carries at most ${MAX_HEADERS} headers (got ${headers.length}).`);
|
|
48963
|
+
}
|
|
48964
|
+
return headers;
|
|
48965
|
+
}
|
|
48966
|
+
__name(resolveHeaders, "resolveHeaders");
|
|
48967
|
+
function wireHeaders(headers) {
|
|
48968
|
+
return headers.map(({ name, value: value3 }) => ({
|
|
48969
|
+
name,
|
|
48970
|
+
value: value3
|
|
48971
|
+
}));
|
|
48972
|
+
}
|
|
48973
|
+
__name(wireHeaders, "wireHeaders");
|
|
48974
|
+
function wantsContent(options, sources) {
|
|
48975
|
+
if (options.includeContent === true) return true;
|
|
48976
|
+
return (sources ?? []).some((source) => LOG_DRAIN_CONTENT_SOURCES.includes(source));
|
|
48977
|
+
}
|
|
48978
|
+
__name(wantsContent, "wantsContent");
|
|
48979
|
+
async function acknowledgeContent(options) {
|
|
48980
|
+
emitAside("", options.json);
|
|
48981
|
+
emitAside(CONTENT_WARNING_TEXT, options.json);
|
|
48982
|
+
emitAside("", options.json);
|
|
48983
|
+
emitAside(CONTENT_ACKNOWLEDGEMENT_TEXT, options.json);
|
|
48984
|
+
emitAside("", options.json);
|
|
48985
|
+
if (options.yes) return true;
|
|
48986
|
+
if (isCiModeEnabled()) {
|
|
48987
|
+
throw CliError.usage("--include-content needs the acknowledgement above; pass --yes to give it non-interactively.", "Nothing was created");
|
|
48988
|
+
}
|
|
48989
|
+
const answer = await safePrompt([
|
|
48990
|
+
{
|
|
48991
|
+
type: "confirm",
|
|
48992
|
+
name: "acknowledged",
|
|
48993
|
+
message: "Do you acknowledge this?",
|
|
48994
|
+
default: false
|
|
48995
|
+
}
|
|
48996
|
+
]);
|
|
48997
|
+
if (!answer?.acknowledged) {
|
|
48998
|
+
throw CliError.usage("Content was not enabled: the acknowledgement was declined.", "Nothing was created");
|
|
48999
|
+
}
|
|
49000
|
+
return true;
|
|
49001
|
+
}
|
|
49002
|
+
__name(acknowledgeContent, "acknowledgeContent");
|
|
49003
|
+
function missingFlag(flag, what, hint) {
|
|
49004
|
+
return CliError.usage(`${flag} is required (${what}).`, joinHint(hint, "Prompting is not possible under --ci"));
|
|
49005
|
+
}
|
|
49006
|
+
__name(missingFlag, "missingFlag");
|
|
49007
|
+
async function promptText(message, flag, what) {
|
|
49008
|
+
if (isCiModeEnabled()) throw missingFlag(flag, what);
|
|
49009
|
+
const answer = await safePrompt([
|
|
49010
|
+
{
|
|
49011
|
+
type: "input",
|
|
49012
|
+
name: "value",
|
|
49013
|
+
message,
|
|
49014
|
+
validate: /* @__PURE__ */ __name((input) => input && input.trim().length > 0 ? true : "Required", "validate")
|
|
49015
|
+
}
|
|
49016
|
+
]);
|
|
49017
|
+
const value3 = trimmed(answer?.value);
|
|
49018
|
+
if (!value3) throw missingFlag(flag, what);
|
|
49019
|
+
return value3;
|
|
49020
|
+
}
|
|
49021
|
+
__name(promptText, "promptText");
|
|
49022
|
+
async function promptChoice(message, choices, flag, what) {
|
|
49023
|
+
if (isCiModeEnabled()) throw missingFlag(flag, what, `Values: ${choices.join(" | ")}`);
|
|
49024
|
+
const answer = await safePrompt([
|
|
49025
|
+
{
|
|
49026
|
+
type: "list",
|
|
49027
|
+
name: "value",
|
|
49028
|
+
message,
|
|
49029
|
+
choices
|
|
49030
|
+
}
|
|
49031
|
+
]);
|
|
49032
|
+
const value3 = answer?.value;
|
|
49033
|
+
if (!value3) throw missingFlag(flag, what, `Values: ${choices.join(" | ")}`);
|
|
49034
|
+
return value3;
|
|
49035
|
+
}
|
|
49036
|
+
__name(promptChoice, "promptChoice");
|
|
49037
|
+
async function promptSources() {
|
|
49038
|
+
const answer = await safePrompt([
|
|
49039
|
+
{
|
|
49040
|
+
type: "checkbox",
|
|
49041
|
+
name: "sources",
|
|
49042
|
+
message: "Which sources should this drain carry?",
|
|
49043
|
+
pageSize: 20,
|
|
49044
|
+
choices: [
|
|
49045
|
+
{
|
|
49046
|
+
type: "separator",
|
|
49047
|
+
line: "\u2500\u2500 Conversation content (needs the acknowledgement) \u2500\u2500"
|
|
49048
|
+
},
|
|
49049
|
+
...LOG_DRAIN_CONTENT_SOURCES.map((source) => ({
|
|
49050
|
+
name: source,
|
|
49051
|
+
value: source,
|
|
49052
|
+
checked: false
|
|
49053
|
+
})),
|
|
49054
|
+
{
|
|
49055
|
+
type: "separator",
|
|
49056
|
+
line: "\u2500\u2500 Execution and platform \u2500\u2500"
|
|
49057
|
+
},
|
|
49058
|
+
...NON_CONTENT_SOURCES.map((source) => ({
|
|
49059
|
+
name: source,
|
|
49060
|
+
value: source,
|
|
49061
|
+
checked: LOG_DRAIN_DEFAULT_SOURCES.includes(source)
|
|
49062
|
+
}))
|
|
49063
|
+
],
|
|
49064
|
+
validate: /* @__PURE__ */ __name((chosen) => chosen.length > 0 ? true : "Pick at least one source", "validate")
|
|
49065
|
+
}
|
|
49066
|
+
]);
|
|
49067
|
+
const sources = answer?.sources ?? [];
|
|
49068
|
+
if (sources.length === 0) throw CliError.usage("A drain needs at least one source.");
|
|
49069
|
+
return sources;
|
|
49070
|
+
}
|
|
49071
|
+
__name(promptSources, "promptSources");
|
|
49072
|
+
async function resolveDestination(type, options) {
|
|
49073
|
+
const endpoint = trimmed(options.endpoint);
|
|
49074
|
+
const site = trimmed(options.site);
|
|
49075
|
+
if (SITE_TYPES.includes(type)) {
|
|
49076
|
+
if (endpoint) {
|
|
49077
|
+
throw CliError.usage(`--endpoint is not accepted for ${type}: its URL is derived from --site.`, listHint("Sites", LOG_DRAIN_DATADOG_SITES));
|
|
49078
|
+
}
|
|
49079
|
+
const chosen = site ?? await promptChoice("Which site?", LOG_DRAIN_DATADOG_SITES, "--site", `${type}`);
|
|
49080
|
+
if (!LOG_DRAIN_DATADOG_SITES.includes(chosen)) {
|
|
49081
|
+
throw CliError.usage(`--site "${chosen}" is not a ${type} site.`, listHint("Sites", LOG_DRAIN_DATADOG_SITES));
|
|
49082
|
+
}
|
|
49083
|
+
return {
|
|
49084
|
+
site: chosen
|
|
49085
|
+
};
|
|
49086
|
+
}
|
|
49087
|
+
if (!ENDPOINT_TYPES.includes(type)) {
|
|
49088
|
+
throw CliError.usage(`This lua-cli does not know how to address a "${type}" destination yet.`, "Upgrade lua-cli, or create the drain from the dashboard");
|
|
49089
|
+
}
|
|
49090
|
+
if (site) {
|
|
49091
|
+
throw CliError.usage(`--site is not accepted for ${type}: give the destination URL with --endpoint.`);
|
|
49092
|
+
}
|
|
49093
|
+
const url = endpoint ?? await promptText(type === "otlp" ? "OTLP logs endpoint (the full /v1/logs URL):" : "Destination URL:", "--endpoint", `${type} sends to your own URL`);
|
|
49094
|
+
return {
|
|
49095
|
+
endpoint: url
|
|
49096
|
+
};
|
|
49097
|
+
}
|
|
49098
|
+
__name(resolveDestination, "resolveDestination");
|
|
49099
|
+
function verificationCurl(type, endpoint, headers) {
|
|
49100
|
+
const target = endpoint ?? "<your endpoint>";
|
|
49101
|
+
const headerArgs = headers.map((header) => header.fromEnv ? ` -H "${header.name}: $${header.fromEnv}" \\` : ` -H '${header.name}: <the value you entered>' \\`);
|
|
49102
|
+
if (TOKEN_ECHO_TYPES.includes(type)) {
|
|
49103
|
+
return [
|
|
49104
|
+
`curl -isS -X POST '${target}' \\`,
|
|
49105
|
+
...headerArgs,
|
|
49106
|
+
` -H 'Content-Type: application/json' \\`,
|
|
49107
|
+
` -H 'X-Lua-Verify: lua-echo-check' \\`,
|
|
49108
|
+
` --data '{"records":[]}' | grep -i 'x-lua-verify'`
|
|
49109
|
+
];
|
|
49110
|
+
}
|
|
49111
|
+
return [
|
|
49112
|
+
`curl -isS -X POST '${target}' \\`,
|
|
49113
|
+
...headerArgs,
|
|
49114
|
+
` -H 'Content-Type: application/json' \\`,
|
|
49115
|
+
` --data '[]'`
|
|
49116
|
+
];
|
|
49117
|
+
}
|
|
49118
|
+
__name(verificationCurl, "verificationCurl");
|
|
49119
|
+
function verificationInstructions(drain, headers, options) {
|
|
49120
|
+
const type = drain.type;
|
|
49121
|
+
const json = options.json;
|
|
49122
|
+
emitAside("", json);
|
|
49123
|
+
emitAside("Before anything is delivered, Lua has to confirm you own this destination.", json);
|
|
49124
|
+
if (TOKEN_ECHO_TYPES.includes(type)) {
|
|
49125
|
+
emitAside("Lua POSTs one record carrying an X-Lua-Verify header; your receiver must answer 2xx AND", json);
|
|
49126
|
+
emitAside("repeat that header back on the response. Check yours first:", json);
|
|
49127
|
+
} else {
|
|
49128
|
+
emitAside("Lua POSTs one record to the intake; any 2xx from the vendor verifies the drain.", json);
|
|
49129
|
+
emitAside("Check the credentials reach the intake first:", json);
|
|
49130
|
+
}
|
|
49131
|
+
emitAside("", json);
|
|
49132
|
+
for (const line of verificationCurl(type, drain.endpoint, headers)) emitAside(` ${line}`, json);
|
|
49133
|
+
emitAside("", json);
|
|
49134
|
+
emitAside(`Then: lua drains verify ${drain.id}`, json);
|
|
49135
|
+
}
|
|
49136
|
+
__name(verificationInstructions, "verificationInstructions");
|
|
49137
|
+
async function createDrainCore(context, options) {
|
|
49138
|
+
const name = trimmed(options.name) ?? await promptText("Drain name:", "--name", "1\u201364 chars, unique per org");
|
|
49139
|
+
const type = parseType(options.type) ?? await promptChoice("Where should the logs go?", LOG_DRAIN_TYPES_PHASE1, "--type", "the destination kind");
|
|
49140
|
+
const destination = await resolveDestination(type, options);
|
|
49141
|
+
const format = parseFormat(options.format);
|
|
49142
|
+
const headers = await resolveHeaders(options);
|
|
49143
|
+
const flagSources = parseSources(options.sources);
|
|
49144
|
+
const sources = flagSources ?? (isCiModeEnabled() ? void 0 : await promptSources());
|
|
49145
|
+
const minSeverity = parseSeverity(options.minSeverity);
|
|
49146
|
+
const environments = parseEnvironments(options.environments);
|
|
49147
|
+
const sampling = parseSampling(options.sampling);
|
|
49148
|
+
const agents = parseAgents(options.agents) ?? (context.agentId ? [
|
|
49149
|
+
context.agentId
|
|
49150
|
+
] : "*");
|
|
49151
|
+
const includeContent = wantsContent(options, sources);
|
|
49152
|
+
const includeContentAck = includeContent ? await acknowledgeContent(options) : void 0;
|
|
49153
|
+
const input = {
|
|
49154
|
+
name,
|
|
49155
|
+
type,
|
|
49156
|
+
...destination.endpoint ? {
|
|
49157
|
+
endpoint: destination.endpoint
|
|
49158
|
+
} : {},
|
|
49159
|
+
...destination.site ? {
|
|
49160
|
+
site: destination.site
|
|
49161
|
+
} : {},
|
|
49162
|
+
...format ? {
|
|
49163
|
+
format
|
|
49164
|
+
} : {},
|
|
49165
|
+
...headers.length > 0 ? {
|
|
49166
|
+
headers: wireHeaders(headers)
|
|
49167
|
+
} : {},
|
|
49168
|
+
...sources ? {
|
|
49169
|
+
sources
|
|
49170
|
+
} : {},
|
|
49171
|
+
...minSeverity ? {
|
|
49172
|
+
minSeverity
|
|
49173
|
+
} : {},
|
|
49174
|
+
agents,
|
|
49175
|
+
environments: environments ?? [
|
|
49176
|
+
"production"
|
|
49177
|
+
],
|
|
49178
|
+
...sampling ? {
|
|
49179
|
+
sampling
|
|
49180
|
+
} : {},
|
|
49181
|
+
...includeContent ? {
|
|
49182
|
+
includeContent: true,
|
|
49183
|
+
includeContentAck
|
|
49184
|
+
} : {}
|
|
49185
|
+
};
|
|
49186
|
+
const created = await drainsCall(() => drainsApiFor(context).createDrain(input));
|
|
49187
|
+
const { secret, ...drain } = created;
|
|
49188
|
+
if (options.json) {
|
|
49189
|
+
printJson(secret ? {
|
|
49190
|
+
drain,
|
|
49191
|
+
secret
|
|
49192
|
+
} : {
|
|
49193
|
+
drain
|
|
49194
|
+
});
|
|
49195
|
+
} else {
|
|
49196
|
+
writeSuccess(`\u2705 Created drain ${drain.name} (${drain.id})`);
|
|
49197
|
+
writeInfo(` type ${drain.type} \xB7 ${drain.endpoint ?? drain.site ?? "\u2014"} \xB7 state ${drain.state}`);
|
|
49198
|
+
if (secret) {
|
|
49199
|
+
writeInfo("");
|
|
49200
|
+
writeInfo("\u{1F511} Signing secret \u2014 shown once, and never again. Store it now:");
|
|
49201
|
+
writeInfo(` ${secret}`);
|
|
49202
|
+
writeInfo(" Your receiver verifies X-Lua-Signature with it (docs: /drains/verify-signatures).");
|
|
49203
|
+
}
|
|
49204
|
+
}
|
|
49205
|
+
verificationInstructions(drain, headers, options);
|
|
49206
|
+
if (!options.json) {
|
|
49207
|
+
writeHintBlock({
|
|
49208
|
+
headline: "Next:",
|
|
49209
|
+
lines: [
|
|
49210
|
+
{
|
|
49211
|
+
label: "Verify",
|
|
49212
|
+
command: `lua drains verify ${drain.id}`
|
|
49213
|
+
},
|
|
49214
|
+
{
|
|
49215
|
+
label: "Send one record",
|
|
49216
|
+
command: `lua drains test ${drain.id}`
|
|
49217
|
+
}
|
|
49218
|
+
]
|
|
49219
|
+
});
|
|
49220
|
+
}
|
|
49221
|
+
}
|
|
49222
|
+
__name(createDrainCore, "createDrainCore");
|
|
49223
|
+
async function updateDrainCore(context, drainId, options) {
|
|
49224
|
+
if (trimmed(options.type)) {
|
|
49225
|
+
throw CliError.usage("A drain cannot change type in place.", "Delete this drain and create a new one of the other type");
|
|
49226
|
+
}
|
|
49227
|
+
const patch = {};
|
|
49228
|
+
const name = trimmed(options.name);
|
|
49229
|
+
if (name) patch.name = name;
|
|
49230
|
+
const endpoint = trimmed(options.endpoint);
|
|
49231
|
+
if (endpoint) patch.endpoint = endpoint;
|
|
49232
|
+
const site = trimmed(options.site);
|
|
49233
|
+
if (site) patch.site = site;
|
|
49234
|
+
const format = parseFormat(options.format);
|
|
49235
|
+
if (format) patch.format = format;
|
|
49236
|
+
const headers = await resolveHeaders(options);
|
|
49237
|
+
if (headers.length > 0) patch.headers = wireHeaders(headers);
|
|
49238
|
+
const sources = parseSources(options.sources);
|
|
49239
|
+
if (sources) patch.sources = sources;
|
|
49240
|
+
const minSeverity = parseSeverity(options.minSeverity);
|
|
49241
|
+
if (minSeverity) patch.minSeverity = minSeverity;
|
|
49242
|
+
const agents = parseAgents(options.agents);
|
|
49243
|
+
if (agents) patch.agents = agents;
|
|
49244
|
+
const environments = parseEnvironments(options.environments);
|
|
49245
|
+
if (environments) patch.environments = environments;
|
|
49246
|
+
const sampling = parseSampling(options.sampling);
|
|
49247
|
+
if (sampling) patch.sampling = sampling;
|
|
49248
|
+
if (options.includeContent === false) {
|
|
49249
|
+
if ((sources ?? []).some((source) => LOG_DRAIN_CONTENT_SOURCES.includes(source))) {
|
|
49250
|
+
throw CliError.usage("--no-include-content cannot be combined with a content source in the same update.", "Send the sources first, then --no-include-content \u2014 or drop the content sources");
|
|
49251
|
+
}
|
|
49252
|
+
patch.includeContent = false;
|
|
49253
|
+
} else if (wantsContent(options, sources)) {
|
|
49254
|
+
patch.includeContent = true;
|
|
49255
|
+
patch.includeContentAck = await acknowledgeContent(options);
|
|
49256
|
+
}
|
|
49257
|
+
if (Object.keys(patch).length === 0) {
|
|
49258
|
+
throw CliError.usage("Nothing to update \u2014 no field flags were given.", listHint("Changeable", [
|
|
49259
|
+
"--name",
|
|
49260
|
+
"--endpoint",
|
|
49261
|
+
"--site",
|
|
49262
|
+
"--format",
|
|
49263
|
+
"--header / --header-from-env",
|
|
49264
|
+
"--sources",
|
|
49265
|
+
"--min-severity",
|
|
49266
|
+
"--agents",
|
|
49267
|
+
"--environments",
|
|
49268
|
+
"--sampling",
|
|
49269
|
+
"--include-content"
|
|
49270
|
+
]));
|
|
49271
|
+
}
|
|
49272
|
+
const drain = await drainsCall(() => drainsApiFor(context).updateDrain(drainId, patch));
|
|
49273
|
+
if (options.json) {
|
|
49274
|
+
printJson({
|
|
49275
|
+
drain
|
|
49276
|
+
});
|
|
49277
|
+
return;
|
|
49278
|
+
}
|
|
49279
|
+
writeSuccess(`\u2705 Updated ${drain.name} (${drain.id})`);
|
|
49280
|
+
writeInfo(` state ${drain.state}`);
|
|
49281
|
+
if (drain.state === "pending_verification") {
|
|
49282
|
+
writeInfo(" The destination changed, so delivery is paused until the drain is verified again.");
|
|
49283
|
+
writeInfo(" Records keep buffering while you do.");
|
|
49284
|
+
writeHintBlock({
|
|
49285
|
+
headline: "Next:",
|
|
49286
|
+
lines: [
|
|
49287
|
+
{
|
|
49288
|
+
label: "Verify",
|
|
49289
|
+
command: `lua drains verify ${drain.id}`
|
|
49290
|
+
}
|
|
49291
|
+
]
|
|
49292
|
+
});
|
|
49293
|
+
}
|
|
49294
|
+
}
|
|
49295
|
+
__name(updateDrainCore, "updateDrainCore");
|
|
49296
|
+
async function deleteDrainCore(context, drainId, options) {
|
|
49297
|
+
if (!options.yes) {
|
|
49298
|
+
if (isCiModeEnabled()) {
|
|
49299
|
+
throw CliError.usage(`Deleting ${drainId} needs a confirmation; pass --yes to give it non-interactively.`, "Nothing was deleted");
|
|
49300
|
+
}
|
|
49301
|
+
writeInfo(`Deleting a drain purges the destination's stored credentials and drops its queued records.`);
|
|
49302
|
+
const answer = await safePrompt([
|
|
49303
|
+
{
|
|
49304
|
+
type: "confirm",
|
|
49305
|
+
name: "confirmed",
|
|
49306
|
+
message: `Delete drain ${drainId}?`,
|
|
49307
|
+
default: false
|
|
49308
|
+
}
|
|
49309
|
+
]);
|
|
49310
|
+
if (!answer?.confirmed) {
|
|
49311
|
+
throw CliError.usage("Cancelled \u2014 nothing was deleted.");
|
|
49312
|
+
}
|
|
49313
|
+
}
|
|
49314
|
+
await drainsCall(() => drainsApiFor(context).deleteDrain(drainId));
|
|
49315
|
+
if (options.json) {
|
|
49316
|
+
printJson({
|
|
49317
|
+
id: drainId,
|
|
49318
|
+
deleted: true
|
|
49319
|
+
});
|
|
49320
|
+
return;
|
|
49321
|
+
}
|
|
49322
|
+
writeSuccess(`\u2705 Deleted drain ${drainId}`);
|
|
49323
|
+
writeInfo(" Stored credentials were purged and queued records were dropped.");
|
|
49324
|
+
}
|
|
49325
|
+
__name(deleteDrainCore, "deleteDrainCore");
|
|
49326
|
+
async function awaitTestDelivery(api, drainId, batchId) {
|
|
49327
|
+
for (let attempt = 0; attempt < DRAIN_POLL.testAttempts; attempt++) {
|
|
49328
|
+
await DRAIN_POLL.sleep(DRAIN_POLL.intervalMs);
|
|
49329
|
+
const page = await drainsCall(() => api.listDeliveries(drainId, {
|
|
49330
|
+
kind: "test",
|
|
49331
|
+
limit: 20
|
|
49332
|
+
}));
|
|
49333
|
+
const row2 = (page.deliveries ?? []).find((delivery) => delivery.batchId === batchId);
|
|
49334
|
+
if (row2) return row2;
|
|
49335
|
+
}
|
|
49336
|
+
return null;
|
|
49337
|
+
}
|
|
49338
|
+
__name(awaitTestDelivery, "awaitTestDelivery");
|
|
49339
|
+
async function testDrainCore(context, drainId, options) {
|
|
49340
|
+
const api = drainsApiFor(context);
|
|
49341
|
+
const started = await drainsCall(() => api.testDrain(drainId));
|
|
49342
|
+
if (!options.json) writeInfo(`Sent one test record to ${drainId} (batch ${started.batchId}) \u2014 waiting for it\u2026`);
|
|
49343
|
+
const attempt = await awaitTestDelivery(api, drainId, started.batchId);
|
|
49344
|
+
const delivered = attempt?.ok === true;
|
|
49345
|
+
if (options.json) {
|
|
49346
|
+
printJson({
|
|
49347
|
+
batchId: started.batchId,
|
|
49348
|
+
statusCode: attempt?.statusCode ?? null,
|
|
49349
|
+
latencyMs: attempt?.latencyMs ?? null,
|
|
49350
|
+
responseExcerpt: attempt?.responseExcerpt ?? null,
|
|
49351
|
+
ok: delivered,
|
|
49352
|
+
errorClass: attempt?.errorClass ?? null,
|
|
49353
|
+
...attempt ? {} : {
|
|
49354
|
+
pending: true
|
|
49355
|
+
}
|
|
49356
|
+
});
|
|
49357
|
+
} else if (!attempt) {
|
|
49358
|
+
writeInfo(`\u23F3 No delivery attempt recorded yet for batch ${started.batchId}.`);
|
|
49359
|
+
writeHintBlock({
|
|
49360
|
+
headline: "Read it when it lands:",
|
|
49361
|
+
lines: [
|
|
49362
|
+
{
|
|
49363
|
+
label: "Attempts",
|
|
49364
|
+
command: `lua drains deliveries ${drainId} --kind test`
|
|
49365
|
+
}
|
|
49366
|
+
],
|
|
49367
|
+
when: "partial"
|
|
49368
|
+
});
|
|
49369
|
+
} else {
|
|
49370
|
+
const status = attempt.statusCode === void 0 ? "\u2014" : String(attempt.statusCode);
|
|
49371
|
+
const latency = attempt.latencyMs === void 0 ? "\u2014" : `${attempt.latencyMs} ms`;
|
|
49372
|
+
if (delivered) writeSuccess(`\u2705 Delivered \u2014 HTTP ${status} in ${latency}`);
|
|
49373
|
+
else writeInfo(`Not delivered \u2014 HTTP ${status} in ${latency}${attempt.errorClass ? ` (${attempt.errorClass})` : ""}`);
|
|
49374
|
+
if (attempt.responseExcerpt) writeInfo(` response: ${attempt.responseExcerpt}`);
|
|
49375
|
+
}
|
|
49376
|
+
if (!delivered) process.exitCode = CLI_EXIT.ERROR;
|
|
49377
|
+
}
|
|
49378
|
+
__name(testDrainCore, "testDrainCore");
|
|
49379
|
+
async function awaitVerification(api, drainId, previousAttemptedAt) {
|
|
49380
|
+
for (let attempt = 0; attempt < DRAIN_POLL.verifyAttempts; attempt++) {
|
|
49381
|
+
await DRAIN_POLL.sleep(DRAIN_POLL.intervalMs);
|
|
49382
|
+
const drain = await drainsCall(() => api.getDrain(drainId));
|
|
49383
|
+
const verification = drain.verification;
|
|
49384
|
+
if (verification?.outcome && verification.attemptedAt !== previousAttemptedAt) return drain;
|
|
49385
|
+
}
|
|
49386
|
+
return null;
|
|
49387
|
+
}
|
|
49388
|
+
__name(awaitVerification, "awaitVerification");
|
|
49389
|
+
async function verifyDrainCore(context, drainId, options) {
|
|
49390
|
+
const api = drainsApiFor(context);
|
|
49391
|
+
const before = await drainsCall(() => api.getDrain(drainId));
|
|
49392
|
+
const started = await drainsCall(() => api.verifyDrain(drainId));
|
|
49393
|
+
if (!options.json) writeInfo(`Verifying ${drainId} \u2014 waiting for your endpoint to answer\u2026`);
|
|
49394
|
+
const drain = await awaitVerification(api, drainId, before.verification?.attemptedAt);
|
|
49395
|
+
const verification = drain?.verification;
|
|
49396
|
+
const outcome = verification?.outcome;
|
|
49397
|
+
const verified = outcome === "ok";
|
|
49398
|
+
const line = outcome ? VERIFY_OUTCOME_TEXT[outcome] : "no result yet";
|
|
49399
|
+
if (options.json) {
|
|
49400
|
+
printJson({
|
|
49401
|
+
verificationId: started.verificationId,
|
|
49402
|
+
expiresAt: started.expiresAt,
|
|
49403
|
+
outcome: outcome ?? null,
|
|
49404
|
+
message: line,
|
|
49405
|
+
statusCode: verification?.statusCode ?? null,
|
|
49406
|
+
latencyMs: verification?.latencyMs ?? null,
|
|
49407
|
+
responseExcerpt: verification?.responseExcerpt ?? null,
|
|
49408
|
+
state: drain?.state ?? null,
|
|
49409
|
+
verifiedAt: drain?.verifiedAt ?? null,
|
|
49410
|
+
verified,
|
|
49411
|
+
...drain ? {} : {
|
|
49412
|
+
pending: true
|
|
49413
|
+
}
|
|
49414
|
+
});
|
|
49415
|
+
} else {
|
|
49416
|
+
const status = verification?.statusCode === void 0 ? "\u2014" : String(verification.statusCode);
|
|
49417
|
+
const latency = verification?.latencyMs === void 0 ? "\u2014" : `${verification.latencyMs} ms`;
|
|
49418
|
+
if (verified) {
|
|
49419
|
+
writeSuccess(`\u2705 Verified \u2014 HTTP ${status} in ${latency}`);
|
|
49420
|
+
writeInfo(` state ${drain?.state ?? "\u2014"} \xB7 verifiedAt ${shortIso(drain?.verifiedAt)}`);
|
|
49421
|
+
} else if (!drain) {
|
|
49422
|
+
writeInfo(`\u23F3 ${line} (attempt ${started.verificationId}, expires ${shortIso(started.expiresAt)}).`);
|
|
49423
|
+
writeHintBlock({
|
|
49424
|
+
headline: "Read it when it lands:",
|
|
49425
|
+
lines: [
|
|
49426
|
+
{
|
|
49427
|
+
label: "Drain",
|
|
49428
|
+
command: `lua drains status ${drainId}`
|
|
49429
|
+
}
|
|
49430
|
+
],
|
|
49431
|
+
when: "partial"
|
|
49432
|
+
});
|
|
49433
|
+
} else {
|
|
49434
|
+
writeInfo(`Not verified: ${line} \u2014 HTTP ${status} in ${latency}`);
|
|
49435
|
+
if (verification?.responseExcerpt) writeInfo(` response: ${verification.responseExcerpt}`);
|
|
49436
|
+
if (outcome === "token_not_echoed") {
|
|
49437
|
+
writeInfo(" Your receiver answered, but did not repeat the X-Lua-Verify header on its response.");
|
|
49438
|
+
}
|
|
49439
|
+
}
|
|
49440
|
+
}
|
|
49441
|
+
if (!verified) process.exitCode = CLI_EXIT.ERROR;
|
|
49442
|
+
}
|
|
49443
|
+
__name(verifyDrainCore, "verifyDrainCore");
|
|
49444
|
+
async function pauseDrainCore(context, drainId, options) {
|
|
49445
|
+
const reason = trimmed(options.reason);
|
|
49446
|
+
const drain = await drainsCall(() => drainsApiFor(context).pauseDrain(drainId, reason));
|
|
49447
|
+
if (options.json) {
|
|
49448
|
+
printJson({
|
|
49449
|
+
drain
|
|
49450
|
+
});
|
|
49451
|
+
return;
|
|
49452
|
+
}
|
|
49453
|
+
writeSuccess(`\u2705 Paused ${drain.name} (${drain.id})`);
|
|
49454
|
+
writeInfo(` state ${drain.state}${reason ? ` \xB7 reason "${reason}"` : ""}`);
|
|
49455
|
+
writeInfo(" Records keep buffering while the drain is paused; nothing is delivered.");
|
|
49456
|
+
writeHintBlock({
|
|
49457
|
+
headline: "Next:",
|
|
49458
|
+
lines: [
|
|
49459
|
+
{
|
|
49460
|
+
label: "Resume",
|
|
49461
|
+
command: `lua drains resume ${drain.id}`
|
|
49462
|
+
}
|
|
49463
|
+
]
|
|
49464
|
+
});
|
|
49465
|
+
}
|
|
49466
|
+
__name(pauseDrainCore, "pauseDrainCore");
|
|
49467
|
+
async function resumeDrainCore(context, drainId, options) {
|
|
49468
|
+
const drain = await drainsCall(() => drainsApiFor(context).resumeDrain(drainId));
|
|
49469
|
+
if (options.json) {
|
|
49470
|
+
printJson({
|
|
49471
|
+
drain
|
|
49472
|
+
});
|
|
49473
|
+
return;
|
|
49474
|
+
}
|
|
49475
|
+
writeSuccess(`\u2705 Resumed ${drain.name} (${drain.id})`);
|
|
49476
|
+
writeInfo(` state ${drain.state} \u2014 a resumed drain proves itself before it reads healthy again.`);
|
|
49477
|
+
writeHintBlock({
|
|
49478
|
+
headline: "Next:",
|
|
49479
|
+
lines: [
|
|
49480
|
+
{
|
|
49481
|
+
label: "Health",
|
|
49482
|
+
command: `lua drains status ${drain.id}`
|
|
49483
|
+
}
|
|
49484
|
+
]
|
|
49485
|
+
});
|
|
49486
|
+
}
|
|
49487
|
+
__name(resumeDrainCore, "resumeDrainCore");
|
|
49488
|
+
async function rotateSecretCore(context, drainId, options) {
|
|
49489
|
+
const finalize = options.finalize === true;
|
|
49490
|
+
const answer = await drainsCall(() => drainsApiFor(context).rotateSecret(drainId, finalize));
|
|
49491
|
+
if (finalize) {
|
|
49492
|
+
const drain = answer;
|
|
49493
|
+
if (options.json) {
|
|
49494
|
+
printJson({
|
|
49495
|
+
drain
|
|
49496
|
+
});
|
|
49497
|
+
return;
|
|
49498
|
+
}
|
|
49499
|
+
writeSuccess(`\u2705 Rotation window closed for ${drain.name ?? drainId}`);
|
|
49500
|
+
writeInfo(" Deliveries now carry the new signature only.");
|
|
49501
|
+
return;
|
|
49502
|
+
}
|
|
49503
|
+
const rotated = answer;
|
|
49504
|
+
if (options.json) {
|
|
49505
|
+
printJson({
|
|
49506
|
+
secret: rotated.secret,
|
|
49507
|
+
rotation: rotated.rotation
|
|
49508
|
+
});
|
|
49509
|
+
return;
|
|
49510
|
+
}
|
|
49511
|
+
writeSuccess(`\u2705 Rotated the signing secret for ${drainId}`);
|
|
49512
|
+
writeInfo("");
|
|
49513
|
+
writeInfo("\u{1F511} New signing secret \u2014 shown once, and never again. Store it now:");
|
|
49514
|
+
writeInfo(` ${rotated.secret}`);
|
|
49515
|
+
writeInfo("");
|
|
49516
|
+
writeInfo(` Both secrets are accepted until ${shortIso(rotated.rotation?.expiresAt)}; every batch in that`);
|
|
49517
|
+
writeInfo(" window carries two signatures, so deploy the new value and then close the window.");
|
|
49518
|
+
writeHintBlock({
|
|
49519
|
+
headline: "When the receiver has the new value:",
|
|
49520
|
+
lines: [
|
|
49521
|
+
{
|
|
49522
|
+
label: "Close early",
|
|
49523
|
+
command: `lua drains rotate-secret ${drainId} --finalize`
|
|
49524
|
+
}
|
|
49525
|
+
]
|
|
49526
|
+
});
|
|
49527
|
+
}
|
|
49528
|
+
__name(rotateSecretCore, "rotateSecretCore");
|
|
49529
|
+
|
|
49530
|
+
// src/commands/drains.ts
|
|
49531
|
+
var DRAIN_ACTIONS = [
|
|
49532
|
+
"list",
|
|
49533
|
+
"status",
|
|
49534
|
+
"deliveries",
|
|
49535
|
+
"create",
|
|
49536
|
+
"update",
|
|
49537
|
+
"delete",
|
|
49538
|
+
"test",
|
|
49539
|
+
"verify",
|
|
49540
|
+
"pause",
|
|
49541
|
+
"resume",
|
|
49542
|
+
"rotate-secret"
|
|
49543
|
+
];
|
|
49544
|
+
var MISSING_SCOPE_MESSAGE = "Missing scope: logs:manage. Create a key with that scope (lua auth key) or ask an org admin.";
|
|
49545
|
+
var DRAINS_FAILING_EXIT = 2;
|
|
49546
|
+
var DELIVERY_KINDS = [
|
|
49547
|
+
"batch",
|
|
49548
|
+
"test",
|
|
49549
|
+
"verify",
|
|
49550
|
+
"heartbeat",
|
|
49551
|
+
"dropped",
|
|
49552
|
+
"truncated"
|
|
49553
|
+
];
|
|
49554
|
+
var DEFAULT_DELIVERY_LIMIT = 20;
|
|
49555
|
+
var MAX_DELIVERY_LIMIT = 100;
|
|
49556
|
+
var MAX_TABLE_WIDTH = 100;
|
|
49557
|
+
async function resolveDrainsContext(options) {
|
|
49558
|
+
const apiKey = await requireAuth();
|
|
49559
|
+
const flagOrg = typeof options.org === "string" ? options.org.trim() : "";
|
|
49560
|
+
if (flagOrg) return {
|
|
49561
|
+
orgId: flagOrg,
|
|
49562
|
+
apiKey
|
|
49563
|
+
};
|
|
49564
|
+
const config = readYamlConfig();
|
|
49565
|
+
const projectOrg = config?.agent?.orgId;
|
|
49566
|
+
if (projectOrg) return {
|
|
49567
|
+
orgId: projectOrg,
|
|
49568
|
+
agentId: config?.agent?.agentId,
|
|
49569
|
+
apiKey
|
|
49570
|
+
};
|
|
49571
|
+
return {
|
|
49572
|
+
orgId: await orgFromCredential(apiKey),
|
|
49573
|
+
apiKey
|
|
49574
|
+
};
|
|
49575
|
+
}
|
|
49576
|
+
__name(resolveDrainsContext, "resolveDrainsContext");
|
|
49577
|
+
async function orgFromCredential(apiKey) {
|
|
49578
|
+
const { authorization } = await resolveCredentialOperationalContext(apiKey);
|
|
49579
|
+
const orgs = (authorization.orgs ?? []).filter((org) => !org.archived);
|
|
49580
|
+
if (orgs.length === 1) return orgs[0].orgId;
|
|
49581
|
+
if (orgs.length === 0) {
|
|
49582
|
+
throw CliError.usage("This credential does not reach any organization, so there is no drain to read.", "Ask an org admin for access, or run the command from a Lua project directory");
|
|
49583
|
+
}
|
|
49584
|
+
throw CliError.usage(`This credential reaches ${orgs.length} organizations \u2014 name one with --org <id>.`, joinHint(listHint("Organizations", orgs.map((org) => `${org.orgId}${org.name ? ` \u2014 ${org.name}` : ""}`)), "Inside a Lua project directory the org comes from lua.skill.yaml"));
|
|
49585
|
+
}
|
|
49586
|
+
__name(orgFromCredential, "orgFromCredential");
|
|
49587
|
+
function drainsApiFor(context) {
|
|
49588
|
+
return new DrainsApi(BASE_URLS.API, context.apiKey, context.orgId);
|
|
49589
|
+
}
|
|
49590
|
+
__name(drainsApiFor, "drainsApiFor");
|
|
49591
|
+
function drainRefusalMessage(error) {
|
|
49592
|
+
const message = error?.message || "The log drains API refused the request.";
|
|
49593
|
+
const code = error?.code;
|
|
49594
|
+
const field = error?.field;
|
|
49595
|
+
const line = code ? `${code}: ${message}` : message;
|
|
49596
|
+
return field ? `${line} (field: ${field})` : line;
|
|
49597
|
+
}
|
|
49598
|
+
__name(drainRefusalMessage, "drainRefusalMessage");
|
|
49599
|
+
async function drainsCall(call) {
|
|
49600
|
+
let response;
|
|
49601
|
+
try {
|
|
49602
|
+
response = await call();
|
|
49603
|
+
} catch (error) {
|
|
49604
|
+
if (CliError.isCliError(error) && error.statusCode === 403) {
|
|
49605
|
+
throw CliError.forbidden(MISSING_SCOPE_MESSAGE);
|
|
49606
|
+
}
|
|
49607
|
+
throw error;
|
|
49608
|
+
}
|
|
49609
|
+
if (response.success && response.data !== void 0) return response.data;
|
|
49610
|
+
if (response.error?.statusCode === 403) throw CliError.forbidden(MISSING_SCOPE_MESSAGE);
|
|
49611
|
+
throw CliError.fromStatus(response.error?.statusCode, drainRefusalMessage(response.error), void 0, apiErrorDetail(response.error));
|
|
49612
|
+
}
|
|
49613
|
+
__name(drainsCall, "drainsCall");
|
|
49614
|
+
function printJson2(payload) {
|
|
49615
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
49616
|
+
}
|
|
49617
|
+
__name(printJson2, "printJson");
|
|
49618
|
+
function tableOverhead(columns) {
|
|
49619
|
+
return 3 * columns + 1;
|
|
49620
|
+
}
|
|
49621
|
+
__name(tableOverhead, "tableOverhead");
|
|
49622
|
+
function clip(value3, width) {
|
|
49623
|
+
if (value3.length <= width) return value3;
|
|
49624
|
+
return width <= 1 ? value3.slice(0, width) : `${value3.slice(0, width - 1)}\u2026`;
|
|
49625
|
+
}
|
|
49626
|
+
__name(clip, "clip");
|
|
49627
|
+
function renderFittedTable(headers, rows3, options = {}) {
|
|
49628
|
+
if (rows3.length === 0) return renderTable(headers, rows3);
|
|
49629
|
+
const { maxWidth = MAX_TABLE_WIDTH, shrinkFirst = [], softFloor = 12 } = options;
|
|
49630
|
+
const budget = maxWidth - tableOverhead(headers.length);
|
|
49631
|
+
const hardFloors = headers.map((header) => header.length);
|
|
49632
|
+
const widths = headers.map((header, i) => Math.max(header.length, ...rows3.map((row2) => (row2[i] ?? "").length)));
|
|
49633
|
+
let total = widths.reduce((sum, width) => sum + width, 0);
|
|
49634
|
+
const shrink = /* @__PURE__ */ __name((candidates, floorOf) => {
|
|
49635
|
+
for (; ; ) {
|
|
49636
|
+
if (total <= budget) return;
|
|
49637
|
+
let widest = -1;
|
|
49638
|
+
for (const i of candidates) {
|
|
49639
|
+
if (widths[i] <= floorOf(i)) continue;
|
|
49640
|
+
if (widest === -1 || widths[i] > widths[widest]) widest = i;
|
|
49641
|
+
}
|
|
49642
|
+
if (widest === -1) return;
|
|
49643
|
+
widths[widest] -= 1;
|
|
49644
|
+
total -= 1;
|
|
49645
|
+
}
|
|
49646
|
+
}, "shrink");
|
|
49647
|
+
shrink(shrinkFirst, (i) => Math.max(hardFloors[i], softFloor));
|
|
49648
|
+
shrink(shrinkFirst, (i) => hardFloors[i]);
|
|
49649
|
+
shrink(headers.map((_, i) => i), (i) => hardFloors[i]);
|
|
49650
|
+
return renderTable(headers, rows3.map((row2) => row2.map((cell, i) => clip(cell ?? "", widths[i]))));
|
|
49651
|
+
}
|
|
49652
|
+
__name(renderFittedTable, "renderFittedTable");
|
|
49653
|
+
function shortIso2(value3) {
|
|
49654
|
+
if (typeof value3 !== "string" || value3.length === 0) return "\u2014";
|
|
49655
|
+
const date = new Date(value3);
|
|
49656
|
+
if (Number.isNaN(date.getTime())) return value3;
|
|
49657
|
+
return date.toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
49658
|
+
}
|
|
49659
|
+
__name(shortIso2, "shortIso");
|
|
49660
|
+
function environmentsOf(drain) {
|
|
49661
|
+
const environments = drain.selectors?.environments ?? [];
|
|
49662
|
+
return environments.length > 0 ? environments.join(",") : "\u2014";
|
|
49663
|
+
}
|
|
49664
|
+
__name(environmentsOf, "environmentsOf");
|
|
49665
|
+
function agentsOf(drain) {
|
|
49666
|
+
const agents = drain.selectors?.agents;
|
|
49667
|
+
if (agents === "*" || agents === void 0) return "all";
|
|
49668
|
+
return String(agents.length);
|
|
49669
|
+
}
|
|
49670
|
+
__name(agentsOf, "agentsOf");
|
|
49671
|
+
function drainsTable(drains) {
|
|
49672
|
+
return renderFittedTable(
|
|
49673
|
+
[
|
|
49674
|
+
"NAME",
|
|
49675
|
+
"TYPE",
|
|
49676
|
+
"STATE",
|
|
49677
|
+
"ENV",
|
|
49678
|
+
"AGENTS",
|
|
49679
|
+
"BACKLOG",
|
|
49680
|
+
"LAST SUCCESS"
|
|
49681
|
+
],
|
|
49682
|
+
drains.map((drain) => [
|
|
49683
|
+
drain.name ?? "",
|
|
49684
|
+
drain.type ?? "",
|
|
49685
|
+
drain.state ?? "",
|
|
49686
|
+
environmentsOf(drain),
|
|
49687
|
+
agentsOf(drain),
|
|
49688
|
+
String(drain.health?.backlog ?? 0),
|
|
49689
|
+
shortIso2(drain.health?.lastSuccessAt)
|
|
49690
|
+
]),
|
|
49691
|
+
{
|
|
49692
|
+
shrinkFirst: [
|
|
49693
|
+
0,
|
|
49694
|
+
3
|
|
49695
|
+
]
|
|
49696
|
+
}
|
|
49697
|
+
// NAME and ENV give way before a state, a count or a timestamp
|
|
49698
|
+
);
|
|
49699
|
+
}
|
|
49700
|
+
__name(drainsTable, "drainsTable");
|
|
49701
|
+
function statusTable(drains) {
|
|
49702
|
+
return renderFittedTable([
|
|
49703
|
+
"NAME",
|
|
49704
|
+
"STATE",
|
|
49705
|
+
"BACKLOG",
|
|
49706
|
+
"DELIVERED",
|
|
49707
|
+
"DROPPED",
|
|
49708
|
+
"REJECTED",
|
|
49709
|
+
"P50 MS",
|
|
49710
|
+
"QUOTA",
|
|
49711
|
+
"LAST SUCCESS"
|
|
49712
|
+
], drains.map((drain) => [
|
|
49713
|
+
drain.name ?? "",
|
|
49714
|
+
drain.state ?? "",
|
|
49715
|
+
String(drain.health?.backlog ?? 0),
|
|
49716
|
+
String(drain.health?.deliveredCount24h ?? 0),
|
|
49717
|
+
String(drain.health?.droppedCount24h ?? 0),
|
|
49718
|
+
String(drain.health?.rejectedCount24h ?? 0),
|
|
49719
|
+
drain.health?.p50LatencyMs === null || drain.health?.p50LatencyMs === void 0 ? "\u2014" : String(drain.health.p50LatencyMs),
|
|
49720
|
+
quotaRatio(drain),
|
|
49721
|
+
shortIso2(drain.health?.lastSuccessAt)
|
|
49722
|
+
]), {
|
|
49723
|
+
shrinkFirst: [
|
|
49724
|
+
0
|
|
49725
|
+
]
|
|
49726
|
+
});
|
|
49727
|
+
}
|
|
49728
|
+
__name(statusTable, "statusTable");
|
|
49729
|
+
function quotaRatio(drain) {
|
|
49730
|
+
const quota = drain.quota;
|
|
49731
|
+
if (!quota || !quota.eventsPerDay) return "\u2014";
|
|
49732
|
+
const ratio = quota.eventsPerDay > 0 ? (quota.usedEvents ?? 0) / quota.eventsPerDay : 0;
|
|
49733
|
+
const percent = Math.round(ratio * 1e3) / 10;
|
|
49734
|
+
return quota.degradation && quota.degradation !== "none" ? `${percent}% ${quota.degradation}` : `${percent}%`;
|
|
49735
|
+
}
|
|
49736
|
+
__name(quotaRatio, "quotaRatio");
|
|
49737
|
+
function printDrainDetail(drain) {
|
|
49738
|
+
const health = drain.health ?? {};
|
|
49739
|
+
const quota = drain.quota ?? {};
|
|
49740
|
+
const rows3 = [
|
|
49741
|
+
[
|
|
49742
|
+
"type",
|
|
49743
|
+
drain.type ?? "\u2014"
|
|
49744
|
+
],
|
|
49745
|
+
[
|
|
49746
|
+
"state",
|
|
49747
|
+
drain.state ?? "\u2014"
|
|
49748
|
+
],
|
|
49749
|
+
[
|
|
49750
|
+
"endpoint",
|
|
49751
|
+
drain.endpoint ?? "\u2014"
|
|
49752
|
+
],
|
|
49753
|
+
[
|
|
49754
|
+
"site",
|
|
49755
|
+
drain.site ?? "\u2014"
|
|
49756
|
+
],
|
|
49757
|
+
[
|
|
49758
|
+
"format",
|
|
49759
|
+
drain.format ?? "\u2014"
|
|
49760
|
+
],
|
|
49761
|
+
[
|
|
49762
|
+
"environments",
|
|
49763
|
+
environmentsOf(drain)
|
|
49764
|
+
],
|
|
49765
|
+
[
|
|
49766
|
+
"agents",
|
|
49767
|
+
drain.selectors?.agents === "*" ? "all" : (drain.selectors?.agents ?? []).join(",") || "\u2014"
|
|
49768
|
+
],
|
|
49769
|
+
[
|
|
49770
|
+
"minSeverity",
|
|
49771
|
+
drain.selectors?.minSeverity ?? "\u2014"
|
|
49772
|
+
],
|
|
49773
|
+
[
|
|
49774
|
+
"includeContent",
|
|
49775
|
+
String(drain.selectors?.includeContent ?? false)
|
|
49776
|
+
],
|
|
49777
|
+
[
|
|
49778
|
+
"verifiedAt",
|
|
49779
|
+
shortIso2(drain.verifiedAt)
|
|
49780
|
+
],
|
|
49781
|
+
[
|
|
49782
|
+
"lastSuccessAt",
|
|
49783
|
+
shortIso2(health.lastSuccessAt)
|
|
49784
|
+
],
|
|
49785
|
+
[
|
|
49786
|
+
"lastFailureAt",
|
|
49787
|
+
shortIso2(health.lastFailureAt)
|
|
49788
|
+
],
|
|
49789
|
+
[
|
|
49790
|
+
"lastStatusCode",
|
|
49791
|
+
health.lastStatusCode === void 0 ? "\u2014" : String(health.lastStatusCode)
|
|
49792
|
+
],
|
|
49793
|
+
[
|
|
49794
|
+
"lastError",
|
|
49795
|
+
health.lastError ?? "\u2014"
|
|
49796
|
+
],
|
|
49797
|
+
[
|
|
49798
|
+
"backlog",
|
|
49799
|
+
String(health.backlog ?? 0)
|
|
49800
|
+
],
|
|
49801
|
+
[
|
|
49802
|
+
"backlogBytes",
|
|
49803
|
+
String(health.backlogBytes ?? 0)
|
|
49804
|
+
],
|
|
49805
|
+
[
|
|
49806
|
+
"deliveredCount24h",
|
|
49807
|
+
String(health.deliveredCount24h ?? 0)
|
|
49808
|
+
],
|
|
49809
|
+
[
|
|
49810
|
+
"droppedCount24h",
|
|
49811
|
+
String(health.droppedCount24h ?? 0)
|
|
49812
|
+
],
|
|
49813
|
+
[
|
|
49814
|
+
"rejectedCount24h",
|
|
49815
|
+
String(health.rejectedCount24h ?? 0)
|
|
49816
|
+
],
|
|
49817
|
+
[
|
|
49818
|
+
"p50LatencyMs",
|
|
49819
|
+
health.p50LatencyMs === null || health.p50LatencyMs === void 0 ? "\u2014" : String(health.p50LatencyMs)
|
|
49820
|
+
],
|
|
49821
|
+
[
|
|
49822
|
+
"scrubHits24h",
|
|
49823
|
+
String(health.scrubHits24h ?? 0)
|
|
49824
|
+
],
|
|
49825
|
+
[
|
|
49826
|
+
"pauseReason",
|
|
49827
|
+
health.pauseReason ?? "\u2014"
|
|
49828
|
+
],
|
|
49829
|
+
[
|
|
49830
|
+
"usedEvents",
|
|
49831
|
+
`${quota.usedEvents ?? 0} / ${quota.eventsPerDay ?? 0}`
|
|
49832
|
+
],
|
|
49833
|
+
[
|
|
49834
|
+
"usedBytes",
|
|
49835
|
+
`${quota.usedBytes ?? 0} / ${quota.bytesPerDay ?? 0}`
|
|
49836
|
+
],
|
|
49837
|
+
[
|
|
49838
|
+
"degradation",
|
|
49839
|
+
quota.degradation ?? "\u2014"
|
|
49840
|
+
],
|
|
49841
|
+
[
|
|
49842
|
+
"resetsAt",
|
|
49843
|
+
shortIso2(quota.resetsAt)
|
|
49844
|
+
]
|
|
49845
|
+
];
|
|
49846
|
+
const label2 = Math.max(...rows3.map(([key]) => key.length));
|
|
49847
|
+
console.log(`
|
|
49848
|
+
\u{1F6B0} ${drain.name} (${drain.id})`);
|
|
49849
|
+
for (const [key, value3] of rows3) {
|
|
49850
|
+
console.log(` ${key.padEnd(label2)} ${clip(value3, MAX_TABLE_WIDTH - label2 - 5)}`);
|
|
49851
|
+
}
|
|
49852
|
+
console.log("");
|
|
49853
|
+
}
|
|
49854
|
+
__name(printDrainDetail, "printDrainDetail");
|
|
49855
|
+
function statusView(drain) {
|
|
49856
|
+
return {
|
|
49857
|
+
id: drain.id,
|
|
49858
|
+
name: drain.name,
|
|
49859
|
+
state: drain.state,
|
|
49860
|
+
health: drain.health,
|
|
49861
|
+
quota: drain.quota
|
|
49862
|
+
};
|
|
49863
|
+
}
|
|
49864
|
+
__name(statusView, "statusView");
|
|
49865
|
+
function str(value3) {
|
|
49866
|
+
if (value3 === void 0 || value3 === null || value3 === "") return "\u2014";
|
|
49867
|
+
return String(value3);
|
|
49868
|
+
}
|
|
49869
|
+
__name(str, "str");
|
|
49870
|
+
function deliveriesTable(deliveries) {
|
|
49871
|
+
return renderFittedTable(
|
|
49872
|
+
[
|
|
49873
|
+
"STARTED",
|
|
49874
|
+
"KIND",
|
|
49875
|
+
"TRY",
|
|
49876
|
+
"OK",
|
|
49877
|
+
"STATUS",
|
|
49878
|
+
"MS",
|
|
49879
|
+
"RECORDS",
|
|
49880
|
+
"BYTES",
|
|
49881
|
+
"ERROR"
|
|
49882
|
+
],
|
|
49883
|
+
deliveries.map((delivery) => [
|
|
49884
|
+
shortIso2(delivery.startedAt),
|
|
49885
|
+
str(delivery.kind),
|
|
49886
|
+
str(delivery.attempt),
|
|
49887
|
+
delivery.ok === true ? "yes" : "no",
|
|
49888
|
+
str(delivery.statusCode),
|
|
49889
|
+
str(delivery.latencyMs),
|
|
49890
|
+
str(delivery.recordCount),
|
|
49891
|
+
str(delivery.bytes),
|
|
49892
|
+
str(delivery.errorClass)
|
|
49893
|
+
]),
|
|
49894
|
+
{
|
|
49895
|
+
shrinkFirst: [
|
|
49896
|
+
8
|
|
49897
|
+
],
|
|
49898
|
+
softFloor: 8
|
|
49899
|
+
}
|
|
49900
|
+
// the error class gives way before the timings do
|
|
49901
|
+
);
|
|
49902
|
+
}
|
|
49903
|
+
__name(deliveriesTable, "deliveriesTable");
|
|
49904
|
+
async function listDrainsCore(context, options) {
|
|
49905
|
+
const payload = await drainsCall(() => drainsApiFor(context).listDrains());
|
|
49906
|
+
if (options.json) {
|
|
49907
|
+
printJson2(payload);
|
|
49908
|
+
return;
|
|
49909
|
+
}
|
|
49910
|
+
const drains = payload.drains ?? [];
|
|
49911
|
+
if (drains.length === 0) {
|
|
49912
|
+
writeInfo(`No log drains in ${context.orgId}.`);
|
|
49913
|
+
writeHintBlock({
|
|
49914
|
+
headline: "Send this org\u2019s logs somewhere you own:",
|
|
49915
|
+
lines: [
|
|
49916
|
+
{
|
|
49917
|
+
label: "Create one",
|
|
49918
|
+
command: "lua drains create"
|
|
49919
|
+
}
|
|
49920
|
+
]
|
|
49921
|
+
});
|
|
49922
|
+
return;
|
|
49923
|
+
}
|
|
49924
|
+
console.log(drainsTable(drains));
|
|
49925
|
+
writeHintBlock({
|
|
49926
|
+
headline: "Next:",
|
|
49927
|
+
lines: [
|
|
49928
|
+
{
|
|
49929
|
+
label: "Health",
|
|
49930
|
+
command: "lua drains status"
|
|
49931
|
+
},
|
|
49932
|
+
{
|
|
49933
|
+
label: "Attempts",
|
|
49934
|
+
command: `lua drains deliveries ${drains[0].id}`
|
|
49935
|
+
}
|
|
49936
|
+
]
|
|
49937
|
+
});
|
|
49938
|
+
}
|
|
49939
|
+
__name(listDrainsCore, "listDrainsCore");
|
|
49940
|
+
async function statusDrainsCore(context, drainId, options) {
|
|
49941
|
+
const api = drainsApiFor(context);
|
|
49942
|
+
const drains = drainId ? [
|
|
49943
|
+
await drainsCall(() => api.getDrain(drainId))
|
|
49944
|
+
] : (await drainsCall(() => api.listDrains())).drains ?? [];
|
|
49945
|
+
if (options.json) {
|
|
49946
|
+
printJson2({
|
|
49947
|
+
drains: drains.map(statusView)
|
|
49948
|
+
});
|
|
49949
|
+
} else if (drains.length === 0) {
|
|
49950
|
+
writeInfo(`No log drains in ${context.orgId}.`);
|
|
49951
|
+
} else if (drainId) {
|
|
49952
|
+
printDrainDetail(drains[0]);
|
|
49953
|
+
} else {
|
|
49954
|
+
console.log(statusTable(drains));
|
|
49955
|
+
}
|
|
49956
|
+
const failing = drains.filter((drain) => drain.state === "failing");
|
|
49957
|
+
if (failing.length > 0) {
|
|
49958
|
+
if (!options.json) {
|
|
49959
|
+
writeInfo(`\u26A0\uFE0F ${failing.length} drain(s) failing: ${failing.map((drain) => drain.name).join(", ")}`);
|
|
49960
|
+
writeHintBlock({
|
|
49961
|
+
headline: "Why a drain is failing:",
|
|
49962
|
+
lines: [
|
|
49963
|
+
{
|
|
49964
|
+
label: "Attempts",
|
|
49965
|
+
command: `lua drains deliveries ${failing[0].id} --kind batch`
|
|
49966
|
+
}
|
|
49967
|
+
],
|
|
49968
|
+
when: "partial"
|
|
49969
|
+
});
|
|
49970
|
+
}
|
|
49971
|
+
process.exitCode = DRAINS_FAILING_EXIT;
|
|
49972
|
+
}
|
|
49973
|
+
}
|
|
49974
|
+
__name(statusDrainsCore, "statusDrainsCore");
|
|
49975
|
+
async function deliveriesCore(context, drainId, options) {
|
|
49976
|
+
const limit = parseLimit(options.limit);
|
|
49977
|
+
const kind = parseKind(options.kind);
|
|
49978
|
+
const page = await drainsCall(() => drainsApiFor(context).listDeliveries(drainId, {
|
|
49979
|
+
limit,
|
|
49980
|
+
...kind ? {
|
|
49981
|
+
kind
|
|
49982
|
+
} : {}
|
|
49983
|
+
}));
|
|
49984
|
+
if (options.json) {
|
|
49985
|
+
printJson2(page);
|
|
49986
|
+
return;
|
|
49987
|
+
}
|
|
49988
|
+
const deliveries = page.deliveries ?? [];
|
|
49989
|
+
if (deliveries.length === 0) {
|
|
49990
|
+
writeInfo(`No delivery attempts recorded for ${drainId}${kind ? ` (kind ${kind})` : ""}.`);
|
|
49991
|
+
return;
|
|
49992
|
+
}
|
|
49993
|
+
console.log(deliveriesTable(deliveries));
|
|
49994
|
+
if (page.nextCursor) {
|
|
49995
|
+
writeInfo(`\u2026 more attempts available \u2014 raise --limit (max ${MAX_DELIVERY_LIMIT}) or read --json for the cursor.`);
|
|
49996
|
+
}
|
|
49997
|
+
}
|
|
49998
|
+
__name(deliveriesCore, "deliveriesCore");
|
|
49999
|
+
function parseLimit(raw) {
|
|
50000
|
+
if (raw === void 0 || raw === null || `${raw}`.trim() === "") return DEFAULT_DELIVERY_LIMIT;
|
|
50001
|
+
const limit = Number(raw);
|
|
50002
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > MAX_DELIVERY_LIMIT) {
|
|
50003
|
+
throw CliError.usage(`--limit must be a whole number between 1 and ${MAX_DELIVERY_LIMIT} (got "${raw}").`, `Default is ${DEFAULT_DELIVERY_LIMIT}`);
|
|
50004
|
+
}
|
|
50005
|
+
return limit;
|
|
50006
|
+
}
|
|
50007
|
+
__name(parseLimit, "parseLimit");
|
|
50008
|
+
function parseKind(raw) {
|
|
50009
|
+
if (raw === void 0 || raw === null || `${raw}`.trim() === "") return void 0;
|
|
50010
|
+
const kind = `${raw}`.trim().toLowerCase();
|
|
50011
|
+
if (!DELIVERY_KINDS.includes(kind)) {
|
|
50012
|
+
throw CliError.usage(`--kind "${raw}" is not a delivery kind.`, listHint("Valid values", DELIVERY_KINDS));
|
|
50013
|
+
}
|
|
50014
|
+
return kind;
|
|
50015
|
+
}
|
|
50016
|
+
__name(parseKind, "parseKind");
|
|
50017
|
+
async function drainsCommand(action, drainId, cmdObj) {
|
|
50018
|
+
return withErrorHandling(
|
|
50019
|
+
async () => {
|
|
50020
|
+
const options = cmdObj ?? {};
|
|
50021
|
+
const verb = action ? validateOrSuggest("drains.action", action) : "list";
|
|
50022
|
+
const needsId = /* @__PURE__ */ __name((v) => v === "deliveries" || v === "update" || v === "delete" || v === "test" || v === "verify" || v === "pause" || v === "resume" || v === "rotate-secret", "needsId");
|
|
50023
|
+
if (needsId(verb) && !drainId) {
|
|
50024
|
+
throw CliError.usage(`lua drains ${verb} needs a drain id.`, listHint("Run", [
|
|
50025
|
+
"lua drains list"
|
|
50026
|
+
]));
|
|
50027
|
+
}
|
|
50028
|
+
const context = await resolveDrainsContext(options);
|
|
50029
|
+
switch (verb) {
|
|
50030
|
+
case "list":
|
|
50031
|
+
await listDrainsCore(context, options);
|
|
50032
|
+
break;
|
|
50033
|
+
case "status":
|
|
50034
|
+
await statusDrainsCore(context, drainId, options);
|
|
50035
|
+
break;
|
|
50036
|
+
case "deliveries":
|
|
50037
|
+
await deliveriesCore(context, drainId, options);
|
|
50038
|
+
break;
|
|
50039
|
+
case "create":
|
|
50040
|
+
await createDrainCore(context, options);
|
|
50041
|
+
break;
|
|
50042
|
+
case "update":
|
|
50043
|
+
await updateDrainCore(context, drainId, options);
|
|
50044
|
+
break;
|
|
50045
|
+
case "delete":
|
|
50046
|
+
await deleteDrainCore(context, drainId, options);
|
|
50047
|
+
break;
|
|
50048
|
+
case "test":
|
|
50049
|
+
await testDrainCore(context, drainId, options);
|
|
50050
|
+
break;
|
|
50051
|
+
case "verify":
|
|
50052
|
+
await verifyDrainCore(context, drainId, options);
|
|
50053
|
+
break;
|
|
50054
|
+
case "pause":
|
|
50055
|
+
await pauseDrainCore(context, drainId, options);
|
|
50056
|
+
break;
|
|
50057
|
+
case "resume":
|
|
50058
|
+
await resumeDrainCore(context, drainId, options);
|
|
50059
|
+
break;
|
|
50060
|
+
case "rotate-secret":
|
|
50061
|
+
await rotateSecretCore(context, drainId, options);
|
|
50062
|
+
break;
|
|
50063
|
+
default:
|
|
50064
|
+
throw CliError.usage(`Unknown drains action '${action}'.`, listHint("Try", DRAIN_ACTIONS));
|
|
50065
|
+
}
|
|
50066
|
+
trackEvent("cli_drains_action", {
|
|
50067
|
+
action: verb,
|
|
50068
|
+
non_interactive: !!action
|
|
50069
|
+
});
|
|
50070
|
+
},
|
|
50071
|
+
"drains",
|
|
50072
|
+
// LUA-803: a refusal that escapes a verb under `--json` is the typed envelope on stdout,
|
|
50073
|
+
// never the `✖` line — the one shape a script parses.
|
|
50074
|
+
{
|
|
50075
|
+
json: /* @__PURE__ */ __name(() => !!cmdObj?.json, "json")
|
|
50076
|
+
}
|
|
50077
|
+
);
|
|
50078
|
+
}
|
|
50079
|
+
__name(drainsCommand, "drainsCommand");
|
|
50080
|
+
|
|
48085
50081
|
// src/commands/completion.ts
|
|
48086
50082
|
init_cli();
|
|
48087
50083
|
init_analytics();
|
|
@@ -49422,10 +51418,10 @@ function truncate2(s, n2) {
|
|
|
49422
51418
|
return s.length <= n2 ? s : s.slice(0, Math.max(0, n2 - 1)) + "\u2026";
|
|
49423
51419
|
}
|
|
49424
51420
|
__name(truncate2, "truncate");
|
|
49425
|
-
function
|
|
51421
|
+
function printJson3(report2) {
|
|
49426
51422
|
console.log(JSON.stringify(report2));
|
|
49427
51423
|
}
|
|
49428
|
-
__name(
|
|
51424
|
+
__name(printJson3, "printJson");
|
|
49429
51425
|
var TICK = chalk3.green("\u2713");
|
|
49430
51426
|
var WARN = chalk3.yellow("!");
|
|
49431
51427
|
var CROSS = chalk3.red("\u2717");
|
|
@@ -49708,7 +51704,7 @@ async function statusCommand(options) {
|
|
|
49708
51704
|
hints
|
|
49709
51705
|
};
|
|
49710
51706
|
if (options.json) {
|
|
49711
|
-
|
|
51707
|
+
printJson3(report2);
|
|
49712
51708
|
} else {
|
|
49713
51709
|
printHuman(report2);
|
|
49714
51710
|
}
|
|
@@ -53102,31 +55098,58 @@ function runMetering(run) {
|
|
|
53102
55098
|
return run.usage?.metering === "priced" ? "priced" : "flat";
|
|
53103
55099
|
}
|
|
53104
55100
|
__name(runMetering, "runMetering");
|
|
55101
|
+
var SEAT_COPY = "charged like chat \u2014 actions = the call's price band \xD7 the model's multiplier per model call; cached tokens count at the provider's ratio";
|
|
53105
55102
|
function budgetCopy(run) {
|
|
53106
55103
|
if (runMetering(run) === "priced") {
|
|
53107
|
-
|
|
53108
|
-
if (
|
|
53109
|
-
return "charged like chat \u2014
|
|
55104
|
+
const engine = budgetEngineOf(run);
|
|
55105
|
+
if (engine === "seat") return SEAT_COPY;
|
|
55106
|
+
if (engine === "legacy") return "charged like chat \u2014 a credit is one model reply on a Job step, one agent step otherwise; tokens are never metered";
|
|
55107
|
+
return "charged like chat \u2014 a credit is one model reply on a Job step (one agent step otherwise) on the legacy plan, or actions = price band \xD7 the model's multiplier per model call on a seat plan";
|
|
53110
55108
|
}
|
|
55109
|
+
if (run.budget?.unit === "actions") return SEAT_COPY;
|
|
53111
55110
|
return "a credit is one agent step; a Job-tier attempt is 4 \u2014 tokens are never metered";
|
|
53112
55111
|
}
|
|
53113
55112
|
__name(budgetCopy, "budgetCopy");
|
|
55113
|
+
function budgetEngineOf(run) {
|
|
55114
|
+
const engine = run.usage?.engine;
|
|
55115
|
+
if (engine === "seat" || engine === "legacy") return engine;
|
|
55116
|
+
const unit = run.budget?.unit;
|
|
55117
|
+
return unit === "actions" ? "seat" : unit === "credits" ? "legacy" : void 0;
|
|
55118
|
+
}
|
|
55119
|
+
__name(budgetEngineOf, "budgetEngineOf");
|
|
53114
55120
|
var fmtNum = /* @__PURE__ */ __name((v) => v.toLocaleString("en-US"), "fmtNum");
|
|
53115
55121
|
function budgetLine(run) {
|
|
53116
55122
|
const u = run.usage;
|
|
53117
55123
|
const b = run.budget;
|
|
53118
55124
|
if (!u && !b) return void 0;
|
|
53119
|
-
const seat =
|
|
55125
|
+
const seat = budgetEngineOf(run) === "seat";
|
|
53120
55126
|
const spent = seat ? u?.actionsUsed ?? b?.spent?.actionsEstimate ?? 0 : u?.creditsUsed ?? b?.spent?.credits ?? 0;
|
|
53121
55127
|
const cap = runBudgetCap(b);
|
|
53122
55128
|
const parts = [
|
|
53123
55129
|
`${fmtNum(spent)}${cap !== void 0 ? ` of ${fmtNum(cap)}` : ""} ${seat ? "actions" : "credits"} spent`,
|
|
53124
55130
|
b?.remaining !== void 0 ? `${fmtNum(b.remaining)} remaining` : void 0,
|
|
53125
|
-
seat && u?.creditsUsed ? `${fmtNum(u.creditsUsed)} flat credits` : void 0
|
|
55131
|
+
seat && u?.creditsUsed ? `${fmtNum(u.creditsUsed)} flat credits` : void 0,
|
|
55132
|
+
// [WJB-B5] (BAC-677 / plan D4): the run's own `budget.exceeded` stamp — the last step crossed the cap and
|
|
55133
|
+
// the run finished rather than parking for a raise nobody could act on. Printed only when the server
|
|
55134
|
+
// stamped it (never `false`, never inferred from `spent > cap`, which a concurrent settle can show for a
|
|
55135
|
+
// run that parked legitimately).
|
|
55136
|
+
b?.exceeded === true ? "finished past the cap" : void 0
|
|
53126
55137
|
].filter((p) => !!p);
|
|
53127
55138
|
return `${parts.join(" \xB7 ")} (${budgetCopy(run)})`;
|
|
53128
55139
|
}
|
|
53129
55140
|
__name(budgetLine, "budgetLine");
|
|
55141
|
+
function tokensLine(run) {
|
|
55142
|
+
const t = run.usage?.tokens;
|
|
55143
|
+
if (!t) return void 0;
|
|
55144
|
+
const parts = [
|
|
55145
|
+
typeof t.inputTokens === "number" ? `${fmtNum(t.inputTokens)} uncached in` : void 0,
|
|
55146
|
+
typeof t.cacheReadTokens === "number" ? `${fmtNum(t.cacheReadTokens)} cache read` : void 0,
|
|
55147
|
+
typeof t.cacheCreationTokens === "number" ? `${fmtNum(t.cacheCreationTokens)} cache write` : void 0,
|
|
55148
|
+
typeof t.outputTokens === "number" ? `${fmtNum(t.outputTokens)} out` : void 0
|
|
55149
|
+
].filter((p) => !!p);
|
|
55150
|
+
return parts.length ? parts.join(" \xB7 ") : void 0;
|
|
55151
|
+
}
|
|
55152
|
+
__name(tokensLine, "tokensLine");
|
|
53130
55153
|
function autonomyDurationLabel(seconds) {
|
|
53131
55154
|
if (!Number.isFinite(seconds) || seconds < 0) return `${seconds} s`;
|
|
53132
55155
|
if (seconds >= 86400 && seconds % 86400 === 0) return `${fmtNum(seconds / 86400)} d`;
|
|
@@ -53265,6 +55288,8 @@ function printRun(run, withSteps) {
|
|
|
53265
55288
|
if (consent) console.log(` Consent: ${consent}`);
|
|
53266
55289
|
const budget = budgetLine(run);
|
|
53267
55290
|
if (budget) console.log(` Budget: ${budget}`);
|
|
55291
|
+
const tokens = tokensLine(run);
|
|
55292
|
+
if (tokens) console.log(` Tokens: ${tokens}`);
|
|
53268
55293
|
if (run.cancel) console.log(` Cancel: ${formatRunCancel(run.cancel)}`);
|
|
53269
55294
|
if (run.gate) {
|
|
53270
55295
|
const kind = run.gate.kind;
|
|
@@ -53275,7 +55300,7 @@ function printRun(run, withSteps) {
|
|
|
53275
55300
|
} else if (kind === "budget") {
|
|
53276
55301
|
console.log(`
|
|
53277
55302
|
\u23F8\uFE0F Paused \u2014 run budget reached (${budgetCopy(run)}):`);
|
|
53278
|
-
console.log(` lua workflows raise-budget ${id} --credits <n
|
|
55303
|
+
console.log(` lua workflows raise-budget ${id} --credits <n> (<n> is the new cap in ${budgetEngineOf(run) === "seat" ? "actions" : "credits"})`);
|
|
53279
55304
|
} else if (kind === "billing") {
|
|
53280
55305
|
for (const line of billingParkLines(run)) console.log(line);
|
|
53281
55306
|
} else if (kind === "model_policy") {
|
|
@@ -53309,11 +55334,17 @@ function printRun(run, withSteps) {
|
|
|
53309
55334
|
else {
|
|
53310
55335
|
console.log("");
|
|
53311
55336
|
const withChildren = steps.some((s) => typeof s.childRunId === "string");
|
|
55337
|
+
const withTokens = steps.some((s) => !!s.tokens);
|
|
53312
55338
|
console.log(renderTable([
|
|
53313
55339
|
"Step",
|
|
53314
55340
|
"Kind",
|
|
53315
55341
|
"Status",
|
|
53316
55342
|
"Attempt",
|
|
55343
|
+
...withTokens ? [
|
|
55344
|
+
"Uncached",
|
|
55345
|
+
"Cached",
|
|
55346
|
+
"Output"
|
|
55347
|
+
] : [],
|
|
53317
55348
|
"Error",
|
|
53318
55349
|
...withChildren ? [
|
|
53319
55350
|
"Child run"
|
|
@@ -53323,6 +55354,7 @@ function printRun(run, withSteps) {
|
|
|
53323
55354
|
s.kind ?? "\u2014",
|
|
53324
55355
|
s.status,
|
|
53325
55356
|
stepAttemptCell(s),
|
|
55357
|
+
...withTokens ? stepTokenCells(s) : [],
|
|
53326
55358
|
stepErrorCell(s.error),
|
|
53327
55359
|
...withChildren ? [
|
|
53328
55360
|
s.childRunId ?? ""
|
|
@@ -53352,6 +55384,22 @@ function billingParkLines(run) {
|
|
|
53352
55384
|
return out;
|
|
53353
55385
|
}
|
|
53354
55386
|
__name(billingParkLines, "billingParkLines");
|
|
55387
|
+
function stepTokenCells(s) {
|
|
55388
|
+
const t = s.tokens;
|
|
55389
|
+
const cell = /* @__PURE__ */ __name((v) => typeof v === "number" && Number.isFinite(v) ? fmtNum(v) : "\u2014", "cell");
|
|
55390
|
+
if (!t) return [
|
|
55391
|
+
"\u2014",
|
|
55392
|
+
"\u2014",
|
|
55393
|
+
"\u2014"
|
|
55394
|
+
];
|
|
55395
|
+
const cached = typeof t.cacheReadTokens === "number" || typeof t.cacheCreationTokens === "number" ? (t.cacheReadTokens ?? 0) + (t.cacheCreationTokens ?? 0) : void 0;
|
|
55396
|
+
return [
|
|
55397
|
+
cell(t.inputTokens),
|
|
55398
|
+
cell(cached),
|
|
55399
|
+
cell(t.outputTokens)
|
|
55400
|
+
];
|
|
55401
|
+
}
|
|
55402
|
+
__name(stepTokenCells, "stepTokenCells");
|
|
53355
55403
|
function stepAttemptLines(s) {
|
|
53356
55404
|
const out = [];
|
|
53357
55405
|
const cause = stepFailureLine(s.error);
|
|
@@ -53360,6 +55408,8 @@ function stepAttemptLines(s) {
|
|
|
53360
55408
|
if (burned) out.push(` \u03A3 ${s.stepId}: attempt ${s.attempt ?? 1} ${s.status}: ${burned}`);
|
|
53361
55409
|
const billed = stepBillingLine(s.billing);
|
|
53362
55410
|
if (billed) out.push(` $ ${s.stepId}: attempt ${s.billing?.attempt ?? s.attempt ?? 1} billed: ${billed}`);
|
|
55411
|
+
const jobModel = stepJobModelLine(s);
|
|
55412
|
+
if (jobModel) out.push(` \u2699 ${s.stepId}: ${jobModel}`);
|
|
53363
55413
|
const fetchable = outputRefLine(s.outputRef);
|
|
53364
55414
|
if (fetchable) out.push(` \u21E9 ${s.stepId}: ${fetchable}`);
|
|
53365
55415
|
const escalated = approverFallbackLine(s);
|
|
@@ -53373,6 +55423,22 @@ function stepAttemptLines(s) {
|
|
|
53373
55423
|
return out;
|
|
53374
55424
|
}
|
|
53375
55425
|
__name(stepAttemptLines, "stepAttemptLines");
|
|
55426
|
+
function stepJobModelLine(s) {
|
|
55427
|
+
const j = s.job;
|
|
55428
|
+
if (!j) return void 0;
|
|
55429
|
+
const parts = [
|
|
55430
|
+
j.model ? `model ${j.model}` : void 0,
|
|
55431
|
+
typeof j.multiplier === "number" ? `\xD7${fmtNum(j.multiplier)}` : void 0,
|
|
55432
|
+
j.modelSource ? `chosen by ${jobModelSourceWord(j.modelSource)}` : void 0
|
|
55433
|
+
].filter((p) => !!p);
|
|
55434
|
+
return parts.length ? parts.join(" \xB7 ") : void 0;
|
|
55435
|
+
}
|
|
55436
|
+
__name(stepJobModelLine, "stepJobModelLine");
|
|
55437
|
+
function jobModelSourceWord(source) {
|
|
55438
|
+
const labels = WORKFLOW_JOB_MODEL_SOURCE_LABELS;
|
|
55439
|
+
return labels[source] ?? source;
|
|
55440
|
+
}
|
|
55441
|
+
__name(jobModelSourceWord, "jobModelSourceWord");
|
|
53376
55442
|
function approverFallbackLine(s) {
|
|
53377
55443
|
const f = s.suspend?.approverFallback;
|
|
53378
55444
|
if (!f?.from || !f.to) return void 0;
|
|
@@ -53674,18 +55740,23 @@ __name(handleWatchFrame, "handleWatchFrame");
|
|
|
53674
55740
|
async function boundaryVerdict(runId, ev, state3, boundary) {
|
|
53675
55741
|
const type = ev.type;
|
|
53676
55742
|
if (type === "run.gated") {
|
|
53677
|
-
const
|
|
53678
|
-
const
|
|
53679
|
-
|
|
55743
|
+
const raw = ev.data;
|
|
55744
|
+
const rawKind = raw?.kind ?? raw?.gate;
|
|
55745
|
+
const stepId = raw?.stepId;
|
|
55746
|
+
if (rawKind === "exception") {
|
|
53680
55747
|
return boundary(`\u26A0\uFE0F run parked on an exception gate \u2014 a human decides next: lua workflows status ${runId}`, WORKFLOW_EXIT.RUN_PARKED);
|
|
53681
55748
|
}
|
|
53682
|
-
if (
|
|
55749
|
+
if (rawKind === "billing") {
|
|
53683
55750
|
return boundary(`\u23F8\uFE0F run parked on a billing gate \u2014 top up the workspace; it resumes within a few minutes (right away: lua workflows retry-step ${runId} --step ${stepId ?? "<stepId>"})`, WORKFLOW_EXIT.RUN_PARKED);
|
|
53684
55751
|
}
|
|
53685
|
-
if (
|
|
53686
|
-
return boundary(`\u23F8\uFE0F run budget reached \u2014 lua workflows raise-budget ${runId} --credits <n> (lua workflows status ${runId} says
|
|
55752
|
+
if (rawKind === "budget") {
|
|
55753
|
+
return boundary(`\u23F8\uFE0F run budget reached \u2014 lua workflows raise-budget ${runId} --credits <n> (the cap is in this run's own budget unit \u2014 credits, or actions on a seat plan; lua workflows status ${runId} says which)`, WORKFLOW_EXIT.RUN_PARKED);
|
|
53687
55754
|
}
|
|
53688
|
-
|
|
55755
|
+
if (rawKind === "quota") {
|
|
55756
|
+
return boundary(`\u23F8\uFE0F run gated on the concurrency quota \u2014 it clears on its own as a slot frees (oldest-gated run first); check progress: lua workflows status ${runId}`, WORKFLOW_EXIT.RUN_GATED);
|
|
55757
|
+
}
|
|
55758
|
+
const label2 = rawKind === "start-consent" || rawKind === void 0 ? "consent" : rawKind;
|
|
55759
|
+
return boundary(`\u23F8\uFE0F run gated (${label2}) \u2014 approve it from the desktop; then: lua workflows watch ${runId}`, WORKFLOW_EXIT.RUN_GATED);
|
|
53689
55760
|
}
|
|
53690
55761
|
if (type === "run.suspended") {
|
|
53691
55762
|
const kind = ev.data?.kind;
|
|
@@ -53700,7 +55771,7 @@ async function boundaryVerdict(runId, ev, state3, boundary) {
|
|
|
53700
55771
|
}
|
|
53701
55772
|
}
|
|
53702
55773
|
if (type === "run.budget_parked") {
|
|
53703
|
-
return boundary(`\u23F8\uFE0F run budget reached \u2014 lua workflows raise-budget ${runId} --credits <n> (lua workflows status ${runId} says
|
|
55774
|
+
return boundary(`\u23F8\uFE0F run budget reached \u2014 lua workflows raise-budget ${runId} --credits <n> (the cap is in this run's own budget unit \u2014 credits, or actions on a seat plan; lua workflows status ${runId} says which)`, WORKFLOW_EXIT.RUN_PARKED);
|
|
53704
55775
|
}
|
|
53705
55776
|
if (type === "run.completed") return WORKFLOW_EXIT.OK;
|
|
53706
55777
|
if (type === "run.failed" || type === "run.timed_out") return WORKFLOW_EXIT.RUN_FAILED;
|
|
@@ -53930,10 +56001,10 @@ function budgetCapFlag(cap) {
|
|
|
53930
56001
|
return "--credits";
|
|
53931
56002
|
}
|
|
53932
56003
|
__name(budgetCapFlag, "budgetCapFlag");
|
|
53933
|
-
function budgetCapsLabel(b) {
|
|
56004
|
+
function budgetCapsLabel(b, unit) {
|
|
53934
56005
|
if (!b) return "";
|
|
53935
56006
|
const parts = [];
|
|
53936
|
-
if (b.maxCredits !== void 0) parts.push(`${b.maxCredits} credits`);
|
|
56007
|
+
if (b.maxCredits !== void 0) parts.push(`${b.maxCredits} ${unit ?? "credits"}`);
|
|
53937
56008
|
if (b.maxSteps !== void 0) parts.push(`${b.maxSteps} steps`);
|
|
53938
56009
|
if (b.maxJobSeconds !== void 0) parts.push(`${b.maxJobSeconds}s job`);
|
|
53939
56010
|
if (b.maxDurationSeconds !== void 0) parts.push(`${b.maxDurationSeconds}s wall`);
|
|
@@ -53999,9 +56070,10 @@ async function raiseBudgetCore(ctx, runId, o) {
|
|
|
53999
56070
|
emitJson(ctx, res);
|
|
54000
56071
|
if (!ctx.json) {
|
|
54001
56072
|
const d = res.data;
|
|
54002
|
-
const
|
|
56073
|
+
const unit = d.unit === "actions" ? "actions" : "credits";
|
|
56074
|
+
const caps = budgetCapsLabel(d.budget ?? d.to, unit);
|
|
54003
56075
|
if (d.raised) {
|
|
54004
|
-
const delta = d.from && d.to ? ` (${budgetCapsLabel(d.from)} \u2192 ${budgetCapsLabel(d.to)})` : caps ? ` to ${caps}` : "";
|
|
56076
|
+
const delta = d.from && d.to ? ` (${budgetCapsLabel(d.from, unit)} \u2192 ${budgetCapsLabel(d.to, unit)})` : caps ? ` to ${caps}` : "";
|
|
54005
56077
|
writeSuccess(`\u2705 budget raised${delta}${d.runStatus ? ` \xB7 run is ${d.runStatus}` : ""}`);
|
|
54006
56078
|
if (d.resumed === false) writeInfo(`\u2139\uFE0F the run did not resume on this raise \u2014 the next step's reserve is still short (raise again), or nothing was parked: lua workflows status ${runId}`);
|
|
54007
56079
|
else if (d.resumed) writeInfo(`\u{1F4A1} Follow it: lua workflows watch ${runId}`);
|
|
@@ -54346,23 +56418,77 @@ async function replayChildRun(ctx, childRunId) {
|
|
|
54346
56418
|
};
|
|
54347
56419
|
}
|
|
54348
56420
|
__name(replayChildRun, "replayChildRun");
|
|
54349
|
-
var WORKFLOW_LOG_EVENT_PATTERN = /progress|log|started|completed|failed|skipped|model_resolved|model_policy_warning/;
|
|
56421
|
+
var WORKFLOW_LOG_EVENT_PATTERN = /progress|log|started|completed|failed|skipped|model_resolved|model_policy_warning|budget_parked|budget_raised|budget_exceeded/;
|
|
56422
|
+
function jobModelEventDetail(data) {
|
|
56423
|
+
const d = data ?? {};
|
|
56424
|
+
const nested = d.detail && typeof d.detail === "object" ? d.detail : {};
|
|
56425
|
+
const pick = /* @__PURE__ */ __name((key) => d[key] !== void 0 ? d[key] : nested[key], "pick");
|
|
56426
|
+
const model = typeof pick("model") === "string" ? pick("model") : void 0;
|
|
56427
|
+
const raw = pick("multiplier");
|
|
56428
|
+
const multiplier = typeof raw === "number" && Number.isFinite(raw) ? raw : void 0;
|
|
56429
|
+
const source = typeof pick("source") === "string" ? pick("source") : void 0;
|
|
56430
|
+
const calibrated = pick("calibrated");
|
|
56431
|
+
if (!model && multiplier === void 0 && !source) return void 0;
|
|
56432
|
+
const tail = [
|
|
56433
|
+
multiplier !== void 0 ? `\xD7${fmtNum(multiplier)}` : void 0,
|
|
56434
|
+
source ? `(${jobModelSourceWord(source)})` : void 0,
|
|
56435
|
+
calibrated === false ? "\u2014 uncalibrated model, fallback rate" : void 0
|
|
56436
|
+
].filter((p) => !!p);
|
|
56437
|
+
return `job model \u2192 ${model ?? "?"}${tail.length ? ` ${tail.join(" ")}` : ""}`;
|
|
56438
|
+
}
|
|
56439
|
+
__name(jobModelEventDetail, "jobModelEventDetail");
|
|
56440
|
+
function budgetEventDetail(type, data) {
|
|
56441
|
+
if (type !== "run.budget_parked" && type !== "run.budget_raised" && type !== "run.budget_exceeded") return void 0;
|
|
56442
|
+
const d = data ?? {};
|
|
56443
|
+
const nested = d.detail && typeof d.detail === "object" ? d.detail : {};
|
|
56444
|
+
const pick = /* @__PURE__ */ __name((key) => d[key] !== void 0 ? d[key] : nested[key], "pick");
|
|
56445
|
+
const numberOf = /* @__PURE__ */ __name((key) => {
|
|
56446
|
+
const v = pick(key);
|
|
56447
|
+
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
56448
|
+
}, "numberOf");
|
|
56449
|
+
const stringOf = /* @__PURE__ */ __name((key) => {
|
|
56450
|
+
const v = pick(key);
|
|
56451
|
+
return typeof v === "string" && v ? v : void 0;
|
|
56452
|
+
}, "stringOf");
|
|
56453
|
+
const stepId = stringOf("stepId");
|
|
56454
|
+
const step3 = stepId ? ` (step ${stepId})` : "";
|
|
56455
|
+
if (type === "run.budget_raised") {
|
|
56456
|
+
const from = numberOf("from");
|
|
56457
|
+
const to = numberOf("to");
|
|
56458
|
+
const move = from !== void 0 && to !== void 0 ? `cap ${fmtNum(from)} \u2192 ${fmtNum(to)}` : "cap raised";
|
|
56459
|
+
const by = stringOf("by");
|
|
56460
|
+
const resumed = pick("resumed") === true ? " \u2014 run resumed" : "";
|
|
56461
|
+
return `${move}${by ? ` by ${by}` : ""}${resumed}`;
|
|
56462
|
+
}
|
|
56463
|
+
const dimension = stringOf("dimension");
|
|
56464
|
+
const spent = numberOf("spent");
|
|
56465
|
+
const cap = numberOf("cap");
|
|
56466
|
+
const figures = spent !== void 0 && cap !== void 0 ? `${fmtNum(spent)} of ${fmtNum(cap)}${dimension ? ` ${dimension}` : ""}` : dimension;
|
|
56467
|
+
const lead = type === "run.budget_exceeded" ? "finished past the cap" : "paused on its run budget";
|
|
56468
|
+
const detail = [
|
|
56469
|
+
figures,
|
|
56470
|
+
stringOf("engine")
|
|
56471
|
+
].filter((p) => !!p).join(", ");
|
|
56472
|
+
return `${lead}${detail ? ` \u2014 ${detail}` : ""}${step3}`;
|
|
56473
|
+
}
|
|
56474
|
+
__name(budgetEventDetail, "budgetEventDetail");
|
|
54350
56475
|
function modelEventDetail(type, data) {
|
|
56476
|
+
if (type === "step.job_model_resolved") return jobModelEventDetail(data);
|
|
54351
56477
|
if (type !== "step.model_resolved" && type !== "step.model_policy_warning") return void 0;
|
|
54352
56478
|
const d = data ?? {};
|
|
54353
56479
|
const nested = d.detail ?? {};
|
|
54354
|
-
const
|
|
56480
|
+
const str2 = /* @__PURE__ */ __name((...vals) => {
|
|
54355
56481
|
for (const v of vals) if (typeof v === "string" && v) return v;
|
|
54356
56482
|
return void 0;
|
|
54357
56483
|
}, "str");
|
|
54358
|
-
const requested =
|
|
54359
|
-
const resolved =
|
|
56484
|
+
const requested = str2(d.requested, nested.requested, d.modelRequested, nested.modelRequested);
|
|
56485
|
+
const resolved = str2(d.resolved, nested.resolved, d.model, nested.model);
|
|
54360
56486
|
if (type === "step.model_resolved") {
|
|
54361
|
-
const cls = requested?.startsWith("class/") ? requested.slice("class/".length) :
|
|
56487
|
+
const cls = requested?.startsWith("class/") ? requested.slice("class/".length) : str2(d.taskClass, nested.taskClass);
|
|
54362
56488
|
return `model resolved \u2192 ${resolved ?? requested ?? "?"}${cls ? ` (${cls})` : ""}`;
|
|
54363
56489
|
}
|
|
54364
|
-
const outcome =
|
|
54365
|
-
const detail =
|
|
56490
|
+
const outcome = str2(d.outcome, nested.outcome, d.code, nested.code) ?? "unknown";
|
|
56491
|
+
const detail = str2(d.message, nested.message) ?? (requested && resolved && requested !== resolved ? `${requested} \u2192 ${resolved}` : requested ?? resolved);
|
|
54366
56492
|
return `model policy warning: ${outcome}${detail ? ` ${detail}` : ""}`;
|
|
54367
56493
|
}
|
|
54368
56494
|
__name(modelEventDetail, "modelEventDetail");
|
|
@@ -54378,7 +56504,9 @@ async function logsCore(ctx, runId, o) {
|
|
|
54378
56504
|
if (events.length === 0) console.log("(no log events yet)");
|
|
54379
56505
|
for (const e of events) {
|
|
54380
56506
|
const data = scrubEventData(e.data);
|
|
54381
|
-
const msg = modelEventDetail(e.type, data) ??
|
|
56507
|
+
const msg = modelEventDetail(e.type, data) ?? // [WJB-B5]: the budget events carry no `message` of their own — without a renderer they would print as a
|
|
56508
|
+
// bare type, which is why the pattern admitting them and this line land together.
|
|
56509
|
+
budgetEventDetail(e.type, data) ?? data?.message ?? subrunEventDetail(e);
|
|
54382
56510
|
console.log(`[${clockOf(e.ts)}] ${e.type}${e.stepId ? ` \xB7 ${e.stepId}` : ""}${msg ? ` \xB7 ${msg}` : ""}`);
|
|
54383
56511
|
}
|
|
54384
56512
|
return WORKFLOW_EXIT.OK;
|
|
@@ -54756,7 +56884,7 @@ async function archiveRunsCore(ctx, o) {
|
|
|
54756
56884
|
if (!ctx.json) console.log(line);
|
|
54757
56885
|
}, "say");
|
|
54758
56886
|
const sha256 = /* @__PURE__ */ __name((buf) => crypto5.createHash("sha256").update(buf).digest("hex"), "sha256");
|
|
54759
|
-
const
|
|
56887
|
+
const sleep4 = /* @__PURE__ */ __name((ms) => new Promise((r) => setTimeout(r, ms)), "sleep");
|
|
54760
56888
|
const archiveOne = /* @__PURE__ */ __name(async (apiRow) => {
|
|
54761
56889
|
const run = {
|
|
54762
56890
|
...apiRow,
|
|
@@ -54814,7 +56942,7 @@ async function archiveRunsCore(ctx, o) {
|
|
|
54814
56942
|
}
|
|
54815
56943
|
let dto = req.data;
|
|
54816
56944
|
for (let attempt = 0; !dto || dto.status === "pending"; attempt++) {
|
|
54817
|
-
if (attempt > 0) await
|
|
56945
|
+
if (attempt > 0) await sleep4(Math.min(5e3, 250 * 2 ** Math.min(attempt, 5)));
|
|
54818
56946
|
if (attempt > 60) {
|
|
54819
56947
|
report2.deferred.push({
|
|
54820
56948
|
runId: run.id,
|
|
@@ -56315,12 +58443,8 @@ async function clearGateCore(ctx, runId, o) {
|
|
|
56315
58443
|
if (!res.success || !res.data) return apiFailure(ctx, res, "clear-gate");
|
|
56316
58444
|
emitJson(ctx, res);
|
|
56317
58445
|
if (ctx.json) return WORKFLOW_EXIT.OK;
|
|
56318
|
-
|
|
56319
|
-
|
|
56320
|
-
console.log(` lua workflows watch ${runId}`);
|
|
56321
|
-
} else {
|
|
56322
|
-
writeInfo(`\u2139\uFE0F ${runId} is not parked on a ${kind} gate${res.data.reason ? ` \u2014 ${res.data.reason}` : ""}. Nothing to clear.`);
|
|
56323
|
-
}
|
|
58446
|
+
writeSuccess(`\u2705 Cleared the ${res.data.kind ?? kind} gate on ${runId}${res.data.status ? ` \u2014 ${res.data.status}` : ""}`);
|
|
58447
|
+
console.log(` lua workflows watch ${runId}`);
|
|
56324
58448
|
return WORKFLOW_EXIT.OK;
|
|
56325
58449
|
}
|
|
56326
58450
|
__name(clearGateCore, "clearGateCore");
|
|
@@ -56345,12 +58469,18 @@ async function recomposeCore(ctx, name, _o) {
|
|
|
56345
58469
|
emitJson(ctx, res);
|
|
56346
58470
|
if (ctx.json) return WORKFLOW_EXIT.OK;
|
|
56347
58471
|
const d = res.data;
|
|
56348
|
-
|
|
58472
|
+
const rewrittenCount = d.rewritten?.length ?? 0;
|
|
58473
|
+
if (rewrittenCount === 0) {
|
|
56349
58474
|
writeInfo(`\u2139\uFE0F ${wf.name} already asks for model classes everywhere it can \u2014 no new version was published.`);
|
|
56350
58475
|
return WORKFLOW_EXIT.OK;
|
|
56351
58476
|
}
|
|
56352
|
-
|
|
56353
|
-
|
|
58477
|
+
const saved = d.composed?.saved;
|
|
58478
|
+
const version = saved?.version ?? saved?.versionId ?? "(new)";
|
|
58479
|
+
writeSuccess(`\u2705 ${wf.name} recomposed \u2192 version ${version} \xB7 ${rewrittenCount} agent step${rewrittenCount === 1 ? "" : "s"} rewritten`);
|
|
58480
|
+
if (saved?.supersededBy) {
|
|
58481
|
+
writeInfo(`\u2139\uFE0F a concurrent recompose already holds the pin at version ${saved.supersededBy} \u2014 that is what runs.`);
|
|
58482
|
+
}
|
|
58483
|
+
for (const line of recomposeNextSteps(wf, version)) console.log(line);
|
|
56354
58484
|
return WORKFLOW_EXIT.OK;
|
|
56355
58485
|
}
|
|
56356
58486
|
__name(recomposeCore, "recomposeCore");
|
|
@@ -58395,10 +60525,10 @@ async function templateCommand(action, options = {}) {
|
|
|
58395
60525
|
});
|
|
58396
60526
|
}
|
|
58397
60527
|
__name(templateCommand, "templateCommand");
|
|
58398
|
-
function
|
|
60528
|
+
function sleep3(ms) {
|
|
58399
60529
|
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
58400
60530
|
}
|
|
58401
|
-
__name(
|
|
60531
|
+
__name(sleep3, "sleep");
|
|
58402
60532
|
function missingVersionOrRethrow(error) {
|
|
58403
60533
|
if (CliError.isCliError(error) && error.statusCode === 404) return null;
|
|
58404
60534
|
throw error;
|
|
@@ -58442,12 +60572,12 @@ function parseEnvContract(raw) {
|
|
|
58442
60572
|
const result = {};
|
|
58443
60573
|
for (const entry of raw) {
|
|
58444
60574
|
for (const pair of entry.split(/,(?=\s*[A-Za-z_][A-Za-z0-9_]*\??\s*=)/)) {
|
|
58445
|
-
const
|
|
58446
|
-
if (!
|
|
58447
|
-
const eqIdx =
|
|
60575
|
+
const trimmed2 = pair.trim();
|
|
60576
|
+
if (!trimmed2) continue;
|
|
60577
|
+
const eqIdx = trimmed2.indexOf("=");
|
|
58448
60578
|
if (eqIdx === -1) continue;
|
|
58449
|
-
let key =
|
|
58450
|
-
const description =
|
|
60579
|
+
let key = trimmed2.slice(0, eqIdx).trim();
|
|
60580
|
+
const description = trimmed2.slice(eqIdx + 1).trim();
|
|
58451
60581
|
let required = true;
|
|
58452
60582
|
if (key.endsWith("?")) {
|
|
58453
60583
|
required = false;
|
|
@@ -59014,8 +61144,7 @@ Apply v${versionObj.version} to ${targets.length} agent(s)?`);
|
|
|
59014
61144
|
writeProgress("\u{1F504} Starting apply run...");
|
|
59015
61145
|
const { runId } = await templateApi.apply(templateId, {
|
|
59016
61146
|
version: versionObj.version,
|
|
59017
|
-
targets
|
|
59018
|
-
skipEnvCheck: options.skipEnvCheck
|
|
61147
|
+
targets
|
|
59019
61148
|
});
|
|
59020
61149
|
if (options.wait === false) {
|
|
59021
61150
|
if (options.json) {
|
|
@@ -59034,7 +61163,7 @@ Apply v${versionObj.version} to ${targets.length} agent(s)?`);
|
|
|
59034
61163
|
if (Date.now() > waitDeadline) {
|
|
59035
61164
|
throw new Error(`Apply run ${runId} still running after 30 minutes \u2014 a crashed worker can leave a run stuck. Check later with: lua marketplace template status --template-id ${templateId}`);
|
|
59036
61165
|
}
|
|
59037
|
-
await
|
|
61166
|
+
await sleep3(3e3);
|
|
59038
61167
|
run = await templateApi.getApplyRun(templateId, runId);
|
|
59039
61168
|
}
|
|
59040
61169
|
if (options.json) {
|
|
@@ -67422,7 +69551,7 @@ function setupMarketplaceCommands(program2) {
|
|
|
67422
69551
|
program2.command("marketplace [noun] [action]").description("\u{1F6CD}\uFE0F Browse, install, and manage marketplace skills and agent templates").option("--skill-name <name>", "Skill name (for skill list/update/uninstall)").option("--marketplace-id <id>", "Marketplace skill ID").option("--new-org-id <id>", "Destination organization ID (for skill transfer)").option("--version-id <id>", "Version ID (for skill publish/install)").option("--env-vars-json <json>", "JSON string with env var metadata (for skill publish)").option("--query <text>", "Search query (for skill search)").option("--page <n>", "Page number (for skill search)").option("--limit <n>", "Results per page (for skill search)").option("--name <name>", "Template name, an internal identifier (for template create)").option("--description <text>", "Description (for template create)").option("--template-id <id>", "Template ID").option("--window-days <n>", "Fleet-health window in days (template health, R46)").option("--source-version <n>", "Agent version to freeze into this template version (default: active) (for template publish)").option("--env-contract <pair>", "KEY=description env contract entry, repeatable; use KEY?=description for optional (for template publish)", (val, previous) => [
|
|
67423
69552
|
...previous,
|
|
67424
69553
|
val
|
|
67425
|
-
], []).option("--skip-auto-apply", "Publish without auto-updating the installs that consented to creator updates (for template publish)").option("--version <n>", "Template version (for template view/install/apply)").option("--allow-creator-updates", "Allow the template creator to push future updates onto this install").option("--skip-env-check", "
|
|
69554
|
+
], []).option("--skip-auto-apply", "Publish without auto-updating the installs that consented to creator updates (for template publish)").option("--version <n>", "Template version (for template view/install/apply)").option("--allow-creator-updates", "Allow the template creator to push future updates onto this install").option("--skip-env-check", "Deprecated no-op: the env-contract check is server-enforced; use `lua env` to satisfy the contract (for template install/apply)").option("--agents <ids>", "Comma-separated target agent IDs (for template apply)").option("--file <path>", "Path to a file with one target agent ID per line (for template apply)").option("--all-installed", "Target every agent that already has this template installed (for template apply)").option("--no-wait", "Print the apply runId immediately instead of polling for completion (for template apply)").option("--display-name <name>", "Display name (for skill list/edit, template create)").option("--visibility <visibility>", "Who can see and install it: public or private (for skill list, template create)").option("--changelog <text>", "Changelog for this version (for skill/template publish)").option("--env-vars <pairs>", "Comma-separated key=value pairs (for skill/template install/update)").option("--json", "Output as JSON").option("--force", "Skip confirmation prompts").option("--yes", "Auto-confirm ONLY the template-publish consequence prompt (section clear/narrow); unlike --force it skips no other confirmation").addHelpText("after", `
|
|
67426
69555
|
Arguments:
|
|
67427
69556
|
noun Optional: 'skill' or 'template' (prompts if not provided)
|
|
67428
69557
|
action Optional: specific action for non-interactive mode
|
|
@@ -67699,9 +69828,9 @@ Examples:
|
|
|
67699
69828
|
$ lua channels Interactive management
|
|
67700
69829
|
$ lua channels list List all channels
|
|
67701
69830
|
`).action(channelsCommand);
|
|
67702
|
-
program2.command("logs").description("\u{1F4CA} View agent and skill logs").option("--type <type>", "Filter by type: all, skill, job, webhook, preprocessor, postprocessor, user_message, agent_response, mcp,
|
|
69831
|
+
program2.command("logs").description("\u{1F4CA} View agent and skill logs").option("--type <type>", "Filter by type: all, calls, or any of the 18 log sources (skill, job, webhook, trigger, preprocessor, postprocessor, user_message, agent_response, agent_error, runtime, mcp, rag, device, device-trigger, model-resolver, workflow-step, workflow-script, workflow)").option("--name <name>", "Entity name to filter (requires --type)").option("--user-id <userId>", "Filter logs by user ID").option("--agent-id <agentId>", "View logs for a specific agent ID (admin access required)").option("--limit <n>", "Number of logs to show (default: 20)").option("--page <n>", "Page number for pagination").option("--json", "Output as JSON (for scripting)").option("--direction <direction>", "Filter calls by direction (inbound | outbound) \u2014 only with --type calls").option("--status <status>", "Filter calls by status \u2014 only with --type calls").option("--since <when>", "Only logs at or after this time: an ISO 8601 instant, or 15m | 2h | 7d").option("--until <when>", "Only logs at or before this time; same formats (ends a --follow)").option("--environment <env>", "production | sandbox (a row with no environment reads as production)").option("--follow", "Stream new logs as they arrive (Ctrl-C to stop); not valid with --page").addHelpText("after", `
|
|
67703
69832
|
Options:
|
|
67704
|
-
--type <type> Filter by type: all, skill, job, webhook, preprocessor, postprocessor, user_message, agent_response, mcp,
|
|
69833
|
+
--type <type> Filter by type: all, calls, or any of the 18 log sources (skill, job, webhook, trigger, preprocessor, postprocessor, user_message, agent_response, agent_error, runtime, mcp, rag, device, device-trigger, model-resolver, workflow-step, workflow-script, workflow)
|
|
67705
69834
|
--name <name> Entity name to filter (requires --type, not for message types)
|
|
67706
69835
|
--user-id <userId> Filter logs by user ID
|
|
67707
69836
|
--agent-id <agentId> View logs for a specific agent ID (admin access required, overrides the agent in lua.config.yaml)
|
|
@@ -67710,6 +69839,11 @@ Options:
|
|
|
67710
69839
|
--json Output as JSON for scripting
|
|
67711
69840
|
--direction <dir> Filter calls by direction (inbound | outbound) \u2014 only with --type calls
|
|
67712
69841
|
--status <status> Filter calls by status \u2014 only with --type calls
|
|
69842
|
+
--since <when> Inclusive lower bound: an ISO 8601 instant, or a relative window (15m, 2h, 7d)
|
|
69843
|
+
--until <when> Inclusive upper bound, same formats; it also ends a --follow
|
|
69844
|
+
--environment <env> production | sandbox \u2014 a row with no environment reads as production
|
|
69845
|
+
--follow Poll for new logs until Ctrl-C; refuses --page, and --json emits one
|
|
69846
|
+
{logs, nextCursor, pagination} envelope per poll
|
|
67713
69847
|
|
|
67714
69848
|
Examples:
|
|
67715
69849
|
$ lua logs Interactive selection
|
|
@@ -67723,6 +69857,16 @@ Examples:
|
|
|
67723
69857
|
$ lua logs --type calls Recent voice calls (renders as table)
|
|
67724
69858
|
$ lua logs --type calls --direction outbound Outbound calls only
|
|
67725
69859
|
$ lua logs --type calls --status failed --json Failed calls as JSON
|
|
69860
|
+
$ lua logs --since 15m The last fifteen minutes
|
|
69861
|
+
$ lua logs --since 2026-09-21T09:00:00Z --until 2026-09-21T10:00:00Z One hour, exactly
|
|
69862
|
+
$ lua logs --environment sandbox --type skill Sandbox skill logs only
|
|
69863
|
+
$ lua logs --follow Stream new logs until Ctrl-C
|
|
69864
|
+
$ lua logs --follow --since 5m --json Tail the last five minutes, as JSON
|
|
69865
|
+
|
|
69866
|
+
Notes:
|
|
69867
|
+
A relative --since/--until is resolved by the SERVER's clock, so a skewed machine cannot
|
|
69868
|
+
shift the window. --type calls reads voice calls and ignores --since/--until/--environment
|
|
69869
|
+
/--follow. --since is INCLUSIVE; the boundary row is de-duplicated by id while following.
|
|
67726
69870
|
`).action(logsCommand);
|
|
67727
69871
|
program2.command("skills [actionOrEnv] [action]").description("\u2699\uFE0F Manage and view skills").option("--skill-name <name>", "Skill name").option("--skill-version <version>", "Version for deploy action (or 'latest')").addHelpText("after", `
|
|
67728
69872
|
Arguments:
|
|
@@ -67765,6 +69909,28 @@ Examples:
|
|
|
67765
69909
|
$ lua webhooks subscribe --webhook-name myWebhook --event message.delivered Subscribe to event
|
|
67766
69910
|
$ lua webhooks unsubscribe --webhook-name myWebhook --event message.delivered Unsubscribe from event
|
|
67767
69911
|
`).action(webhooksCommand);
|
|
69912
|
+
program2.command("drains [action] [id]").description("\u{1F6B0} Manage log drains (stream this organization's logs to your own destination)").option("--json", "Output as JSON").option("--yes", "Skip confirmation prompts (required with --include-content in CI)").option("--org <id>", "The organization to act on (default: the project, or the key when it reaches one org)").option("--name <name>", "Drain name (1-64 chars, unique per org)").option("--type <type>", "http | otlp | datadog | betterstack").option("--endpoint <url>", "Destination URL (http and otlp only; https, public host)").option("--site <site>", "Preset site/region, e.g. datadoghq.eu").option("--format <format>", "json | ndjson").option("--header <name>", "Custom header NAME (the value is prompted)", collect, []).option("--header-from-env <name=ENV_VAR>", "Custom header, value read from an env var (CI form)", collect, []).option("--sources <list>", "Comma-separated source selectors (default: the recommended set)").option("--min-severity <level>", "debug | info | warn | error (default info)").option("--agents <list>", "'all' or a comma-separated list of agent ids").option("--environments <list>", "production,sandbox (default production)").option("--sampling <spec>", "Head sampling, e.g. debug=0.1").option("--include-content", "Include user messages and agent responses (prints an acknowledgement)").option("--no-include-content", "update: stop sending message bodies (the drain keeps its sources)").option("--limit <n>", "deliveries: rows to return (max 100)").option("--kind <kind>", "deliveries: batch | test | verify | heartbeat | dropped | truncated").option("--reason <text>", "pause: why").option("--finalize", "rotate-secret: close an open rotation window early").addHelpText("after", `
|
|
69913
|
+
Arguments:
|
|
69914
|
+
action Optional: list (default), status, deliveries, create, update, delete,
|
|
69915
|
+
test, verify, pause, resume, rotate-secret
|
|
69916
|
+
id The drain id, for every action but list, status and create
|
|
69917
|
+
|
|
69918
|
+
Examples:
|
|
69919
|
+
$ lua drains List this org's drains
|
|
69920
|
+
$ lua drains status --json Health + quota (exit 2 if any is failing)
|
|
69921
|
+
$ lua drains create --name prod-siem --type http --endpoint https://logs.example.com/lua
|
|
69922
|
+
$ lua drains verify drn_... Prove you own the endpoint
|
|
69923
|
+
$ lua drains deliveries drn_... --limit 20 --kind batch Recent delivery attempts
|
|
69924
|
+
$ lua drains rotate-secret drn_... New signing secret (shown once)
|
|
69925
|
+
$ lua drains rotate-secret drn_... --finalize Close the rotation window
|
|
69926
|
+
$ lua drains pause drn_... --reason "noisy vendor" Stop delivering (buffering continues)
|
|
69927
|
+
$ lua drains update drn_... --no-include-content Stop sending message bodies
|
|
69928
|
+
|
|
69929
|
+
Notes:
|
|
69930
|
+
Secrets are never flags. --header takes a NAME and prompts for the value; in --ci mode use
|
|
69931
|
+
--header-from-env DD_API_KEY=DATADOG_KEY. The HMAC signing secret is minted by the server and
|
|
69932
|
+
printed exactly once, at create and at rotate-secret.
|
|
69933
|
+
`).action(drainsCommand);
|
|
67768
69934
|
program2.command("devices [action]").description("\u{1F4E1} Manage connected devices").option("--device-name <name>", "Device name").option("--group <group>", "Filter by device group").option("--payload <json>", "JSON payload for test/test-trigger", "{}").option("--timeout <ms>", "Timeout in milliseconds", "30000").option("--force", "Skip confirmation prompts").addHelpText("after", `
|
|
67769
69935
|
Arguments:
|
|
67770
69936
|
action Optional: list, status, enable, disable, remove, test, test-trigger
|
|
@@ -67808,7 +69974,7 @@ Examples:
|
|
|
67808
69974
|
$ lua jobs versions -i myJob View job versions
|
|
67809
69975
|
$ lua jobs history -i myJob View execution history
|
|
67810
69976
|
`).action(jobsCommand);
|
|
67811
|
-
program2.command("workflows [action] [target] [extra]").description("\u{1F9ED} Manage workflows and their runs (list, start, watch, cancel, resume, retry-step, resolve-step, raise-budget, approve, signal, replay, export, schedules)").option("-i, --workflow-name <name>", "Workflow name (or id)").option("-r, --run-id <id>", "Run id").option("-v, --workflow-version <ver>", "deploy/start/export/goals create/schedules create: a semver, 'latest' (newest push) or a version id").option("--json", "Print the raw {success,data} envelope").option("--all", "list: include dynamic workflows").option("--input <json|@file>", "start/run/goals create/schedules create: run input").option("--idempotency-key <key>", "start: idempotency key").option("--correlation-key <key>", "start/runs: correlation key").option("--tag <tag>", "start/runs/schedules create: tag (repeatable, \u2264 10)", collect, []).option("--budget-credits <n>", "start/schedules create: run budget (credits)").option("--wait <s>", "start: server long-poll \u2264 55 s").option("--follow", "start/logs: attach watch").option("--status <status>", "runs/goals list: filter by status").option("--workflow <name>", "runs: filter by workflow").option("--limit <n>", "runs/goals list/approval-payload --path: page size").option("--cursor <c>", "runs/goals list/approval-payload --path: page cursor").option("--sort <field>", "runs: -createdAt|createdAt|-durationMs|durationMs").option("--steps", "status: per-step table").option("--strict", "status: exit 4/5 by terminal status, 6 for a gated run").option("--compose <on|off>", "policy models set: may the composer be shown the model menu").option("--max-class <fast|balanced|strong>", "policy models set: ceiling for class requests and the class map").option("--consent-actions <n>", "policy models set: estimated actions above which a composed run shows the card").option("--allow <codes>", "policy models set: comma-separated approved codes to narrow the set to").option("--class-fast <codes>", "policy models set: ordered overrides of the fast class (comma-separated)").option("--class-balanced <codes>", "policy models set: ordered overrides of the balanced class (comma-separated)").option("--class-strong <codes>", "policy models set: ordered overrides of the strong class (comma-separated)").option("--class-map <pairs>", "policy models set: comma-separated <taskClass>=<modelClass> pairs").option("--pins <class-only|allowed>", "policy models set: may a composed definition pin a concrete code").option("--fallback <same-class|same-provider>", "policy models set: where a failed leg may hop to").option("--enabled <on|off>", "policy autonomy set: may a start inside the envelope skip the consent card").option("--max-duration <seconds>", "policy autonomy set: the envelope\u2019s duration bound, in seconds").option("--max-actions <n>", "policy autonomy set: the envelope\u2019s estimated-actions bound").option("--max-runs-per-hour <n>", "policy autonomy set: autonomous starts per hour, per agent").option("--forms <list>", "policy autonomy set: comma-separated forms the envelope admits (graph,script,static)").option("--clear <keys>", "policy autonomy set: comma-separated members to clear back to the platform default").option("--agent <agentId>", "policy autonomy: not supported \u2014 no route writes a per-agent envelope (see the refusal)").option("--kind <kind>", "clear-gate: the gate kind to clear (e.g. model_policy)").option("--after <seq>", "watch: replay from seq").option("--timeout <s>", "watch / start --follow: give up after s seconds while the run is still live (exit 7)").option("--events", "watch: print raw frames").option("--wait-for-human", "watch / start --follow: keep following through a human boundary (approval, input, signal, park) instead of exiting 8").option("--reason <text>", "cancel: reason").option("--step <id>", "resume/retry-step/resolve-step/logs: step id").option("--outcome <skip|complete|fail>", "resolve-step: the decision on the parked step (--action is accepted too)").option("--action <skip|complete|fail>", "resolve-step: alias of --outcome").option("--output <json|@file>", "resolve-step: the output a completed step would have produced (required with --outcome complete)").option("--credits <n>", "raise-budget: the new
|
|
69977
|
+
program2.command("workflows [action] [target] [extra]").description("\u{1F9ED} Manage workflows and their runs (list, start, watch, cancel, resume, retry-step, resolve-step, raise-budget, approve, signal, replay, export, schedules)").option("-i, --workflow-name <name>", "Workflow name (or id)").option("-r, --run-id <id>", "Run id").option("-v, --workflow-version <ver>", "deploy/start/export/goals create/schedules create: a semver, 'latest' (newest push) or a version id").option("--json", "Print the raw {success,data} envelope").option("--all", "list: include dynamic workflows").option("--input <json|@file>", "start/run/goals create/schedules create: run input").option("--idempotency-key <key>", "start: idempotency key").option("--correlation-key <key>", "start/runs: correlation key").option("--tag <tag>", "start/runs/schedules create: tag (repeatable, \u2264 10)", collect, []).option("--budget-credits <n>", "start/schedules create: run budget (credits)").option("--wait <s>", "start: server long-poll \u2264 55 s").option("--follow", "start/logs: attach watch").option("--status <status>", "runs/goals list: filter by status").option("--workflow <name>", "runs: filter by workflow").option("--limit <n>", "runs/goals list/approval-payload --path: page size").option("--cursor <c>", "runs/goals list/approval-payload --path: page cursor").option("--sort <field>", "runs: -createdAt|createdAt|-durationMs|durationMs").option("--steps", "status: per-step table").option("--strict", "status: exit 4/5 by terminal status, 6 for a gated run").option("--compose <on|off>", "policy models set: may the composer be shown the model menu").option("--max-class <fast|balanced|strong>", "policy models set: ceiling for class requests and the class map").option("--consent-actions <n>", "policy models set: estimated actions above which a composed run shows the card").option("--allow <codes>", "policy models set: comma-separated approved codes to narrow the set to").option("--class-fast <codes>", "policy models set: ordered overrides of the fast class (comma-separated)").option("--class-balanced <codes>", "policy models set: ordered overrides of the balanced class (comma-separated)").option("--class-strong <codes>", "policy models set: ordered overrides of the strong class (comma-separated)").option("--class-map <pairs>", "policy models set: comma-separated <taskClass>=<modelClass> pairs").option("--pins <class-only|allowed>", "policy models set: may a composed definition pin a concrete code").option("--fallback <same-class|same-provider>", "policy models set: where a failed leg may hop to").option("--enabled <on|off>", "policy autonomy set: may a start inside the envelope skip the consent card").option("--max-duration <seconds>", "policy autonomy set: the envelope\u2019s duration bound, in seconds").option("--max-actions <n>", "policy autonomy set: the envelope\u2019s estimated-actions bound").option("--max-runs-per-hour <n>", "policy autonomy set: autonomous starts per hour, per agent").option("--forms <list>", "policy autonomy set: comma-separated forms the envelope admits (graph,script,static)").option("--clear <keys>", "policy autonomy set: comma-separated members to clear back to the platform default").option("--agent <agentId>", "policy autonomy: not supported \u2014 no route writes a per-agent envelope (see the refusal)").option("--kind <kind>", "clear-gate: the gate kind to clear (e.g. model_policy)").option("--after <seq>", "watch: replay from seq").option("--timeout <s>", "watch / start --follow: give up after s seconds while the run is still live (exit 7)").option("--events", "watch: print raw frames").option("--wait-for-human", "watch / start --follow: keep following through a human boundary (approval, input, signal, park) instead of exiting 8").option("--reason <text>", "cancel: reason").option("--step <id>", "resume/retry-step/resolve-step/logs: step id").option("--outcome <skip|complete|fail>", "resolve-step: the decision on the parked step (--action is accepted too)").option("--action <skip|complete|fail>", "resolve-step: alias of --outcome").option("--output <json|@file>", "resolve-step: the output a completed step would have produced (required with --outcome complete)").option("--credits <n>", "raise-budget: the new priced cap of a budget-parked run, in the run's own budget unit \u2014 credits, or actions on a seat plan (above the current one)").option("--max-steps <n>", "raise-budget: the new step cap").option("--max-job-seconds <n>", "raise-budget: the new Job-tier seconds cap").option("--max-duration-seconds <n>", "raise-budget: the new wall-clock cap").option("--data <json|@file>", "resume: resumeData").option("--approval <id>", "approve/approval-payload: approval id").option("--path <array.path>", "approval-payload: page one array of a large payload (--cursor / --limit inside it)").option("--decision <approve|deny>", "approve: decision (default approve)").option("--note <text>", "approve/retry-step/resolve-step/raise-budget/goals close: note").option("--edit <json|@file>", "approve: edited payload (small inline edits)").option("--fingerprint <f>", "approve: payloadFingerprint (mandatory with --edit)").option("--payload <json|@file>", "signal: payload").option("--dedupe-key <key>", "signal: dedupe key").option("--local", "replay: replay locally against the compiled artifact").option("--since <dur>", "logs: window").option("--yes", "delete/delete-run/schedules delete: skip confirmation").option("--force", "delete: cancel in-flight runs first \xB7 run: seed from a changed graph \xB7 export: overwrite files").option("--step-output <id=json>", "run: complete a step with this output (repeatable)", collect, []).option("--approve <id[=@payload]>", "run: pre-answer an approval (repeatable)", collect, []).option("--deny <id[=@reason]>", "run: pre-deny an approval (repeatable)", collect, []).option("--signal <name=json>", "run: pre-supply a waitForSignal payload (repeatable)", collect, []).option("--from-run <runId>", "run: seed completed steps from a real run").option("--record <dir>", "run: record agent/tool outputs as fixtures").option("--fixtures <dir>", "run: replay recorded fixtures").option("--step-wall <s>", "run: per-step wall in seconds (default 600)").option("--job-wall <s>", "run: virtual wall for tier:'job' steps \u2014 splits at 14400 s segments, > 86400 is exit 2").option("--ledger-out <file>", "run: write the in-memory ledger as JSON").option("--agents <fake|live>", "run: fake agent steps (default) or call the dev API").option("--now <iso>", "run: virtual clock start").option("--park <id>", "run: simulate a platform-fault park of this step (repeatable)", collect, []).option("--fast-retries", "run: collapse retry backoff waits to 0").option("--real-time", "run: actually wait on sleeps/backoffs instead of fast-forwarding").option("--artefacts-dir <dir>", "run: back ctx.artefacts.* on disk").option("--workspace <dir>", "run: the checkout Job-tier code steps run in (ctx.workspace + ctx.exec / ctx.$)").option("--env <KEY=value>", "run: local env.template() overlay (repeatable; missing key \u21D2 exit 2)", collect, []).option("--max-ticks <n>", "run (script form): tick cap before SCRIPT_TICK_LIMIT (default 64)").option("--until <iso>", "archive-runs: window end").option("--out <dir>", "archive-runs: destination dir (archive-index.ndjson + <runId>.zip) \xB7 export: target dir").option("--concurrency <n>", "archive-runs: parallel exports (default 2, max 5)").option("--no-inputs", "archive-runs: exclude run inputs from the bundle").option("--no-artefacts", "archive-runs: exclude artefacts from the bundle").option("--retention-days <n>", "archive-runs: org run retention (default 90) \u2014 --since must fit retention \u2212 7 d").option("--connection <id>", "archive-runs: org storage connection for s3:// / gs:// sinks").option("--release", "workspace: release the run workspace (R42)").option("--attempt <n>", "job-logs: attempt (default latest)").option("--tail <n>", "job-logs: log lines (1..2000, default 200)").option("--objective <text>", "goals create: the objective (\u2264 2000 chars)").option("--judge-predicate <spec>", "goals create: deterministic judge \u2014 '<path> <op> [value]' (e.g. 'output.done truthy'), JSON or @file").option("--judge-agent <agentId|'$self'>", "goals create: judge agent \u2014 write '$self' quoted (or self); it needs --judge-role").option("--judge-role <json|@file>", "goals create: D25 role {name,instructions,tools} for a '$self' judge").option("--schema <json|@file>", "goals create: judge output JsonSchema (must declare a boolean `done`)").option("--cadence <cron|json|@file>", "goals create/schedules create: cadence entry (repeatable, \u2264 5); goals: none \u21D2 immediate", collect, []).option("--timezone <tz>", "goals create/edit/schedules create: IANA timezone for bare cron cadences").option("--notify <emailApp|email|app|off>", "schedules create: where each fire notifies").option("--backfill-on-enable <n|none>", "schedules create/patch/resume: replay \u2264 n missed fires on re-enable (patch: none clears it)").option("--backfill-now", "schedules resume (or patch --paused false): one-shot backfill on THIS re-enable").option("--paused <true|false>", "schedules patch: pause (true) or re-enable (false) the schedule").option("--max-runs <n>", "goals create/edit/raise: iteration cap (1..100)").option("--max-total-credits <n>", "goals create: lineage-wide credit gate").option("--max-credits <n|none>", "goals edit/raise: lineage-wide credit gate (edit: none clears it)").option("--every <interval>", "goals edit/schedules create: interval cadence \u2014 900, 15m, 2h (whole minutes, \u2265 60s)").option("--if-match <updatedAt>", "goals edit/raise: refuse the write if the goal changed since this updatedAt").addHelpText("after", `
|
|
67812
69978
|
Arguments:
|
|
67813
69979
|
action list \xB7 view \xB7 versions \xB7 deploy \xB7 activate \xB7 deactivate \xB7 start \xB7 run \xB7 runs \xB7 status \xB7
|
|
67814
69980
|
watch \xB7 cancel \xB7 resume \xB7 retry-step \xB7 resolve-step \xB7 raise-budget \xB7 approve \xB7 approval-payload \xB7
|
|
@@ -68228,7 +70394,7 @@ __name(visibleLength, "visibleLength");
|
|
|
68228
70394
|
function printBanner(opts) {
|
|
68229
70395
|
if (process.env.LUA_NO_BANNER) return;
|
|
68230
70396
|
if (!process.stdout.isTTY && !process.env.LUA_FORCE_BANNER) return;
|
|
68231
|
-
if (
|
|
70397
|
+
if (noColorEnabled()) {
|
|
68232
70398
|
process.stdout.write(`
|
|
68233
70399
|
lua-cli v${opts.version} \xB7 Build and deploy AI agents with superpowers
|
|
68234
70400
|
|
|
@@ -68251,6 +70417,7 @@ __name(printBanner, "printBanner");
|
|
|
68251
70417
|
// src/index.ts
|
|
68252
70418
|
init_package_root();
|
|
68253
70419
|
var CLI_VERSION = getCliVersion();
|
|
70420
|
+
configureChalkColor(chalk5);
|
|
68254
70421
|
var args = process.argv.slice(2);
|
|
68255
70422
|
var isBareInvocation = args.length === 0;
|
|
68256
70423
|
var isHelpInvocation = args.includes("--help") || args.includes("-h");
|