lua-cli 3.37.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 +17 -0
- package/dist/api-exports.js +216 -2
- package/dist/api-exports.js.map +1 -1
- package/dist/index.js +2099 -137
- package/dist/index.js.map +1 -1
- package/dist/workflow-builder.js +215 -0
- package/dist/workflow-builder.js.map +1 -1
- package/docs/README.md +2 -2
- package/package.json +2 -2
- 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
|
}
|
|
@@ -1973,17 +2073,17 @@ function isWorkflowApprovalOutput(value3) {
|
|
|
1973
2073
|
return typeof v.approved === "boolean" && WORKFLOW_APPROVAL_OUTPUT_DECISIONS.includes(v.decision) && typeof v.text === "string";
|
|
1974
2074
|
}
|
|
1975
2075
|
function extractSingleJsonValue(text) {
|
|
1976
|
-
const
|
|
1977
|
-
if (!
|
|
2076
|
+
const trimmed2 = (text ?? "").trim();
|
|
2077
|
+
if (!trimmed2) return {
|
|
1978
2078
|
reason: "reply is empty"
|
|
1979
2079
|
};
|
|
1980
2080
|
const fenced = [
|
|
1981
|
-
...
|
|
2081
|
+
...trimmed2.matchAll(JSON_FENCE_RE)
|
|
1982
2082
|
];
|
|
1983
2083
|
if (fenced.length > 1) return {
|
|
1984
2084
|
reason: "reply carries more than one fenced block"
|
|
1985
2085
|
};
|
|
1986
|
-
const candidate = fenced.length === 1 ? fenced[0][1].trim() :
|
|
2086
|
+
const candidate = fenced.length === 1 ? fenced[0][1].trim() : trimmed2;
|
|
1987
2087
|
try {
|
|
1988
2088
|
return {
|
|
1989
2089
|
value: JSON.parse(candidate)
|
|
@@ -1994,17 +2094,17 @@ function extractSingleJsonValue(text) {
|
|
|
1994
2094
|
};
|
|
1995
2095
|
}
|
|
1996
2096
|
const opens = [
|
|
1997
|
-
|
|
1998
|
-
|
|
2097
|
+
trimmed2.indexOf("{"),
|
|
2098
|
+
trimmed2.indexOf("[")
|
|
1999
2099
|
].filter((i) => i !== -1);
|
|
2000
2100
|
const start = opens.length ? Math.min(...opens) : -1;
|
|
2001
|
-
const end = Math.max(
|
|
2101
|
+
const end = Math.max(trimmed2.lastIndexOf("}"), trimmed2.lastIndexOf("]"));
|
|
2002
2102
|
if (start === -1 || end <= start) return {
|
|
2003
2103
|
reason: "reply is not JSON"
|
|
2004
2104
|
};
|
|
2005
2105
|
try {
|
|
2006
2106
|
return {
|
|
2007
|
-
value: JSON.parse(
|
|
2107
|
+
value: JSON.parse(trimmed2.slice(start, end + 1))
|
|
2008
2108
|
};
|
|
2009
2109
|
} catch {
|
|
2010
2110
|
return {
|
|
@@ -2080,12 +2180,39 @@ function effectiveAgentFeatures(base, override, rule) {
|
|
|
2080
2180
|
if (rule === "wholesale") return override || base || void 0;
|
|
2081
2181
|
return effectiveAgentFeatureRows(base, override).rows;
|
|
2082
2182
|
}
|
|
2083
|
-
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_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;
|
|
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;
|
|
2084
2184
|
var init_dist = __esm({
|
|
2085
2185
|
"../shared-types/dist/index.mjs"() {
|
|
2086
2186
|
"use strict";
|
|
2087
2187
|
__defProp2 = Object.defineProperty;
|
|
2088
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");
|
|
2089
2216
|
__name(isPersonaTextObject, "isPersonaTextObject");
|
|
2090
2217
|
__name2(isPersonaTextObject, "isPersonaTextObject");
|
|
2091
2218
|
__name(flattenPersonaText, "flattenPersonaText");
|
|
@@ -2757,6 +2884,124 @@ This text is who you are for this person. As you learn them, their name, their w
|
|
|
2757
2884
|
"workflow-script",
|
|
2758
2885
|
"workflow"
|
|
2759
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");
|
|
2760
3005
|
CORE_DRAINING_CODE = "CORE_DRAINING";
|
|
2761
3006
|
CORE_DRAINING_DEFAULT_RETRY_MS = 1e3;
|
|
2762
3007
|
CORE_DRAINING_MAX_RETRY_MS = 5e3;
|
|
@@ -4792,10 +5037,10 @@ function parseModelTemplate(model) {
|
|
|
4792
5037
|
if (!looksLikeModelTemplate(model)) return {
|
|
4793
5038
|
kind: "static"
|
|
4794
5039
|
};
|
|
4795
|
-
const
|
|
4796
|
-
const m = WORKFLOW_MODEL_TEMPLATE_RE.exec(
|
|
5040
|
+
const trimmed2 = model.trim();
|
|
5041
|
+
const m = WORKFLOW_MODEL_TEMPLATE_RE.exec(trimmed2);
|
|
4797
5042
|
if (!m) {
|
|
4798
|
-
const inner = /^\$\{([^}]*)\}$/.exec(
|
|
5043
|
+
const inner = /^\$\{([^}]*)\}$/.exec(trimmed2)?.[1];
|
|
4799
5044
|
const root = inner?.split(/[.|]/, 1)[0];
|
|
4800
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";
|
|
4801
5046
|
return {
|
|
@@ -4825,7 +5070,7 @@ function parseModelTemplate(model) {
|
|
|
4825
5070
|
return {
|
|
4826
5071
|
kind: "template",
|
|
4827
5072
|
template: {
|
|
4828
|
-
placeholder:
|
|
5073
|
+
placeholder: trimmed2,
|
|
4829
5074
|
path: path26,
|
|
4830
5075
|
default: dflt
|
|
4831
5076
|
}
|
|
@@ -4834,7 +5079,7 @@ function parseModelTemplate(model) {
|
|
|
4834
5079
|
return {
|
|
4835
5080
|
kind: "template",
|
|
4836
5081
|
template: {
|
|
4837
|
-
placeholder:
|
|
5082
|
+
placeholder: trimmed2,
|
|
4838
5083
|
path: path26
|
|
4839
5084
|
}
|
|
4840
5085
|
};
|
|
@@ -5487,9 +5732,9 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
5487
5732
|
const registry = opts.approvedModels;
|
|
5488
5733
|
if (registry === void 0) return;
|
|
5489
5734
|
if (registry === "unavailable") {
|
|
5490
|
-
const
|
|
5491
|
-
if (
|
|
5492
|
-
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);
|
|
5493
5738
|
}
|
|
5494
5739
|
return;
|
|
5495
5740
|
}
|
|
@@ -12454,8 +12699,8 @@ function ensureGitignored(rootDir, entry, afterEntry) {
|
|
|
12454
12699
|
return;
|
|
12455
12700
|
}
|
|
12456
12701
|
}
|
|
12457
|
-
const
|
|
12458
|
-
fs2.writeFileSync(gitignorePath,
|
|
12702
|
+
const trimmed2 = content.endsWith("\n") ? content : content + "\n";
|
|
12703
|
+
fs2.writeFileSync(gitignorePath, trimmed2 + entry + "\n");
|
|
12459
12704
|
}
|
|
12460
12705
|
function hasEnvFile() {
|
|
12461
12706
|
return fs2.existsSync(path2.join(process.cwd(), ".env"));
|
|
@@ -27854,6 +28099,7 @@ var init_mcp_server_handler = __esm({
|
|
|
27854
28099
|
|
|
27855
28100
|
// src/index.ts
|
|
27856
28101
|
import { Command } from "commander";
|
|
28102
|
+
import chalk5 from "chalk";
|
|
27857
28103
|
|
|
27858
28104
|
// src/cli/parse-agent-version.ts
|
|
27859
28105
|
import { InvalidArgumentError } from "commander";
|
|
@@ -29736,8 +29982,8 @@ var PostProcessorApi = class extends HttpClient {
|
|
|
29736
29982
|
// src/utils/sync-fetch.ts
|
|
29737
29983
|
init_developer_api_service();
|
|
29738
29984
|
init_mcp_server_handler();
|
|
29739
|
-
function normalizeForComparison(
|
|
29740
|
-
return
|
|
29985
|
+
function normalizeForComparison(str2) {
|
|
29986
|
+
return str2.trim().replace(/\\'/g, "'").replace(/\\"/g, '"').replace(/\\\\/g, "\\").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
29741
29987
|
}
|
|
29742
29988
|
__name(normalizeForComparison, "normalizeForComparison");
|
|
29743
29989
|
function canonicalizeForm(value3) {
|
|
@@ -31582,12 +31828,30 @@ __name(buildLogsCommand, "buildLogsCommand");
|
|
|
31582
31828
|
// src/utils/sync-display.ts
|
|
31583
31829
|
init_dist();
|
|
31584
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
|
|
31585
31850
|
var colors = {
|
|
31586
|
-
red: "\x1B[31m",
|
|
31587
|
-
green: "\x1B[32m",
|
|
31588
|
-
gray: "\x1B[90m",
|
|
31589
|
-
|
|
31590
|
-
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")
|
|
31591
31855
|
};
|
|
31592
31856
|
var primitiveTypeLabels = {
|
|
31593
31857
|
skill: "SKILLS",
|
|
@@ -31599,31 +31863,31 @@ var primitiveTypeLabels = {
|
|
|
31599
31863
|
};
|
|
31600
31864
|
function showColoredDiff(oldText, newText, oldLabel = "Server", newLabel = "Local") {
|
|
31601
31865
|
if (!oldText && !newText) {
|
|
31602
|
-
console.log(colors.gray
|
|
31866
|
+
console.log(colors.gray("(both empty)"));
|
|
31603
31867
|
return;
|
|
31604
31868
|
}
|
|
31605
31869
|
if (!oldText) {
|
|
31606
|
-
console.log(colors.green
|
|
31870
|
+
console.log(colors.green(`+ (${newLabel} only - no ${oldLabel} content)`));
|
|
31607
31871
|
return;
|
|
31608
31872
|
}
|
|
31609
31873
|
if (!newText) {
|
|
31610
|
-
console.log(colors.red
|
|
31874
|
+
console.log(colors.red(`- (${oldLabel} only - no ${newLabel} content)`));
|
|
31611
31875
|
return;
|
|
31612
31876
|
}
|
|
31613
31877
|
const diff = diffLines(oldText, newText);
|
|
31614
31878
|
diff.forEach((part) => {
|
|
31615
31879
|
if (part.added) {
|
|
31616
|
-
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)));
|
|
31617
31881
|
} else if (part.removed) {
|
|
31618
|
-
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)));
|
|
31619
31883
|
} else {
|
|
31620
31884
|
const lines = part.value.split("\n").filter((l) => l);
|
|
31621
31885
|
if (lines.length <= 6) {
|
|
31622
|
-
lines.forEach((line) => console.log(colors.gray
|
|
31886
|
+
lines.forEach((line) => console.log(colors.gray(" " + line)));
|
|
31623
31887
|
} else {
|
|
31624
|
-
lines.slice(0, 3).forEach((line) => console.log(colors.gray
|
|
31625
|
-
console.log(colors.gray
|
|
31626
|
-
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)));
|
|
31627
31891
|
}
|
|
31628
31892
|
}
|
|
31629
31893
|
});
|
|
@@ -31631,8 +31895,8 @@ function showColoredDiff(oldText, newText, oldLabel = "Server", newLabel = "Loca
|
|
|
31631
31895
|
__name(showColoredDiff, "showColoredDiff");
|
|
31632
31896
|
function showPersonaDiff(serverPersona, localPersona) {
|
|
31633
31897
|
console.log("\n" + "=".repeat(60));
|
|
31634
|
-
console.log(colors.bold
|
|
31635
|
-
console.log(colors.red
|
|
31898
|
+
console.log(colors.bold("PERSONA DIFF"));
|
|
31899
|
+
console.log(colors.red("- Server (deployed)") + " " + colors.green("+ Local (code)"));
|
|
31636
31900
|
console.log("=".repeat(60) + "\n");
|
|
31637
31901
|
showColoredDiff(flattenPersonaTextAll(serverPersona), flattenPersonaTextAll(localPersona), "Server", "Local");
|
|
31638
31902
|
console.log("\n" + "=".repeat(60) + "\n");
|
|
@@ -31640,19 +31904,19 @@ function showPersonaDiff(serverPersona, localPersona) {
|
|
|
31640
31904
|
__name(showPersonaDiff, "showPersonaDiff");
|
|
31641
31905
|
function showNameDiff(serverName, localName) {
|
|
31642
31906
|
console.log("\n" + "=".repeat(60));
|
|
31643
|
-
console.log(colors.bold
|
|
31907
|
+
console.log(colors.bold("NAME DIFF"));
|
|
31644
31908
|
console.log("=".repeat(60));
|
|
31645
|
-
console.log(colors.red
|
|
31646
|
-
console.log(colors.green
|
|
31909
|
+
console.log(colors.red(`- Server: "${serverName || "(none)"}"`));
|
|
31910
|
+
console.log(colors.green(`+ Local: "${localName || "(none)"}"`));
|
|
31647
31911
|
console.log("=".repeat(60) + "\n");
|
|
31648
31912
|
}
|
|
31649
31913
|
__name(showNameDiff, "showNameDiff");
|
|
31650
31914
|
function showModelDiff(serverModel, localModel) {
|
|
31651
31915
|
console.log("\n" + "=".repeat(60));
|
|
31652
|
-
console.log(colors.bold
|
|
31916
|
+
console.log(colors.bold("MODEL DIFF"));
|
|
31653
31917
|
console.log("=".repeat(60));
|
|
31654
|
-
console.log(colors.red
|
|
31655
|
-
console.log(colors.green
|
|
31918
|
+
console.log(colors.red(`- Server: "${serverModel || "(none)"}"`));
|
|
31919
|
+
console.log(colors.green(`+ Local: "${localModel || "(none)"}"`));
|
|
31656
31920
|
console.log("=".repeat(60) + "\n");
|
|
31657
31921
|
}
|
|
31658
31922
|
__name(showModelDiff, "showModelDiff");
|
|
@@ -31671,17 +31935,17 @@ function showPrimitiveDrift(items, backupAvailable) {
|
|
|
31671
31935
|
}
|
|
31672
31936
|
for (const [type, groupItems] of grouped) {
|
|
31673
31937
|
const label2 = primitiveTypeLabels[type] ?? type.toUpperCase();
|
|
31674
|
-
console.log("\n" + colors.bold
|
|
31938
|
+
console.log("\n" + colors.bold(`\u2501\u2501\u2501 ${label2} \u2501\u2501\u2501`));
|
|
31675
31939
|
for (const item of groupItems) {
|
|
31676
|
-
console.log("\n " + colors.bold
|
|
31677
|
-
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)");
|
|
31678
31942
|
console.log(` Local: ${localDisplay}`);
|
|
31679
|
-
const serverDisplay = item.serverVersion ? `v${item.serverVersion}` : colors.gray
|
|
31943
|
+
const serverDisplay = item.serverVersion ? `v${item.serverVersion}` : colors.gray("(not found)");
|
|
31680
31944
|
console.log(` Server: ${serverDisplay}`);
|
|
31681
31945
|
}
|
|
31682
31946
|
}
|
|
31683
31947
|
if (backupAvailable !== void 0) {
|
|
31684
|
-
const backupDisplay = backupAvailable ? colors.green
|
|
31948
|
+
const backupDisplay = backupAvailable ? colors.green("available") : colors.red("not available");
|
|
31685
31949
|
console.log(`
|
|
31686
31950
|
Backup: ${backupDisplay}`);
|
|
31687
31951
|
}
|
|
@@ -31703,14 +31967,14 @@ function showPrimitiveDriftSummary(items) {
|
|
|
31703
31967
|
versionInfo = `local only${vSuffix(item.localVersion)}`;
|
|
31704
31968
|
}
|
|
31705
31969
|
const paddedLabel = label2.padEnd(16);
|
|
31706
|
-
console.log(` ${colors.red
|
|
31970
|
+
console.log(` ${colors.red(paddedLabel)} ${item.name} (${versionInfo})`);
|
|
31707
31971
|
}
|
|
31708
31972
|
}
|
|
31709
31973
|
__name(showPrimitiveDriftSummary, "showPrimitiveDriftSummary");
|
|
31710
31974
|
function showGovernanceDiff(serverGovernance, localGovernance) {
|
|
31711
31975
|
console.log("\n" + "=".repeat(60));
|
|
31712
|
-
console.log(colors.bold
|
|
31713
|
-
console.log(colors.red
|
|
31976
|
+
console.log(colors.bold("GOVERNANCE DIFF"));
|
|
31977
|
+
console.log(colors.red("- Server (deployed)") + " " + colors.green("+ Local (code)"));
|
|
31714
31978
|
console.log("=".repeat(60) + "\n");
|
|
31715
31979
|
showColoredDiff(JSON.stringify(serverGovernance, null, 2) || "(none)", JSON.stringify(localGovernance, null, 2) || "(none)", "Server", "Local");
|
|
31716
31980
|
console.log("\n" + "=".repeat(60) + "\n");
|
|
@@ -37008,6 +37272,9 @@ init_artifact_loader();
|
|
|
37008
37272
|
init_types();
|
|
37009
37273
|
init_analytics();
|
|
37010
37274
|
|
|
37275
|
+
// src/utils/aliases.ts
|
|
37276
|
+
init_dist();
|
|
37277
|
+
|
|
37011
37278
|
// src/utils/suggest.ts
|
|
37012
37279
|
function levenshtein(a, b) {
|
|
37013
37280
|
const m = a.length, n2 = b.length;
|
|
@@ -37140,21 +37407,58 @@ var ALIAS_MAP = {
|
|
|
37140
37407
|
everything: "all"
|
|
37141
37408
|
})
|
|
37142
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
|
+
},
|
|
37143
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.
|
|
37144
37460
|
canonical: [
|
|
37145
|
-
|
|
37146
|
-
"job",
|
|
37147
|
-
"webhook",
|
|
37148
|
-
"preprocessor",
|
|
37149
|
-
"postprocessor",
|
|
37150
|
-
"user_message",
|
|
37151
|
-
"agent_response",
|
|
37152
|
-
"agent_error",
|
|
37153
|
-
"mcp",
|
|
37154
|
-
"runtime",
|
|
37155
|
-
"rag",
|
|
37156
|
-
"device",
|
|
37157
|
-
"device-trigger"
|
|
37461
|
+
...AGENT_LOG_SOURCES
|
|
37158
37462
|
],
|
|
37159
37463
|
aliases: lowerKeys({
|
|
37160
37464
|
skills: "skill",
|
|
@@ -40353,8 +40657,8 @@ async function gitUserConfigured(cwd) {
|
|
|
40353
40657
|
cwd
|
|
40354
40658
|
});
|
|
40355
40659
|
if (code !== 0) return void 0;
|
|
40356
|
-
const
|
|
40357
|
-
return
|
|
40660
|
+
const trimmed2 = stdout.trim();
|
|
40661
|
+
return trimmed2.length > 0 ? trimmed2 : void 0;
|
|
40358
40662
|
} catch {
|
|
40359
40663
|
return void 0;
|
|
40360
40664
|
}
|
|
@@ -40379,8 +40683,8 @@ async function getRemoteOriginUrl(cwd) {
|
|
|
40379
40683
|
cwd
|
|
40380
40684
|
});
|
|
40381
40685
|
if (code !== 0) return null;
|
|
40382
|
-
const
|
|
40383
|
-
return
|
|
40686
|
+
const trimmed2 = stdout.trim();
|
|
40687
|
+
return trimmed2.length > 0 ? trimmed2 : null;
|
|
40384
40688
|
} catch {
|
|
40385
40689
|
return null;
|
|
40386
40690
|
}
|
|
@@ -40751,9 +41055,9 @@ async function readCurrentBranch(cwd) {
|
|
|
40751
41055
|
cwd
|
|
40752
41056
|
});
|
|
40753
41057
|
if (res.code !== 0) return null;
|
|
40754
|
-
const
|
|
40755
|
-
if (!
|
|
40756
|
-
return
|
|
41058
|
+
const trimmed2 = res.stdout.trim();
|
|
41059
|
+
if (!trimmed2 || trimmed2 === "HEAD") return null;
|
|
41060
|
+
return trimmed2;
|
|
40757
41061
|
}
|
|
40758
41062
|
__name(readCurrentBranch, "readCurrentBranch");
|
|
40759
41063
|
|
|
@@ -40871,8 +41175,8 @@ __name(reportFailure, "reportFailure");
|
|
|
40871
41175
|
var GIT_MESSAGES = {
|
|
40872
41176
|
pushStaged: "lua: push staged code",
|
|
40873
41177
|
createVersion: /* @__PURE__ */ __name((version, message) => {
|
|
40874
|
-
const
|
|
40875
|
-
return
|
|
41178
|
+
const trimmed2 = message?.trim();
|
|
41179
|
+
return trimmed2 ? `lua: create version v${version}: ${trimmed2}` : `lua: create version v${version}`;
|
|
40876
41180
|
}, "createVersion"),
|
|
40877
41181
|
promote: /* @__PURE__ */ __name((version) => `lua: promote v${version} to production`, "promote"),
|
|
40878
41182
|
delete: /* @__PURE__ */ __name((version) => `lua: delete version v${version}`, "delete"),
|
|
@@ -43489,17 +43793,22 @@ var LogsApi = class extends HttpClient {
|
|
|
43489
43793
|
}
|
|
43490
43794
|
/**
|
|
43491
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
|
+
*
|
|
43492
43801
|
* @param agentId - The ID of the agent
|
|
43493
43802
|
* @param limit - Number of logs per page (default: 20)
|
|
43494
|
-
* @param page - Page number (default: 1)
|
|
43803
|
+
* @param page - Page number (default: 1); ignored when `filters.cursor` is set
|
|
43495
43804
|
* @param filters - Optional filters to narrow log results
|
|
43496
|
-
* @returns Promise resolving to an ApiResponse containing logs and pagination
|
|
43805
|
+
* @returns Promise resolving to an ApiResponse containing logs, nextCursor and pagination
|
|
43497
43806
|
*/
|
|
43498
43807
|
async getAgentLogs(agentId, limit, page, filters = {}) {
|
|
43499
43808
|
const queryParams = new URLSearchParams({
|
|
43500
|
-
limit: limit.toString()
|
|
43501
|
-
page: page.toString()
|
|
43809
|
+
limit: limit.toString()
|
|
43502
43810
|
});
|
|
43811
|
+
if (!filters.cursor) queryParams.append("page", page.toString());
|
|
43503
43812
|
if (filters.logSource) queryParams.append("logSource", filters.logSource);
|
|
43504
43813
|
if (filters.primitiveId) queryParams.append("primitiveId", filters.primitiveId);
|
|
43505
43814
|
if (filters.primitiveName) queryParams.append("primitiveName", filters.primitiveName);
|
|
@@ -43507,6 +43816,10 @@ var LogsApi = class extends HttpClient {
|
|
|
43507
43816
|
if (filters.toolName) queryParams.append("toolName", filters.toolName);
|
|
43508
43817
|
if (filters.logType) queryParams.append("logType", filters.logType);
|
|
43509
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);
|
|
43510
43823
|
return this.httpGet(`/developer/agents/${agentId}/logs?${queryParams.toString()}`, {});
|
|
43511
43824
|
}
|
|
43512
43825
|
};
|
|
@@ -43807,14 +44120,14 @@ async function startChatLoop(chatEnv, probeWindow) {
|
|
|
43807
44120
|
});
|
|
43808
44121
|
rl.prompt();
|
|
43809
44122
|
rl.on("line", async (input) => {
|
|
43810
|
-
const
|
|
43811
|
-
if (!
|
|
44123
|
+
const trimmed2 = input.trim();
|
|
44124
|
+
if (!trimmed2) {
|
|
43812
44125
|
rl.prompt();
|
|
43813
44126
|
return;
|
|
43814
44127
|
}
|
|
43815
44128
|
let messages;
|
|
43816
44129
|
try {
|
|
43817
|
-
messages = await parseMessageWithAttachments(
|
|
44130
|
+
messages = await parseMessageWithAttachments(trimmed2);
|
|
43818
44131
|
} catch (error) {
|
|
43819
44132
|
console.error(`
|
|
43820
44133
|
\u274C ${error instanceof Error ? error.message : "Failed to process attachments"}
|
|
@@ -46632,8 +46945,8 @@ async function promptAreaCode() {
|
|
|
46632
46945
|
default: ""
|
|
46633
46946
|
}
|
|
46634
46947
|
]);
|
|
46635
|
-
const
|
|
46636
|
-
return
|
|
46948
|
+
const trimmed2 = pattern.trim();
|
|
46949
|
+
return trimmed2.length > 0 ? trimmed2 : void 0;
|
|
46637
46950
|
}
|
|
46638
46951
|
__name(promptAreaCode, "promptAreaCode");
|
|
46639
46952
|
function smsLabel(transportOrUndefined) {
|
|
@@ -47578,6 +47891,7 @@ var CallMetricsApi = class extends HttpClient {
|
|
|
47578
47891
|
|
|
47579
47892
|
// src/commands/logs.ts
|
|
47580
47893
|
init_cli_error();
|
|
47894
|
+
init_dist();
|
|
47581
47895
|
var ALL_VALID_SOURCES = AGENT_LOG_SOURCES;
|
|
47582
47896
|
var ENTITY_SOURCES = /* @__PURE__ */ new Set([
|
|
47583
47897
|
"skill",
|
|
@@ -47588,19 +47902,35 @@ var ENTITY_SOURCES = /* @__PURE__ */ new Set([
|
|
|
47588
47902
|
"device"
|
|
47589
47903
|
]);
|
|
47590
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;
|
|
47591
47912
|
async function logsCommand(cmdObj) {
|
|
47592
47913
|
return withErrorHandling(async () => {
|
|
47914
|
+
const pageGiven = cmdObj?.page !== void 0 && cmdObj?.page !== null && cmdObj?.page !== "";
|
|
47593
47915
|
const options = {
|
|
47594
47916
|
type: cmdObj?.type || null,
|
|
47595
47917
|
name: cmdObj?.name || null,
|
|
47596
47918
|
limit: cmdObj?.limit ? parseInt(cmdObj.limit, 10) : 20,
|
|
47597
|
-
page:
|
|
47919
|
+
page: pageGiven ? parseInt(cmdObj.page, 10) : 1,
|
|
47920
|
+
pageGiven,
|
|
47598
47921
|
json: cmdObj?.json || false,
|
|
47599
47922
|
userId: cmdObj?.userId || null,
|
|
47600
47923
|
agentId: cmdObj?.agentId || null,
|
|
47601
47924
|
direction: cmdObj?.direction || null,
|
|
47602
|
-
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
|
|
47603
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
|
+
}
|
|
47604
47934
|
const { agentId: configAgentId, apiKey } = await initializeCommand();
|
|
47605
47935
|
const effectiveAgentId = options.agentId || configAgentId;
|
|
47606
47936
|
if (options.type === "calls") {
|
|
@@ -47615,7 +47945,18 @@ async function logsCommand(cmdObj) {
|
|
|
47615
47945
|
return;
|
|
47616
47946
|
}
|
|
47617
47947
|
const logsApi = new LogsApi(BASE_URLS.API, apiKey);
|
|
47618
|
-
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
|
+
});
|
|
47619
47960
|
if (hasNonInteractiveFlags) {
|
|
47620
47961
|
await nonInteractiveLogs(logsApi, effectiveAgentId, apiKey, options);
|
|
47621
47962
|
} else {
|
|
@@ -47623,13 +47964,6 @@ async function logsCommand(cmdObj) {
|
|
|
47623
47964
|
`);
|
|
47624
47965
|
await interactiveLogs(logsApi, effectiveAgentId, apiKey);
|
|
47625
47966
|
}
|
|
47626
|
-
trackEvent("cli_logs_action", {
|
|
47627
|
-
filter_type: options.type || null,
|
|
47628
|
-
json_output: options.json || false,
|
|
47629
|
-
non_interactive: hasNonInteractiveFlags,
|
|
47630
|
-
page_requested: options.page || 1,
|
|
47631
|
-
agent_id_override: !!options.agentId
|
|
47632
|
-
});
|
|
47633
47967
|
}, "logs viewing");
|
|
47634
47968
|
}
|
|
47635
47969
|
__name(logsCommand, "logsCommand");
|
|
@@ -47681,7 +48015,7 @@ function renderLogEntry(log, isLast) {
|
|
|
47681
48015
|
const logSource = log.metadata?.logSource;
|
|
47682
48016
|
const primitiveId = log.metadata?.primitiveId;
|
|
47683
48017
|
const primitiveName = log.metadata?.primitiveName;
|
|
47684
|
-
const { toolName, channel, userId } = log.metadata;
|
|
48018
|
+
const { toolName, channel, userId, environment, agentVersion } = log.metadata;
|
|
47685
48019
|
const icon = getLogIcon(log.subType, logSource);
|
|
47686
48020
|
const color = getLogColor(log.subType, logSource);
|
|
47687
48021
|
console.log(color(`${icon} [${timestamp}] ${log.subType.toUpperCase()}`));
|
|
@@ -47704,6 +48038,12 @@ function renderLogEntry(log, isLast) {
|
|
|
47704
48038
|
console.log(chalk2.gray(` Tool Name: ${toolName}`));
|
|
47705
48039
|
}
|
|
47706
48040
|
}
|
|
48041
|
+
if (environment) {
|
|
48042
|
+
console.log(chalk2.gray(` Env: ${environment}`));
|
|
48043
|
+
}
|
|
48044
|
+
if (agentVersion) {
|
|
48045
|
+
console.log(chalk2.gray(` Version: ${agentVersion}`));
|
|
48046
|
+
}
|
|
47707
48047
|
if (log.duration !== void 0) {
|
|
47708
48048
|
console.log(chalk2.gray(` Duration: ${log.duration}ms`));
|
|
47709
48049
|
}
|
|
@@ -47713,6 +48053,13 @@ function renderLogEntry(log, isLast) {
|
|
|
47713
48053
|
}
|
|
47714
48054
|
}
|
|
47715
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");
|
|
47716
48063
|
function displayLogsCore(logs, pagination, title, clearScreen = false) {
|
|
47717
48064
|
if (clearScreen) {
|
|
47718
48065
|
console.clear();
|
|
@@ -47721,7 +48068,7 @@ function displayLogsCore(logs, pagination, title, clearScreen = false) {
|
|
|
47721
48068
|
${title}
|
|
47722
48069
|
`);
|
|
47723
48070
|
writeInfo(`${"\u2500".repeat(80)}`);
|
|
47724
|
-
writeInfo(
|
|
48071
|
+
writeInfo(`${formatPageHeader(pagination)}
|
|
47725
48072
|
`);
|
|
47726
48073
|
if (logs.length === 0) {
|
|
47727
48074
|
writeInfo("No logs found.");
|
|
@@ -47777,6 +48124,149 @@ async function resolveEntityId(apiKey, agentId, type, nameOrId) {
|
|
|
47777
48124
|
return found?.id || null;
|
|
47778
48125
|
}
|
|
47779
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");
|
|
47780
48270
|
async function nonInteractiveLogs(logsApi, agentId, apiKey, options) {
|
|
47781
48271
|
const filters = {};
|
|
47782
48272
|
if (options.type && options.type !== "all") {
|
|
@@ -47799,6 +48289,13 @@ async function nonInteractiveLogs(logsApi, agentId, apiKey, options) {
|
|
|
47799
48289
|
if (options.userId) {
|
|
47800
48290
|
filters.userId = options.userId;
|
|
47801
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
|
+
}
|
|
47802
48299
|
const response = await logsApi.getAgentLogs(agentId, options.limit || 20, options.page || 1, filters);
|
|
47803
48300
|
if (!response.success) {
|
|
47804
48301
|
throw CliError.fromStatus(response.error?.statusCode, response.error?.message || "Unknown error", void 0, apiErrorDetail(response.error));
|
|
@@ -47807,6 +48304,10 @@ async function nonInteractiveLogs(logsApi, agentId, apiKey, options) {
|
|
|
47807
48304
|
if (options.json) {
|
|
47808
48305
|
console.log(JSON.stringify({
|
|
47809
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,
|
|
47810
48311
|
pagination: data.pagination
|
|
47811
48312
|
}, null, 2));
|
|
47812
48313
|
} else {
|
|
@@ -48095,8 +48596,8 @@ async function handleNavigation(action, pagination, setPage) {
|
|
|
48095
48596
|
}
|
|
48096
48597
|
}
|
|
48097
48598
|
__name(handleNavigation, "handleNavigation");
|
|
48098
|
-
function capitalize(
|
|
48099
|
-
return
|
|
48599
|
+
function capitalize(str2) {
|
|
48600
|
+
return str2.charAt(0).toUpperCase() + str2.slice(1);
|
|
48100
48601
|
}
|
|
48101
48602
|
__name(capitalize, "capitalize");
|
|
48102
48603
|
function getLogIcon(subType, logSource) {
|
|
@@ -48160,6 +48661,1423 @@ function getLogColor(subType, logSource) {
|
|
|
48160
48661
|
}
|
|
48161
48662
|
__name(getLogColor, "getLogColor");
|
|
48162
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
|
+
|
|
48163
50081
|
// src/commands/completion.ts
|
|
48164
50082
|
init_cli();
|
|
48165
50083
|
init_analytics();
|
|
@@ -49500,10 +51418,10 @@ function truncate2(s, n2) {
|
|
|
49500
51418
|
return s.length <= n2 ? s : s.slice(0, Math.max(0, n2 - 1)) + "\u2026";
|
|
49501
51419
|
}
|
|
49502
51420
|
__name(truncate2, "truncate");
|
|
49503
|
-
function
|
|
51421
|
+
function printJson3(report2) {
|
|
49504
51422
|
console.log(JSON.stringify(report2));
|
|
49505
51423
|
}
|
|
49506
|
-
__name(
|
|
51424
|
+
__name(printJson3, "printJson");
|
|
49507
51425
|
var TICK = chalk3.green("\u2713");
|
|
49508
51426
|
var WARN = chalk3.yellow("!");
|
|
49509
51427
|
var CROSS = chalk3.red("\u2717");
|
|
@@ -49786,7 +51704,7 @@ async function statusCommand(options) {
|
|
|
49786
51704
|
hints
|
|
49787
51705
|
};
|
|
49788
51706
|
if (options.json) {
|
|
49789
|
-
|
|
51707
|
+
printJson3(report2);
|
|
49790
51708
|
} else {
|
|
49791
51709
|
printHuman(report2);
|
|
49792
51710
|
}
|
|
@@ -53822,18 +55740,23 @@ __name(handleWatchFrame, "handleWatchFrame");
|
|
|
53822
55740
|
async function boundaryVerdict(runId, ev, state3, boundary) {
|
|
53823
55741
|
const type = ev.type;
|
|
53824
55742
|
if (type === "run.gated") {
|
|
53825
|
-
const
|
|
53826
|
-
const
|
|
53827
|
-
|
|
55743
|
+
const raw = ev.data;
|
|
55744
|
+
const rawKind = raw?.kind ?? raw?.gate;
|
|
55745
|
+
const stepId = raw?.stepId;
|
|
55746
|
+
if (rawKind === "exception") {
|
|
53828
55747
|
return boundary(`\u26A0\uFE0F run parked on an exception gate \u2014 a human decides next: lua workflows status ${runId}`, WORKFLOW_EXIT.RUN_PARKED);
|
|
53829
55748
|
}
|
|
53830
|
-
if (
|
|
55749
|
+
if (rawKind === "billing") {
|
|
53831
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);
|
|
53832
55751
|
}
|
|
53833
|
-
if (
|
|
55752
|
+
if (rawKind === "budget") {
|
|
53834
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);
|
|
53835
55754
|
}
|
|
53836
|
-
|
|
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);
|
|
53837
55760
|
}
|
|
53838
55761
|
if (type === "run.suspended") {
|
|
53839
55762
|
const kind = ev.data?.kind;
|
|
@@ -54554,18 +56477,18 @@ function modelEventDetail(type, data) {
|
|
|
54554
56477
|
if (type !== "step.model_resolved" && type !== "step.model_policy_warning") return void 0;
|
|
54555
56478
|
const d = data ?? {};
|
|
54556
56479
|
const nested = d.detail ?? {};
|
|
54557
|
-
const
|
|
56480
|
+
const str2 = /* @__PURE__ */ __name((...vals) => {
|
|
54558
56481
|
for (const v of vals) if (typeof v === "string" && v) return v;
|
|
54559
56482
|
return void 0;
|
|
54560
56483
|
}, "str");
|
|
54561
|
-
const requested =
|
|
54562
|
-
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);
|
|
54563
56486
|
if (type === "step.model_resolved") {
|
|
54564
|
-
const cls = requested?.startsWith("class/") ? requested.slice("class/".length) :
|
|
56487
|
+
const cls = requested?.startsWith("class/") ? requested.slice("class/".length) : str2(d.taskClass, nested.taskClass);
|
|
54565
56488
|
return `model resolved \u2192 ${resolved ?? requested ?? "?"}${cls ? ` (${cls})` : ""}`;
|
|
54566
56489
|
}
|
|
54567
|
-
const outcome =
|
|
54568
|
-
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);
|
|
54569
56492
|
return `model policy warning: ${outcome}${detail ? ` ${detail}` : ""}`;
|
|
54570
56493
|
}
|
|
54571
56494
|
__name(modelEventDetail, "modelEventDetail");
|
|
@@ -54961,7 +56884,7 @@ async function archiveRunsCore(ctx, o) {
|
|
|
54961
56884
|
if (!ctx.json) console.log(line);
|
|
54962
56885
|
}, "say");
|
|
54963
56886
|
const sha256 = /* @__PURE__ */ __name((buf) => crypto5.createHash("sha256").update(buf).digest("hex"), "sha256");
|
|
54964
|
-
const
|
|
56887
|
+
const sleep4 = /* @__PURE__ */ __name((ms) => new Promise((r) => setTimeout(r, ms)), "sleep");
|
|
54965
56888
|
const archiveOne = /* @__PURE__ */ __name(async (apiRow) => {
|
|
54966
56889
|
const run = {
|
|
54967
56890
|
...apiRow,
|
|
@@ -55019,7 +56942,7 @@ async function archiveRunsCore(ctx, o) {
|
|
|
55019
56942
|
}
|
|
55020
56943
|
let dto = req.data;
|
|
55021
56944
|
for (let attempt = 0; !dto || dto.status === "pending"; attempt++) {
|
|
55022
|
-
if (attempt > 0) await
|
|
56945
|
+
if (attempt > 0) await sleep4(Math.min(5e3, 250 * 2 ** Math.min(attempt, 5)));
|
|
55023
56946
|
if (attempt > 60) {
|
|
55024
56947
|
report2.deferred.push({
|
|
55025
56948
|
runId: run.id,
|
|
@@ -56520,12 +58443,8 @@ async function clearGateCore(ctx, runId, o) {
|
|
|
56520
58443
|
if (!res.success || !res.data) return apiFailure(ctx, res, "clear-gate");
|
|
56521
58444
|
emitJson(ctx, res);
|
|
56522
58445
|
if (ctx.json) return WORKFLOW_EXIT.OK;
|
|
56523
|
-
|
|
56524
|
-
|
|
56525
|
-
console.log(` lua workflows watch ${runId}`);
|
|
56526
|
-
} else {
|
|
56527
|
-
writeInfo(`\u2139\uFE0F ${runId} is not parked on a ${kind} gate${res.data.reason ? ` \u2014 ${res.data.reason}` : ""}. Nothing to clear.`);
|
|
56528
|
-
}
|
|
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}`);
|
|
56529
58448
|
return WORKFLOW_EXIT.OK;
|
|
56530
58449
|
}
|
|
56531
58450
|
__name(clearGateCore, "clearGateCore");
|
|
@@ -56550,12 +58469,18 @@ async function recomposeCore(ctx, name, _o) {
|
|
|
56550
58469
|
emitJson(ctx, res);
|
|
56551
58470
|
if (ctx.json) return WORKFLOW_EXIT.OK;
|
|
56552
58471
|
const d = res.data;
|
|
56553
|
-
|
|
58472
|
+
const rewrittenCount = d.rewritten?.length ?? 0;
|
|
58473
|
+
if (rewrittenCount === 0) {
|
|
56554
58474
|
writeInfo(`\u2139\uFE0F ${wf.name} already asks for model classes everywhere it can \u2014 no new version was published.`);
|
|
56555
58475
|
return WORKFLOW_EXIT.OK;
|
|
56556
58476
|
}
|
|
56557
|
-
|
|
56558
|
-
|
|
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);
|
|
56559
58484
|
return WORKFLOW_EXIT.OK;
|
|
56560
58485
|
}
|
|
56561
58486
|
__name(recomposeCore, "recomposeCore");
|
|
@@ -58600,10 +60525,10 @@ async function templateCommand(action, options = {}) {
|
|
|
58600
60525
|
});
|
|
58601
60526
|
}
|
|
58602
60527
|
__name(templateCommand, "templateCommand");
|
|
58603
|
-
function
|
|
60528
|
+
function sleep3(ms) {
|
|
58604
60529
|
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
58605
60530
|
}
|
|
58606
|
-
__name(
|
|
60531
|
+
__name(sleep3, "sleep");
|
|
58607
60532
|
function missingVersionOrRethrow(error) {
|
|
58608
60533
|
if (CliError.isCliError(error) && error.statusCode === 404) return null;
|
|
58609
60534
|
throw error;
|
|
@@ -58647,12 +60572,12 @@ function parseEnvContract(raw) {
|
|
|
58647
60572
|
const result = {};
|
|
58648
60573
|
for (const entry of raw) {
|
|
58649
60574
|
for (const pair of entry.split(/,(?=\s*[A-Za-z_][A-Za-z0-9_]*\??\s*=)/)) {
|
|
58650
|
-
const
|
|
58651
|
-
if (!
|
|
58652
|
-
const eqIdx =
|
|
60575
|
+
const trimmed2 = pair.trim();
|
|
60576
|
+
if (!trimmed2) continue;
|
|
60577
|
+
const eqIdx = trimmed2.indexOf("=");
|
|
58653
60578
|
if (eqIdx === -1) continue;
|
|
58654
|
-
let key =
|
|
58655
|
-
const description =
|
|
60579
|
+
let key = trimmed2.slice(0, eqIdx).trim();
|
|
60580
|
+
const description = trimmed2.slice(eqIdx + 1).trim();
|
|
58656
60581
|
let required = true;
|
|
58657
60582
|
if (key.endsWith("?")) {
|
|
58658
60583
|
required = false;
|
|
@@ -59219,8 +61144,7 @@ Apply v${versionObj.version} to ${targets.length} agent(s)?`);
|
|
|
59219
61144
|
writeProgress("\u{1F504} Starting apply run...");
|
|
59220
61145
|
const { runId } = await templateApi.apply(templateId, {
|
|
59221
61146
|
version: versionObj.version,
|
|
59222
|
-
targets
|
|
59223
|
-
skipEnvCheck: options.skipEnvCheck
|
|
61147
|
+
targets
|
|
59224
61148
|
});
|
|
59225
61149
|
if (options.wait === false) {
|
|
59226
61150
|
if (options.json) {
|
|
@@ -59239,7 +61163,7 @@ Apply v${versionObj.version} to ${targets.length} agent(s)?`);
|
|
|
59239
61163
|
if (Date.now() > waitDeadline) {
|
|
59240
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}`);
|
|
59241
61165
|
}
|
|
59242
|
-
await
|
|
61166
|
+
await sleep3(3e3);
|
|
59243
61167
|
run = await templateApi.getApplyRun(templateId, runId);
|
|
59244
61168
|
}
|
|
59245
61169
|
if (options.json) {
|
|
@@ -67627,7 +69551,7 @@ function setupMarketplaceCommands(program2) {
|
|
|
67627
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) => [
|
|
67628
69552
|
...previous,
|
|
67629
69553
|
val
|
|
67630
|
-
], []).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", `
|
|
67631
69555
|
Arguments:
|
|
67632
69556
|
noun Optional: 'skill' or 'template' (prompts if not provided)
|
|
67633
69557
|
action Optional: specific action for non-interactive mode
|
|
@@ -67904,9 +69828,9 @@ Examples:
|
|
|
67904
69828
|
$ lua channels Interactive management
|
|
67905
69829
|
$ lua channels list List all channels
|
|
67906
69830
|
`).action(channelsCommand);
|
|
67907
|
-
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", `
|
|
67908
69832
|
Options:
|
|
67909
|
-
--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)
|
|
67910
69834
|
--name <name> Entity name to filter (requires --type, not for message types)
|
|
67911
69835
|
--user-id <userId> Filter logs by user ID
|
|
67912
69836
|
--agent-id <agentId> View logs for a specific agent ID (admin access required, overrides the agent in lua.config.yaml)
|
|
@@ -67915,6 +69839,11 @@ Options:
|
|
|
67915
69839
|
--json Output as JSON for scripting
|
|
67916
69840
|
--direction <dir> Filter calls by direction (inbound | outbound) \u2014 only with --type calls
|
|
67917
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
|
|
67918
69847
|
|
|
67919
69848
|
Examples:
|
|
67920
69849
|
$ lua logs Interactive selection
|
|
@@ -67928,6 +69857,16 @@ Examples:
|
|
|
67928
69857
|
$ lua logs --type calls Recent voice calls (renders as table)
|
|
67929
69858
|
$ lua logs --type calls --direction outbound Outbound calls only
|
|
67930
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.
|
|
67931
69870
|
`).action(logsCommand);
|
|
67932
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", `
|
|
67933
69872
|
Arguments:
|
|
@@ -67970,6 +69909,28 @@ Examples:
|
|
|
67970
69909
|
$ lua webhooks subscribe --webhook-name myWebhook --event message.delivered Subscribe to event
|
|
67971
69910
|
$ lua webhooks unsubscribe --webhook-name myWebhook --event message.delivered Unsubscribe from event
|
|
67972
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);
|
|
67973
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", `
|
|
67974
69935
|
Arguments:
|
|
67975
69936
|
action Optional: list, status, enable, disable, remove, test, test-trigger
|
|
@@ -68433,7 +70394,7 @@ __name(visibleLength, "visibleLength");
|
|
|
68433
70394
|
function printBanner(opts) {
|
|
68434
70395
|
if (process.env.LUA_NO_BANNER) return;
|
|
68435
70396
|
if (!process.stdout.isTTY && !process.env.LUA_FORCE_BANNER) return;
|
|
68436
|
-
if (
|
|
70397
|
+
if (noColorEnabled()) {
|
|
68437
70398
|
process.stdout.write(`
|
|
68438
70399
|
lua-cli v${opts.version} \xB7 Build and deploy AI agents with superpowers
|
|
68439
70400
|
|
|
@@ -68456,6 +70417,7 @@ __name(printBanner, "printBanner");
|
|
|
68456
70417
|
// src/index.ts
|
|
68457
70418
|
init_package_root();
|
|
68458
70419
|
var CLI_VERSION = getCliVersion();
|
|
70420
|
+
configureChalkColor(chalk5);
|
|
68459
70421
|
var args = process.argv.slice(2);
|
|
68460
70422
|
var isBareInvocation = args.length === 0;
|
|
68461
70423
|
var isHelpInvocation = args.includes("--help") || args.includes("-h");
|