lua-cli 3.32.4 → 3.32.6
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 +32 -1
- package/dist/api-exports.js +342 -60
- package/dist/api-exports.js.map +1 -1
- package/dist/index.js +1033 -497
- package/dist/index.js.map +1 -1
- package/dist/workflow-builder.d.ts +5 -0
- package/dist/workflow-builder.js +215 -8
- package/dist/workflow-builder.js.map +1 -1
- package/docs/CLI_REFERENCE.md +6 -2
- package/docs/README.md +2 -2
- package/docs/workflows/approvals.md +1 -1
- package/docs/workflows/limits.md +4 -0
- package/docs/workflows/testing-offline.md +1 -1
- package/package.json +3 -3
- package/template/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -65,6 +65,16 @@ var init_auth_error = __esm({
|
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
// src/errors/cli.error.ts
|
|
68
|
+
function apiErrorDetail(error) {
|
|
69
|
+
return {
|
|
70
|
+
serverCode: error?.code,
|
|
71
|
+
issues: error?.issues,
|
|
72
|
+
upstream: error?.upstream,
|
|
73
|
+
requestId: error?.requestId,
|
|
74
|
+
vendor: error?.vendor,
|
|
75
|
+
retryAfterSeconds: error?.retryAfterSeconds
|
|
76
|
+
};
|
|
77
|
+
}
|
|
68
78
|
function isTypedCliError(error) {
|
|
69
79
|
return CliError.isCliError(error) || AuthenticationError.isAuthenticationError(error);
|
|
70
80
|
}
|
|
@@ -93,6 +103,17 @@ function debugEnabled() {
|
|
|
93
103
|
const v = process.env.LUA_DEBUG;
|
|
94
104
|
return debugFlag || v === "1" || v === "true" || v === "yes";
|
|
95
105
|
}
|
|
106
|
+
function upstreamUnavailableHint(upstream, requestId) {
|
|
107
|
+
const service = typeof upstream === "string" && upstream ? `its ${upstream} service` : "a service behind it";
|
|
108
|
+
const ref = typeof requestId === "string" && requestId ? ` If it persists, quote request ${requestId}.` : "";
|
|
109
|
+
return `The Lua API is up, but ${service} is temporarily unavailable (503 UPSTREAM_UNAVAILABLE) \u2014 retry in a moment.${ref}`;
|
|
110
|
+
}
|
|
111
|
+
function vendorUnavailableHint(vendor, requestId, retryAfterSeconds) {
|
|
112
|
+
const name = typeof vendor === "string" && vendor ? VENDOR_LABELS[vendor] ?? vendor : "a vendor it depends on";
|
|
113
|
+
const ref = typeof requestId === "string" && requestId ? ` If it persists, quote request ${requestId}.` : "";
|
|
114
|
+
const retry = typeof retryAfterSeconds === "number" ? "retry in a moment" : "the request may have applied at the vendor \u2014 check before retrying";
|
|
115
|
+
return `The Lua API is up, but ${name} is temporarily unavailable (503 VENDOR_UNAVAILABLE) \u2014 ${retry}.${ref}`;
|
|
116
|
+
}
|
|
96
117
|
function authHint(error) {
|
|
97
118
|
if (error.suppressDefaultRemediation) return void 0;
|
|
98
119
|
if (error.reason === "no_agent_access") {
|
|
@@ -116,7 +137,10 @@ function classifyCliError(error) {
|
|
|
116
137
|
code: error.code,
|
|
117
138
|
exitCode: error.exitCode,
|
|
118
139
|
message: error.message,
|
|
119
|
-
hint: error.hint
|
|
140
|
+
hint: error.hint,
|
|
141
|
+
statusCode: error.statusCode,
|
|
142
|
+
serverCode: error.serverCode,
|
|
143
|
+
issues: error.issues
|
|
120
144
|
};
|
|
121
145
|
}
|
|
122
146
|
if (AuthenticationError.isAuthenticationError(error)) {
|
|
@@ -138,30 +162,36 @@ function classifyCliError(error) {
|
|
|
138
162
|
}
|
|
139
163
|
const status = numericStatus(e);
|
|
140
164
|
if (status !== void 0) {
|
|
165
|
+
const statusCode = status;
|
|
141
166
|
if (status === 401) return {
|
|
142
167
|
code: "auth",
|
|
143
168
|
exitCode: CLI_EXIT.AUTH,
|
|
144
|
-
message
|
|
169
|
+
message,
|
|
170
|
+
statusCode
|
|
145
171
|
};
|
|
146
172
|
if (status === 403) return {
|
|
147
173
|
code: "forbidden",
|
|
148
174
|
exitCode: CLI_EXIT.FORBIDDEN,
|
|
149
|
-
message
|
|
175
|
+
message,
|
|
176
|
+
statusCode
|
|
150
177
|
};
|
|
151
178
|
if (status === 404) return {
|
|
152
179
|
code: "not_found",
|
|
153
180
|
exitCode: CLI_EXIT.NOT_FOUND,
|
|
154
|
-
message
|
|
181
|
+
message,
|
|
182
|
+
statusCode
|
|
155
183
|
};
|
|
156
184
|
if (status >= 400 && status < 500) return {
|
|
157
185
|
code: `http_${status}`,
|
|
158
186
|
exitCode: CLI_EXIT.FORBIDDEN,
|
|
159
|
-
message
|
|
187
|
+
message,
|
|
188
|
+
statusCode
|
|
160
189
|
};
|
|
161
190
|
if (status >= 500 || status === 0) return {
|
|
162
191
|
code: "unavailable",
|
|
163
192
|
exitCode: CLI_EXIT.UNAVAILABLE,
|
|
164
|
-
message
|
|
193
|
+
message,
|
|
194
|
+
statusCode
|
|
165
195
|
};
|
|
166
196
|
}
|
|
167
197
|
const causeCode = e.cause?.code;
|
|
@@ -179,9 +209,18 @@ function classifyCliError(error) {
|
|
|
179
209
|
message
|
|
180
210
|
};
|
|
181
211
|
}
|
|
212
|
+
function issueLines(issues) {
|
|
213
|
+
return (issues ?? []).map((issue) => {
|
|
214
|
+
const where = issue.path !== void 0 ? `${issue.path || "/"}: ` : "";
|
|
215
|
+
const what = issue.message ?? issue.code ?? "invalid";
|
|
216
|
+
const tag = issue.message && issue.code ? ` (${issue.code})` : "";
|
|
217
|
+
return ` \u2022 ${where}${what}${tag}`;
|
|
218
|
+
});
|
|
219
|
+
}
|
|
182
220
|
function renderCliError(reported, options = {}) {
|
|
183
221
|
const lines = [
|
|
184
|
-
`\u2716 ${reported.code}: ${reported.message}
|
|
222
|
+
`\u2716 ${reported.code}: ${reported.message}`,
|
|
223
|
+
...issueLines(reported.issues)
|
|
185
224
|
];
|
|
186
225
|
for (const hint of [
|
|
187
226
|
reported.hint,
|
|
@@ -193,9 +232,30 @@ function renderCliError(reported, options = {}) {
|
|
|
193
232
|
if (options.stack) lines.push("", options.stack);
|
|
194
233
|
return lines;
|
|
195
234
|
}
|
|
235
|
+
function cliErrorEnvelope(error) {
|
|
236
|
+
const reported = classifyCliError(error);
|
|
237
|
+
return {
|
|
238
|
+
success: false,
|
|
239
|
+
error: {
|
|
240
|
+
code: reported.serverCode ?? reported.code,
|
|
241
|
+
...reported.statusCode !== void 0 ? {
|
|
242
|
+
statusCode: reported.statusCode
|
|
243
|
+
} : {},
|
|
244
|
+
message: reported.message,
|
|
245
|
+
...reported.issues?.length ? {
|
|
246
|
+
issues: reported.issues
|
|
247
|
+
} : {}
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
}
|
|
196
251
|
function reportCliError(error, options = {}) {
|
|
197
252
|
const reported = classifyCliError(error);
|
|
198
253
|
const stack = debugEnabled() && error instanceof Error ? error.stack : void 0;
|
|
254
|
+
if (options.json) {
|
|
255
|
+
console.log(JSON.stringify(cliErrorEnvelope(error), null, 2));
|
|
256
|
+
if (stack) console.error(stack);
|
|
257
|
+
return reported;
|
|
258
|
+
}
|
|
199
259
|
for (const line of renderCliError(reported, {
|
|
200
260
|
extraHint: options.extraHint,
|
|
201
261
|
stack
|
|
@@ -224,7 +284,7 @@ function reportUnhandledCliError(error) {
|
|
|
224
284
|
process.exitCode = reported.exitCode;
|
|
225
285
|
return reported.exitCode;
|
|
226
286
|
}
|
|
227
|
-
var CLI_EXIT, CliError, HandledCliError, debugFlag, NETWORK_ERRNO, NETWORK_MESSAGE, UNAVAILABLE_HINT, CLI_EXIT_CODE_HELP;
|
|
287
|
+
var CLI_EXIT, CliError, HandledCliError, debugFlag, NETWORK_ERRNO, NETWORK_MESSAGE, UNAVAILABLE_HINT, VENDOR_LABELS, CLI_EXIT_CODE_HELP;
|
|
228
288
|
var init_cli_error = __esm({
|
|
229
289
|
"src/errors/cli.error.ts"() {
|
|
230
290
|
"use strict";
|
|
@@ -238,6 +298,7 @@ var init_cli_error = __esm({
|
|
|
238
298
|
FORBIDDEN: 10,
|
|
239
299
|
UNAVAILABLE: 11
|
|
240
300
|
};
|
|
301
|
+
__name(apiErrorDetail, "apiErrorDetail");
|
|
241
302
|
CliError = class _CliError extends Error {
|
|
242
303
|
static {
|
|
243
304
|
__name(this, "CliError");
|
|
@@ -247,6 +308,8 @@ var init_cli_error = __esm({
|
|
|
247
308
|
exitCode;
|
|
248
309
|
hint;
|
|
249
310
|
statusCode;
|
|
311
|
+
serverCode;
|
|
312
|
+
issues;
|
|
250
313
|
constructor(code, message, options = {}) {
|
|
251
314
|
super(message);
|
|
252
315
|
this.name = "CliError";
|
|
@@ -254,6 +317,8 @@ var init_cli_error = __esm({
|
|
|
254
317
|
this.exitCode = options.exitCode ?? CLI_EXIT.ERROR;
|
|
255
318
|
this.hint = options.hint;
|
|
256
319
|
this.statusCode = options.statusCode;
|
|
320
|
+
this.serverCode = options.serverCode;
|
|
321
|
+
this.issues = options.issues?.length ? options.issues : void 0;
|
|
257
322
|
if (Error.captureStackTrace) Error.captureStackTrace(this, _CliError);
|
|
258
323
|
}
|
|
259
324
|
/** Bad arguments, an unknown action, no project — exit 2. */
|
|
@@ -282,19 +347,23 @@ var init_cli_error = __esm({
|
|
|
282
347
|
/**
|
|
283
348
|
* An API refusal the site already holds the status of (LUA-766) — classified by the same table the top-level
|
|
284
349
|
* classifier applies to an untyped error: 401 auth · 403 forbidden · 404 not_found · other 4xx `http_<status>`
|
|
285
|
-
* (10) · 5xx / 0 unavailable (11, with the network hint unless the site gives its own
|
|
350
|
+
* (10) · 5xx / 0 unavailable (11, with the network hint unless the site gives its own — or the body's code
|
|
351
|
+
* picks one: a 503 UPSTREAM_UNAVAILABLE names the Lua service behind the API, LUA-810) · no status `error` (1).
|
|
286
352
|
* A command that reads `response.error.statusCode` throws through here, so `lua logs` on a 503 exits 11 like
|
|
287
353
|
* every other verb instead of printing the message itself and then throwing an exit-1 `Error`.
|
|
288
354
|
*/
|
|
289
|
-
static fromStatus(statusCode, message, hint) {
|
|
355
|
+
static fromStatus(statusCode, message, hint, detail = {}) {
|
|
290
356
|
const reported = classifyCliError(Object.assign(new Error(message), {
|
|
291
357
|
statusCode
|
|
292
358
|
}));
|
|
359
|
+
const codeHint = detail.serverCode === "UPSTREAM_UNAVAILABLE" ? upstreamUnavailableHint(detail.upstream, detail.requestId) : detail.serverCode === "VENDOR_UNAVAILABLE" ? vendorUnavailableHint(detail.vendor, detail.requestId, detail.retryAfterSeconds) : void 0;
|
|
293
360
|
const classHint = reported.exitCode === CLI_EXIT.UNAVAILABLE ? UNAVAILABLE_HINT : reported.hint;
|
|
294
361
|
return new _CliError(reported.code, message, {
|
|
295
362
|
exitCode: reported.exitCode,
|
|
296
|
-
hint: hint ?? classHint,
|
|
297
|
-
statusCode
|
|
363
|
+
hint: hint ?? codeHint ?? classHint,
|
|
364
|
+
statusCode,
|
|
365
|
+
serverCode: detail.serverCode,
|
|
366
|
+
issues: detail.issues
|
|
298
367
|
});
|
|
299
368
|
}
|
|
300
369
|
static isCliError(error) {
|
|
@@ -340,10 +409,20 @@ var init_cli_error = __esm({
|
|
|
340
409
|
]);
|
|
341
410
|
NETWORK_MESSAGE = /fetch failed|socket hang up|network request failed|request timeout|ECONNREFUSED|ENOTFOUND/i;
|
|
342
411
|
UNAVAILABLE_HINT = "The Lua API could not be reached \u2014 check your network and https://status.heylua.ai, then retry.";
|
|
412
|
+
__name(upstreamUnavailableHint, "upstreamUnavailableHint");
|
|
413
|
+
VENDOR_LABELS = {
|
|
414
|
+
unified: "Unified.to",
|
|
415
|
+
github: "GitHub",
|
|
416
|
+
pusher: "Pusher",
|
|
417
|
+
google: "Google"
|
|
418
|
+
};
|
|
419
|
+
__name(vendorUnavailableHint, "vendorUnavailableHint");
|
|
343
420
|
__name(authHint, "authHint");
|
|
344
421
|
__name(numericStatus, "numericStatus");
|
|
345
422
|
__name(classifyCliError, "classifyCliError");
|
|
423
|
+
__name(issueLines, "issueLines");
|
|
346
424
|
__name(renderCliError, "renderCliError");
|
|
425
|
+
__name(cliErrorEnvelope, "cliErrorEnvelope");
|
|
347
426
|
__name(reportCliError, "reportCliError");
|
|
348
427
|
__name(commanderExitCode, "commanderExitCode");
|
|
349
428
|
__name(reportUnhandledCliError, "reportUnhandledCliError");
|
|
@@ -1066,6 +1145,18 @@ function modelUnresolvedMessage(r) {
|
|
|
1066
1145
|
}
|
|
1067
1146
|
return r.candidates.length ? `model "${r.requested}" does not resolve to an approved model \u2014 accepted forms: ${r.candidates.join(", ")}` : `model "${r.requested}" does not resolve to an approved model \u2014 accepted forms are the registry's provider-prefixed ids (provider/model) or a bare id that names exactly one of them`;
|
|
1068
1147
|
}
|
|
1148
|
+
function providerModelId(code) {
|
|
1149
|
+
const requested = typeof code === "string" ? code.trim() : "";
|
|
1150
|
+
if (!requested || isModelIdSentinel(requested)) return requested;
|
|
1151
|
+
const slash = requested.indexOf("/");
|
|
1152
|
+
if (slash <= 0) return requested;
|
|
1153
|
+
const provider = requested.slice(0, slash).toLowerCase();
|
|
1154
|
+
if (MODEL_ID_BYOK_PROVIDERS.includes(provider)) return requested;
|
|
1155
|
+
return requested.slice(slash + 1);
|
|
1156
|
+
}
|
|
1157
|
+
function providerModelFamily(code) {
|
|
1158
|
+
return providerModelId(code).toLowerCase().replace(MODEL_SNAPSHOT_SUFFIX, "");
|
|
1159
|
+
}
|
|
1069
1160
|
function isImplicitModelSelectionSource(source) {
|
|
1070
1161
|
return source !== void 0 && IMPLICIT_MODEL_SELECTION_SOURCES.includes(source);
|
|
1071
1162
|
}
|
|
@@ -1179,6 +1270,11 @@ function isDeviceCredentialPrincipal(context) {
|
|
|
1179
1270
|
function hasDeviceCredentialType(value3) {
|
|
1180
1271
|
return DeviceCredentialClaimSchema.safeParse(value3).success;
|
|
1181
1272
|
}
|
|
1273
|
+
function sessionAuthTime(context) {
|
|
1274
|
+
if (!context || context.credential.type !== "firstPartySession") return void 0;
|
|
1275
|
+
const authTime = context.authTime;
|
|
1276
|
+
return typeof authTime === "number" && Number.isInteger(authTime) && authTime >= 0 && authTime <= SESSION_AUTH_TIME_MAX_S ? authTime : void 0;
|
|
1277
|
+
}
|
|
1182
1278
|
function isTypedApiKeyPrincipal(context) {
|
|
1183
1279
|
return context?.subject.subjectType === "apiKey" && context.credential.type === "apiKey" && !context.compatibility;
|
|
1184
1280
|
}
|
|
@@ -1351,6 +1447,39 @@ function scheduledWorkflowRunId(jobId, scheduledTime) {
|
|
|
1351
1447
|
const key = typeof scheduledTime === "number" ? String(scheduledTime) : scheduledTimeKey(scheduledTime);
|
|
1352
1448
|
return `${WORKFLOW_SCHEDULED_RUN_ID_PREFIX}${jobId}_${key}`;
|
|
1353
1449
|
}
|
|
1450
|
+
function renderWorkflowScheduleKeyTemplate(template3, ctx) {
|
|
1451
|
+
if (!template3) return void 0;
|
|
1452
|
+
const read = /* @__PURE__ */ __name2((path25) => path25.split(".").reduce((o, k) => o && typeof o === "object" ? o[k] : void 0, ctx.input), "read");
|
|
1453
|
+
let unresolved = false;
|
|
1454
|
+
const out = template3.replace(/\$\{\s*([a-zA-Z0-9_.]+)\s*\}/g, (_m, expr) => {
|
|
1455
|
+
let v = "";
|
|
1456
|
+
if (expr === "scheduledTime") v = ctx.scheduledTime ?? "";
|
|
1457
|
+
else if (expr.startsWith("input.")) v = read(expr.slice("input.".length));
|
|
1458
|
+
const s = v === void 0 || v === null ? "" : String(v);
|
|
1459
|
+
if (s === "") unresolved = true;
|
|
1460
|
+
return s;
|
|
1461
|
+
});
|
|
1462
|
+
if (unresolved) return void 0;
|
|
1463
|
+
const key = out.slice(0, WORKFLOW_SCHEDULE_KEY_MAX);
|
|
1464
|
+
return key && /^[A-Za-z0-9:_\-.\/]+$/.test(key) ? key : void 0;
|
|
1465
|
+
}
|
|
1466
|
+
function scheduledWorkflowIdempotencyKey(jobId, rendered) {
|
|
1467
|
+
const head = `${WORKFLOW_SCHEDULE_IDEMPOTENCY_KEY_PREFIX}${jobId}:`;
|
|
1468
|
+
if (head.length + rendered.length <= WORKFLOW_SCHEDULE_KEY_MAX) return `${head}${rendered}`;
|
|
1469
|
+
const digest = stableKeyDigest(rendered);
|
|
1470
|
+
const room = WORKFLOW_SCHEDULE_KEY_MAX - head.length - digest.length - 1;
|
|
1471
|
+
return `${head}${rendered.slice(0, Math.max(0, room))}~${digest}`;
|
|
1472
|
+
}
|
|
1473
|
+
function stableKeyDigest(s) {
|
|
1474
|
+
let a = 2166136261;
|
|
1475
|
+
let b = 84696351;
|
|
1476
|
+
for (let i = 0; i < s.length; i++) {
|
|
1477
|
+
const c = s.charCodeAt(i);
|
|
1478
|
+
a = Math.imul(a ^ c, 16777619);
|
|
1479
|
+
b = Math.imul(b ^ c, 16777619) ^ b >>> 13;
|
|
1480
|
+
}
|
|
1481
|
+
return (a >>> 0).toString(16).padStart(8, "0") + (b >>> 0).toString(16).padStart(8, "0");
|
|
1482
|
+
}
|
|
1354
1483
|
function workflowOperationId(runId, stepId, billingEpoch) {
|
|
1355
1484
|
return `${WORKFLOW_OPERATION_ID_PREFIX}${runId}:${stepId}:${billingEpoch}`;
|
|
1356
1485
|
}
|
|
@@ -1654,7 +1783,59 @@ function extractSingleJsonValue(text) {
|
|
|
1654
1783
|
};
|
|
1655
1784
|
}
|
|
1656
1785
|
}
|
|
1657
|
-
|
|
1786
|
+
function agentFeatureCatalogDefault(featureName) {
|
|
1787
|
+
return DEFAULT_ON_AGENT_FEATURES.includes(featureName);
|
|
1788
|
+
}
|
|
1789
|
+
function hasExplicitFeatureActive(row2) {
|
|
1790
|
+
return typeof row2?.active === "boolean";
|
|
1791
|
+
}
|
|
1792
|
+
function effectiveFeatureActive(row2, catalogDefault) {
|
|
1793
|
+
return hasExplicitFeatureActive(row2) ? row2.active : catalogDefault;
|
|
1794
|
+
}
|
|
1795
|
+
function resolveEffectiveFeature(row2, catalogDefault) {
|
|
1796
|
+
return hasExplicitFeatureActive(row2) ? {
|
|
1797
|
+
active: row2.active,
|
|
1798
|
+
source: "agent",
|
|
1799
|
+
default: catalogDefault
|
|
1800
|
+
} : {
|
|
1801
|
+
active: catalogDefault,
|
|
1802
|
+
source: "default",
|
|
1803
|
+
default: catalogDefault
|
|
1804
|
+
};
|
|
1805
|
+
}
|
|
1806
|
+
function isFeatureRow(value3) {
|
|
1807
|
+
return typeof value3 === "object" && value3 !== null;
|
|
1808
|
+
}
|
|
1809
|
+
function effectiveAgentFeatureRows(base, override) {
|
|
1810
|
+
const merged = /* @__PURE__ */ new Map();
|
|
1811
|
+
for (const [name, row2] of Object.entries(base ?? {})) {
|
|
1812
|
+
if (isFeatureRow(row2)) merged.set(name, {
|
|
1813
|
+
row: row2,
|
|
1814
|
+
origin: "baseAgent"
|
|
1815
|
+
});
|
|
1816
|
+
}
|
|
1817
|
+
for (const [name, row2] of Object.entries(override ?? {})) {
|
|
1818
|
+
if (isFeatureRow(row2)) merged.set(name, {
|
|
1819
|
+
row: row2,
|
|
1820
|
+
origin: "subAgent"
|
|
1821
|
+
});
|
|
1822
|
+
}
|
|
1823
|
+
return {
|
|
1824
|
+
rows: Object.fromEntries([
|
|
1825
|
+
...merged
|
|
1826
|
+
].map(([name, e]) => [
|
|
1827
|
+
name,
|
|
1828
|
+
e.row
|
|
1829
|
+
])),
|
|
1830
|
+
origins: Object.fromEntries([
|
|
1831
|
+
...merged
|
|
1832
|
+
].map(([name, e]) => [
|
|
1833
|
+
name,
|
|
1834
|
+
e.origin
|
|
1835
|
+
]))
|
|
1836
|
+
};
|
|
1837
|
+
}
|
|
1838
|
+
var __defProp2, __name2, REVIEWABLE_ACTION_EXECUTE_TOOL_ALLOWLIST, REVIEWABLE_MCP_SEND_TOOL_SUFFIX, MCP_TOOL_READ_VERB_RE, MCP_DRAFT_CREATE_VERBS, NON_INTERACTIVE_CHANNELS, RICH_PARTS_MESSAGE_ID_PREFIX, SCREENSHOT_MESSAGE_ID_PREFIX, BROWSER_COMMANDS, BROWSER_COMMAND_NAMES, DESKTOP_FILE_COMMANDS, DESKTOP_FILE_COMMAND_SET, MODEL_ID_BYOK_PROVIDERS, 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, TEMPLATE_TRIGGER_URL_ENV_PREFIX, 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, AUTHZ_PROJECTION_VERSION, ProjectedScopeSchema, DisplayRoleSchema, AuthorizationPrincipalSchema, CredentialContextSchema, ProjectionAnomalySchema, ProjectedOrgSchema, ProjectedResourceSchema, CapabilityProfilesSchema, RoleCatalogSchema, EffectiveAuthorizationSchema, ResourcePageSchema, SYSTEM_USER_PREFIX, WORKFLOW_RUN_IN_FLIGHT, WORKFLOW_RUN_IDLE, WORKFLOW_RUN_TERMINAL, WORKFLOW_RUN_STATUSES, WORKFLOW_STEP_STATUSES, WORKFLOW_STEP_IN_FLIGHT, ARCHIVE_WINDOW_MARGIN_DAYS, WORKFLOW_ORG_PURGING_TTL_S, WORKFLOW_ORG_PURGE_FORCE_AFTER_MS, IDEMPOTENCY_HOLDING_STATUSES, WORKFLOW_SCHEDULED_RUN_ID_PREFIX, CLOUD_TASK_RUN_ID_PREFIX, WORKFLOW_SCHEDULE_KEY_MAX, WORKFLOW_SCHEDULE_IDEMPOTENCY_KEY_PREFIX, WORKFLOW_OPERATION_ID_PREFIX, WORKFLOW_JOURNAL_PROTOCOL_VERSION, WORKFLOW_CONNECTION_KEY_RE, WORKFLOW_SIGNAL_PAYLOAD_MAX_BYTES, WORKFLOW_RESOLVE_OUTPUT_MAX_BYTES, WORKFLOW_RETRY_BACKOFFS, WORKFLOW_RETRY_MIN_ATTEMPTS, WORKFLOW_RETRY_POLICY_KEYS, WORKFLOW_RETRY_MAX_ATTEMPTS, WORKFLOW_RETRY_ENGINE_KEYS, WORKFLOW_JOB_RESOURCES, WORKFLOW_SIDE_EFFECTS, WORKFLOW_JOB_RANGES, WORKFLOW_JOB_RANGE_MEMBERS, WORKFLOW_SINGLE_STEP_TYPES, WORKFLOW_HITL_ENTRY_TYPES, WORKFLOW_ARM_ENTRY_TYPES, WORKFLOW_HITL_ARM_CONTAINERS, WORKFLOW_GRAPH_ENTRY_STEP_KINDS, WORKFLOW_ARM_ENTRY_STEP_KINDS, WORKFLOW_BUDGET_MAX_DURATION_SECONDS, REDACTED_PLACEHOLDER, PROVIDER_MESSAGE_MAX_CHARS, ERROR_MESSAGE_MAX_CHARS, SECRET_LITERAL_PATTERNS, SECRET_NAME, SECRET_PAIR_PATTERNS, GROUP_COUNT, WORKFLOW_SECRET_KEY_RE, WORKFLOW_RESERVED_SECRET_KEYS, SCRUB_INPUT_MAX_CHARS, SCRUB_CUT_BACKOFF_CHARS, WORKFLOW_AUDIT_EVENTS, WORKFLOW_AUDIT_METADATA_MAX_BYTES, INDENT, WRAP_WIDTH, NOUNS, GET_TOOL_NAMES, PREAMBLE, WORKFLOW_APPROVAL_OUTPUT_DECISIONS, WORKFLOW_APPROVAL_OUTPUT_SCHEMA, JSON_FENCE_RE, DEFAULT_ON_AGENT_FEATURES;
|
|
1658
1839
|
var init_dist = __esm({
|
|
1659
1840
|
"../shared-types/dist/index.mjs"() {
|
|
1660
1841
|
"use strict";
|
|
@@ -1972,6 +2153,11 @@ var init_dist = __esm({
|
|
|
1972
2153
|
__name2(normalizeModelId, "normalizeModelId");
|
|
1973
2154
|
__name(modelUnresolvedMessage, "modelUnresolvedMessage");
|
|
1974
2155
|
__name2(modelUnresolvedMessage, "modelUnresolvedMessage");
|
|
2156
|
+
__name(providerModelId, "providerModelId");
|
|
2157
|
+
__name2(providerModelId, "providerModelId");
|
|
2158
|
+
MODEL_SNAPSHOT_SUFFIX = /(?:[-@](?:19|20)\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])|-(?:19|20)\d{2}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01]))$/;
|
|
2159
|
+
__name(providerModelFamily, "providerModelFamily");
|
|
2160
|
+
__name2(providerModelFamily, "providerModelFamily");
|
|
1975
2161
|
REASONING_EFFORT_VALUES = [
|
|
1976
2162
|
"off",
|
|
1977
2163
|
"minimal",
|
|
@@ -2431,6 +2617,7 @@ This text is who you are for this person. As you learn them, their name, their w
|
|
|
2431
2617
|
});
|
|
2432
2618
|
TYPED_API_KEY = /^api_([0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})\.([A-Za-z0-9_-]{43})$/;
|
|
2433
2619
|
IdSchema = z2.string().min(1).max(256);
|
|
2620
|
+
SESSION_AUTH_TIME_MAX_S = 4102444800;
|
|
2434
2621
|
PrincipalDescriptorSchema = z2.object({
|
|
2435
2622
|
subjectType: SubjectTypeSchema,
|
|
2436
2623
|
subjectId: IdSchema
|
|
@@ -2479,7 +2666,8 @@ This text is who you are for this person. As you learn them, their name, their w
|
|
|
2479
2666
|
owner: PrincipalOwnerSchema.optional(),
|
|
2480
2667
|
compatibility: z2.object({
|
|
2481
2668
|
mode: z2.literal("legacy-owner-delegation")
|
|
2482
|
-
}).strict().optional()
|
|
2669
|
+
}).strict().optional(),
|
|
2670
|
+
authTime: z2.number().int().nonnegative().max(SESSION_AUTH_TIME_MAX_S).optional()
|
|
2483
2671
|
}).strict();
|
|
2484
2672
|
DeviceCredentialPrincipalContextSchema = z2.object({
|
|
2485
2673
|
version: z2.literal(1),
|
|
@@ -2535,6 +2723,8 @@ This text is who you are for this person. As you learn them, their name, their w
|
|
|
2535
2723
|
}).passthrough();
|
|
2536
2724
|
__name(hasDeviceCredentialType, "hasDeviceCredentialType");
|
|
2537
2725
|
__name2(hasDeviceCredentialType, "hasDeviceCredentialType");
|
|
2726
|
+
__name(sessionAuthTime, "sessionAuthTime");
|
|
2727
|
+
__name2(sessionAuthTime, "sessionAuthTime");
|
|
2538
2728
|
__name(isTypedApiKeyPrincipal, "isTypedApiKeyPrincipal");
|
|
2539
2729
|
__name2(isTypedApiKeyPrincipal, "isTypedApiKeyPrincipal");
|
|
2540
2730
|
__name(typedApiKeyPrincipalId, "typedApiKeyPrincipalId");
|
|
@@ -2766,6 +2956,14 @@ This text is who you are for this person. As you learn them, their name, their w
|
|
|
2766
2956
|
__name2(isScheduledWorkflowRunId, "isScheduledWorkflowRunId");
|
|
2767
2957
|
__name(scheduledWorkflowRunId, "scheduledWorkflowRunId");
|
|
2768
2958
|
__name2(scheduledWorkflowRunId, "scheduledWorkflowRunId");
|
|
2959
|
+
WORKFLOW_SCHEDULE_KEY_MAX = 128;
|
|
2960
|
+
__name(renderWorkflowScheduleKeyTemplate, "renderWorkflowScheduleKeyTemplate");
|
|
2961
|
+
__name2(renderWorkflowScheduleKeyTemplate, "renderWorkflowScheduleKeyTemplate");
|
|
2962
|
+
WORKFLOW_SCHEDULE_IDEMPOTENCY_KEY_PREFIX = "sched:";
|
|
2963
|
+
__name(scheduledWorkflowIdempotencyKey, "scheduledWorkflowIdempotencyKey");
|
|
2964
|
+
__name2(scheduledWorkflowIdempotencyKey, "scheduledWorkflowIdempotencyKey");
|
|
2965
|
+
__name(stableKeyDigest, "stableKeyDigest");
|
|
2966
|
+
__name2(stableKeyDigest, "stableKeyDigest");
|
|
2769
2967
|
WORKFLOW_OPERATION_ID_PREFIX = "wf:";
|
|
2770
2968
|
__name(workflowOperationId, "workflowOperationId");
|
|
2771
2969
|
__name2(workflowOperationId, "workflowOperationId");
|
|
@@ -3212,6 +3410,23 @@ listed here; never invent a target.`;
|
|
|
3212
3410
|
JSON_FENCE_RE = /```(?:json)?[ \t]*\r?\n([\s\S]*?)\r?\n?```/g;
|
|
3213
3411
|
__name(extractSingleJsonValue, "extractSingleJsonValue");
|
|
3214
3412
|
__name2(extractSingleJsonValue, "extractSingleJsonValue");
|
|
3413
|
+
DEFAULT_ON_AGENT_FEATURES = [
|
|
3414
|
+
"workflows",
|
|
3415
|
+
"workflowCompose",
|
|
3416
|
+
"observationalMemory"
|
|
3417
|
+
];
|
|
3418
|
+
__name(agentFeatureCatalogDefault, "agentFeatureCatalogDefault");
|
|
3419
|
+
__name2(agentFeatureCatalogDefault, "agentFeatureCatalogDefault");
|
|
3420
|
+
__name(hasExplicitFeatureActive, "hasExplicitFeatureActive");
|
|
3421
|
+
__name2(hasExplicitFeatureActive, "hasExplicitFeatureActive");
|
|
3422
|
+
__name(effectiveFeatureActive, "effectiveFeatureActive");
|
|
3423
|
+
__name2(effectiveFeatureActive, "effectiveFeatureActive");
|
|
3424
|
+
__name(resolveEffectiveFeature, "resolveEffectiveFeature");
|
|
3425
|
+
__name2(resolveEffectiveFeature, "resolveEffectiveFeature");
|
|
3426
|
+
__name(isFeatureRow, "isFeatureRow");
|
|
3427
|
+
__name2(isFeatureRow, "isFeatureRow");
|
|
3428
|
+
__name(effectiveAgentFeatureRows, "effectiveAgentFeatureRows");
|
|
3429
|
+
__name2(effectiveAgentFeatureRows, "effectiveAgentFeatureRows");
|
|
3215
3430
|
}
|
|
3216
3431
|
});
|
|
3217
3432
|
|
|
@@ -4098,7 +4313,7 @@ function fillHitl(node) {
|
|
|
4098
4313
|
if (a.onTimeout === void 0) a.onTimeout = "deny";
|
|
4099
4314
|
if (a.onDeny === void 0) a.onDeny = "continue";
|
|
4100
4315
|
if (a.excludeInitiator === void 0) a.excludeInitiator = false;
|
|
4101
|
-
if (a.editable === void 0) a.editable =
|
|
4316
|
+
if (a.editable === void 0) a.editable = approvalEditable(a);
|
|
4102
4317
|
return;
|
|
4103
4318
|
}
|
|
4104
4319
|
const w = node;
|
|
@@ -4342,7 +4557,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
4342
4557
|
const id = singleId(node);
|
|
4343
4558
|
const unknown = unknownWorkflowRetryMembers(r);
|
|
4344
4559
|
if (unknown.length) err("invalid-envelope", workflowRetryUnknownMembersMessage(unknown), `${path25}.retry`, id);
|
|
4345
|
-
if (
|
|
4560
|
+
if (!isWithinWorkflowRetryAttempts(r.maxAttempts)) {
|
|
4346
4561
|
const over = typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS;
|
|
4347
4562
|
err(over ? "cap-exceeded" : "invalid-envelope", workflowRetryMaxAttemptsMessage(r.maxAttempts), `${path25}.retry.maxAttempts`, id);
|
|
4348
4563
|
}
|
|
@@ -4580,7 +4795,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
4580
4795
|
}
|
|
4581
4796
|
const a = node;
|
|
4582
4797
|
checkId(a.id, path25);
|
|
4583
|
-
if (a.approver === "creator" && a.excludeInitiator === true) {
|
|
4798
|
+
if ((a.approver ?? "creator") === "creator" && a.excludeInitiator === true) {
|
|
4584
4799
|
err("approver-excludes-only-candidate", "approver:'creator' with excludeInitiator:true always excludes the only candidate", path25, a.id);
|
|
4585
4800
|
}
|
|
4586
4801
|
const editable = approvalEditable(a);
|
|
@@ -5883,6 +6098,7 @@ function runErrorIssues(issues) {
|
|
|
5883
6098
|
function runNextAction(run) {
|
|
5884
6099
|
if (isTerminalRunStatus(run.status)) return "none";
|
|
5885
6100
|
if (run.status === "suspended" && run.gate?.kind === "budget") return "raise_budget";
|
|
6101
|
+
if (run.status === "suspended" && run.gate?.kind === "billing") return "top_up";
|
|
5886
6102
|
if (!run.cancel?.requestedAt) return "none";
|
|
5887
6103
|
const forceAt = run.cancel.forceAfter ?? run.cancel.requestedAt + FORCE_CANCEL_STALE_MS;
|
|
5888
6104
|
return Date.now() >= forceAt ? "force" : "cancel_again";
|
|
@@ -5910,6 +6126,12 @@ function runCountsFromStepStatuses(statuses) {
|
|
|
5910
6126
|
for (const s of statuses) tally[s] = (tally[s] ?? 0) + 1;
|
|
5911
6127
|
return runCountsFromStatusTally(tally);
|
|
5912
6128
|
}
|
|
6129
|
+
function isBillingHeldStep(row2) {
|
|
6130
|
+
return row2.status === "ready" && row2.billingHold === true;
|
|
6131
|
+
}
|
|
6132
|
+
function stepEffectiveStatus(row2) {
|
|
6133
|
+
return isBillingHeldStep(row2) ? "suspended" : row2.status;
|
|
6134
|
+
}
|
|
5913
6135
|
function runCounts(counts) {
|
|
5914
6136
|
const c = counts ?? {};
|
|
5915
6137
|
const rawInFlight = c.dispatched !== void 0 || c.claimed !== void 0 || c.running !== void 0 || c.cancellation_requested !== void 0;
|
|
@@ -6596,6 +6818,53 @@ function rebaseItemPointer(pointer, itemsPath, index) {
|
|
|
6596
6818
|
const base = `/${itemsPath.split(".").map(escapePointer).join("/")}/${index}`;
|
|
6597
6819
|
return pointer === "/" || pointer === "" ? base : `${base}${pointer}`;
|
|
6598
6820
|
}
|
|
6821
|
+
function validateWorkflowSchedule(schedule, path25 = "/schedule") {
|
|
6822
|
+
if (schedule === void 0 || schedule === null) return [];
|
|
6823
|
+
const issue = /* @__PURE__ */ __name3((at, detail) => [
|
|
6824
|
+
{
|
|
6825
|
+
code: WORKFLOW_SCHEDULE_SHAPE_ISSUE,
|
|
6826
|
+
severity: "error",
|
|
6827
|
+
path: at,
|
|
6828
|
+
message: `${detail} \u2014 ${WORKFLOW_SCHEDULE_SHAPES_HINT}`
|
|
6829
|
+
}
|
|
6830
|
+
], "issue");
|
|
6831
|
+
if (!isObject(schedule)) {
|
|
6832
|
+
return issue(path25, `\`schedule\` is ${Array.isArray(schedule) ? "an array" : `a ${typeof schedule}`}, not a typed schedule object`);
|
|
6833
|
+
}
|
|
6834
|
+
const type = schedule.type;
|
|
6835
|
+
if (type === void 0) {
|
|
6836
|
+
const keys = Object.keys(schedule);
|
|
6837
|
+
const seen = keys.length ? ` (got { ${keys.join(", ")} })` : " (got {})";
|
|
6838
|
+
return issue(path25, `\`schedule\` carries no \`type\` discriminator${seen}`);
|
|
6839
|
+
}
|
|
6840
|
+
if (typeof type !== "string" || !WORKFLOW_SCHEDULE_TYPES.includes(type)) {
|
|
6841
|
+
return issue(path25, `\`schedule.type\` ${JSON.stringify(type)} is not one of ${WORKFLOW_SCHEDULE_TYPES.map((t) => `'${t}'`).join(" | ")}`);
|
|
6842
|
+
}
|
|
6843
|
+
switch (type) {
|
|
6844
|
+
case "cron": {
|
|
6845
|
+
if (typeof schedule.expression !== "string" || schedule.expression.trim().length === 0) {
|
|
6846
|
+
return issue(`${path25}/expression`, "a { type: 'cron' } schedule needs a non-empty string `expression`");
|
|
6847
|
+
}
|
|
6848
|
+
if (schedule.timezone !== void 0 && (typeof schedule.timezone !== "string" || schedule.timezone.length === 0)) {
|
|
6849
|
+
return issue(`${path25}/timezone`, "a { type: 'cron' } schedule's `timezone`, when given, is a non-empty IANA string");
|
|
6850
|
+
}
|
|
6851
|
+
return [];
|
|
6852
|
+
}
|
|
6853
|
+
case "interval": {
|
|
6854
|
+
const s = schedule.seconds;
|
|
6855
|
+
if (typeof s !== "number" || !Number.isFinite(s) || s <= 0) {
|
|
6856
|
+
return issue(`${path25}/seconds`, "a { type: 'interval' } schedule needs a positive number `seconds`");
|
|
6857
|
+
}
|
|
6858
|
+
return [];
|
|
6859
|
+
}
|
|
6860
|
+
case "once": {
|
|
6861
|
+
if (typeof schedule.executeAt !== "string" || Number.isNaN(Date.parse(schedule.executeAt))) {
|
|
6862
|
+
return issue(`${path25}/executeAt`, "a { type: 'once' } schedule needs an ISO-8601 string `executeAt`");
|
|
6863
|
+
}
|
|
6864
|
+
return [];
|
|
6865
|
+
}
|
|
6866
|
+
}
|
|
6867
|
+
}
|
|
6599
6868
|
function collectEnvTemplateKeys(value22) {
|
|
6600
6869
|
const keys = /* @__PURE__ */ new Set();
|
|
6601
6870
|
const walk22 = /* @__PURE__ */ __name3((v) => {
|
|
@@ -6885,7 +7154,7 @@ function needsInheritedWorkspace(graph) {
|
|
|
6885
7154
|
}
|
|
6886
7155
|
return false;
|
|
6887
7156
|
}
|
|
6888
|
-
var __defProp3, __name3, WorkflowTemplateError, TEMPLATE_PLACEHOLDER, TEMPLATE_NAMESPACES, MAP_DESCRIPTOR_KEYS, MAP_MEMBER_MALFORMED_CODE, fromInit, fromStep, value, template, fromRequest, rows, fromKnowledge, SideEffectsSchema, JobResourcesSchema, APPROVER_SPEC_MAX_USERS, ESCALATION_MAX_HOPS, TemplateBindingSchema, ApproverSpecSchema, FourEyesSchema, EscalationHopSchema, TerminalOutcomeSchema, ApprovalOnTimeoutSchema, APPROVER_SPEC_SHAPES, APPROVER_WRITTEN_MAX, USER_ID_SHAPED_RE, BINDING_ROOTS, WORKSPACE_TEMPLATE_EXPR_RE, SLEEP_UNTIL_REPLACEMENT, WORKFLOW_CAPS_DEFAULT, WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS, WORKFLOW_AGENT_DEFAULT_TIMEOUT_SECONDS, WORKFLOW_JOB_DEFAULT_TIMEOUT_SECONDS, WORKFLOW_FOREACH_DEFAULT_CONCURRENCY, WORKFLOW_FOREACH_DEFAULT_MAX_ITEMS, WORKFLOW_LOOP_DEFAULT_MAX_ITERATIONS, WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS, WORKFLOW_SIGNAL_DEFAULT_SOURCES, clone, CONNECTION_ID_HEX_RE, WORKFLOW_JOB_TOOLS, WORKFLOW_JOB_MAX_WORKTREE_ARMS, workspaceOf, mountsWorkspace, isJobTier, jobToolsOf, schemaIsArray, isHitlNode, isSingleStep, singleId, armId, TEMPLATE_STEP_REF, EDITABLE_PATH_RE, PREDICATE_OPS, isPredicateScalar, GRAPH_HASH_PREFIX, WorkflowPlanError, isArmStep, armStepId, armStepKind, joinIdOf, containerIdOf, PATH_PLACEHOLDER, MISSING, stepIdOf, cmp, eq, ne, gt, gte, lt, lte, inSet, notIn, exists, notExists, truthy, falsy, and, or, not, CONTINUED_FAILURE_TAG, CONTINUED_FAILURE_DEFAULT_CODE, CONTINUED_FAILURE_OUTPUT_SCHEMA, CONTINUED_FAILURE_LEAF_PATHS, isHitlNode2, nodeIdOf, GOAL_JUDGE_STEP_ID, NON_LEAF_KINDS, CONDITIONAL_JOIN_ID, branchArmId, canonical, sortKeys, JOIN, entryOfJoin, FORCE_CANCEL_STALE_MS, TERMINAL, WORKFLOW_INLINE_RUN_TAG, RUN_ERROR_ISSUES_MAX, IN_FLIGHT, n, STEP_ERROR_DETAIL_KEYS, STEP_ERROR_DETAIL_MAX_BYTES, DETAIL_MAX_DEPTH, DETAIL_MAX_ITEMS, MAX_HOLIDAYS, MAX_WALK_DAYS, HHMM, YMD, MS_PER_MIN, MS_PER_DAY, MON_FRI, supportedTz, fmtCache, WEEKDAYS, JSON_PATCH_OPS, JSON_PATCH_MAX_OPS, JSON_PATCH_MAX_VALUE_BYTES, JSON_PATCH_MAX_TOTAL_BYTES, SEGMENT_RE, WORKFLOW_ENV_OVERLAY_MAX_KEYS, WORKFLOW_ENV_OVERLAY_MAX_VALUE_BYTES, WORKFLOW_ENV_TEMPLATE_SECRET_KEY_RE, isEnvRef, looksLikeEmbeddedJson, ZERO, isRecord2;
|
|
7157
|
+
var __defProp3, __name3, WorkflowTemplateError, TEMPLATE_PLACEHOLDER, TEMPLATE_NAMESPACES, MAP_DESCRIPTOR_KEYS, MAP_MEMBER_MALFORMED_CODE, fromInit, fromStep, value, template, fromRequest, rows, fromKnowledge, SideEffectsSchema, JobResourcesSchema, APPROVER_SPEC_MAX_USERS, ESCALATION_MAX_HOPS, TemplateBindingSchema, ApproverSpecSchema, FourEyesSchema, EscalationHopSchema, TerminalOutcomeSchema, ApprovalOnTimeoutSchema, APPROVER_SPEC_SHAPES, APPROVER_WRITTEN_MAX, USER_ID_SHAPED_RE, BINDING_ROOTS, WORKSPACE_TEMPLATE_EXPR_RE, SLEEP_UNTIL_REPLACEMENT, WORKFLOW_CAPS_DEFAULT, WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS, WORKFLOW_AGENT_DEFAULT_TIMEOUT_SECONDS, WORKFLOW_JOB_DEFAULT_TIMEOUT_SECONDS, WORKFLOW_FOREACH_DEFAULT_CONCURRENCY, WORKFLOW_FOREACH_DEFAULT_MAX_ITEMS, WORKFLOW_LOOP_DEFAULT_MAX_ITERATIONS, WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS, WORKFLOW_SIGNAL_DEFAULT_SOURCES, clone, CONNECTION_ID_HEX_RE, WORKFLOW_JOB_TOOLS, WORKFLOW_JOB_MAX_WORKTREE_ARMS, workspaceOf, mountsWorkspace, isJobTier, jobToolsOf, schemaIsArray, isHitlNode, isSingleStep, singleId, armId, TEMPLATE_STEP_REF, EDITABLE_PATH_RE, PREDICATE_OPS, isPredicateScalar, GRAPH_HASH_PREFIX, WorkflowPlanError, isArmStep, armStepId, armStepKind, joinIdOf, containerIdOf, PATH_PLACEHOLDER, MISSING, stepIdOf, cmp, eq, ne, gt, gte, lt, lte, inSet, notIn, exists, notExists, truthy, falsy, and, or, not, CONTINUED_FAILURE_TAG, CONTINUED_FAILURE_DEFAULT_CODE, CONTINUED_FAILURE_OUTPUT_SCHEMA, CONTINUED_FAILURE_LEAF_PATHS, isHitlNode2, nodeIdOf, GOAL_JUDGE_STEP_ID, NON_LEAF_KINDS, CONDITIONAL_JOIN_ID, branchArmId, canonical, sortKeys, JOIN, entryOfJoin, FORCE_CANCEL_STALE_MS, TERMINAL, WORKFLOW_INLINE_RUN_TAG, RUN_ERROR_ISSUES_MAX, IN_FLIGHT, n, STEP_ERROR_DETAIL_KEYS, STEP_ERROR_DETAIL_MAX_BYTES, DETAIL_MAX_DEPTH, DETAIL_MAX_ITEMS, MAX_HOLIDAYS, MAX_WALK_DAYS, HHMM, YMD, MS_PER_MIN, MS_PER_DAY, MON_FRI, supportedTz, fmtCache, WEEKDAYS, JSON_PATCH_OPS, JSON_PATCH_MAX_OPS, JSON_PATCH_MAX_VALUE_BYTES, JSON_PATCH_MAX_TOTAL_BYTES, SEGMENT_RE, WORKFLOW_SCHEDULE_TYPES, WORKFLOW_SCHEDULE_SHAPE_ISSUE, WORKFLOW_SCHEDULE_SHAPES_HINT, isObject, WORKFLOW_ENV_OVERLAY_MAX_KEYS, WORKFLOW_ENV_OVERLAY_MAX_VALUE_BYTES, WORKFLOW_ENV_TEMPLATE_SECRET_KEY_RE, isEnvRef, looksLikeEmbeddedJson, ZERO, isRecord2;
|
|
6889
7158
|
var init_dist2 = __esm({
|
|
6890
7159
|
"../workflow-graph/dist/index.mjs"() {
|
|
6891
7160
|
"use strict";
|
|
@@ -7440,6 +7709,10 @@ var init_dist2 = __esm({
|
|
|
7440
7709
|
__name3(runCountsFromStatusTally, "runCountsFromStatusTally");
|
|
7441
7710
|
__name(runCountsFromStepStatuses, "runCountsFromStepStatuses");
|
|
7442
7711
|
__name3(runCountsFromStepStatuses, "runCountsFromStepStatuses");
|
|
7712
|
+
__name(isBillingHeldStep, "isBillingHeldStep");
|
|
7713
|
+
__name3(isBillingHeldStep, "isBillingHeldStep");
|
|
7714
|
+
__name(stepEffectiveStatus, "stepEffectiveStatus");
|
|
7715
|
+
__name3(stepEffectiveStatus, "stepEffectiveStatus");
|
|
7443
7716
|
n = /* @__PURE__ */ __name3((v) => typeof v === "number" && Number.isFinite(v) ? v : 0, "n");
|
|
7444
7717
|
__name(runCounts, "runCounts");
|
|
7445
7718
|
__name3(runCounts, "runCounts");
|
|
@@ -7591,6 +7864,16 @@ var init_dist2 = __esm({
|
|
|
7591
7864
|
__name3(applyJsonPatch, "applyJsonPatch");
|
|
7592
7865
|
__name(rebaseItemPointer, "rebaseItemPointer");
|
|
7593
7866
|
__name3(rebaseItemPointer, "rebaseItemPointer");
|
|
7867
|
+
WORKFLOW_SCHEDULE_TYPES = [
|
|
7868
|
+
"cron",
|
|
7869
|
+
"interval",
|
|
7870
|
+
"once"
|
|
7871
|
+
];
|
|
7872
|
+
WORKFLOW_SCHEDULE_SHAPE_ISSUE = "schedule-shape-invalid";
|
|
7873
|
+
WORKFLOW_SCHEDULE_SHAPES_HINT = "`schedule` must be one of { type: 'cron', expression: '<5-field cron>', timezone?: '<IANA tz>' } | { type: 'interval', seconds: <n> } | { type: 'once', executeAt: '<ISO-8601>' }";
|
|
7874
|
+
isObject = /* @__PURE__ */ __name3((v) => typeof v === "object" && v !== null && !Array.isArray(v), "isObject");
|
|
7875
|
+
__name(validateWorkflowSchedule, "validateWorkflowSchedule");
|
|
7876
|
+
__name3(validateWorkflowSchedule, "validateWorkflowSchedule");
|
|
7594
7877
|
WORKFLOW_ENV_OVERLAY_MAX_KEYS = 64;
|
|
7595
7878
|
WORKFLOW_ENV_OVERLAY_MAX_VALUE_BYTES = 4096;
|
|
7596
7879
|
WORKFLOW_ENV_TEMPLATE_SECRET_KEY_RE = /(SECRET|TOKEN|KEY|PASSWORD)$/;
|
|
@@ -7860,7 +8143,7 @@ var init_workflow = __esm({
|
|
|
7860
8143
|
}, "assertPredicate");
|
|
7861
8144
|
assertRetry = /* @__PURE__ */ __name((r, id) => {
|
|
7862
8145
|
if (!r) return;
|
|
7863
|
-
if (
|
|
8146
|
+
if (!isWithinWorkflowRetryAttempts(r.maxAttempts)) {
|
|
7864
8147
|
const over = typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS;
|
|
7865
8148
|
throw new LuaWorkflowBuildError(over ? "cap-exceeded" : "invalid-envelope", `"${id}": ${workflowRetryMaxAttemptsMessage(r.maxAttempts)}`);
|
|
7866
8149
|
}
|
|
@@ -8381,9 +8664,12 @@ var init_workflow = __esm({
|
|
|
8381
8664
|
if (opts.approver === "creator" && opts.excludeInitiator === true) {
|
|
8382
8665
|
throw new LuaWorkflowBuildError("approver-excludes-only-candidate", `"${id}": approver:'creator' with excludeInitiator:true always excludes the only candidate`);
|
|
8383
8666
|
}
|
|
8384
|
-
|
|
8385
|
-
if (
|
|
8386
|
-
|
|
8667
|
+
const editable = approvalEditable(opts);
|
|
8668
|
+
if (opts.fourEyes !== void 0 && !editable) throw new LuaWorkflowBuildError("four-eyes-requires-editable", `"${id}": \`fourEyes\` requires editable:true`);
|
|
8669
|
+
if (opts.editable === false && Array.isArray(opts.editablePaths) && opts.editablePaths.length > 0) {
|
|
8670
|
+
throw new LuaWorkflowBuildError("editable-path-invalid", `"${id}": \`editablePaths\` beside editable:false is contradictory \u2014 drop the paths or set editable:true`);
|
|
8671
|
+
} else if ((opts.editablePaths !== void 0 || opts.editedPayloadSchema !== void 0) && !editable) {
|
|
8672
|
+
throw new LuaWorkflowBuildError("editable-path-invalid", `"${id}": \`editablePaths\` / \`editedPayloadSchema\` require editable:true (a non-empty editablePaths implies it)`);
|
|
8387
8673
|
}
|
|
8388
8674
|
for (const p of opts.editablePaths ?? []) {
|
|
8389
8675
|
if (!EDITABLE_PATH_RE2.test(p)) throw new LuaWorkflowBuildError("editable-path-invalid", `"${id}": editablePaths entry "${p}" is outside the grammar seg(.seg)* with [*]/[n] selectors`);
|
|
@@ -8719,6 +9005,71 @@ var init_types = __esm({
|
|
|
8719
9005
|
|
|
8720
9006
|
// src/api/http.client.ts
|
|
8721
9007
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
9008
|
+
async function classifyErrorResponse(response) {
|
|
9009
|
+
let errorData;
|
|
9010
|
+
try {
|
|
9011
|
+
errorData = await response.json();
|
|
9012
|
+
} catch (jsonError) {
|
|
9013
|
+
errorData = {};
|
|
9014
|
+
}
|
|
9015
|
+
if (response.status === 401) {
|
|
9016
|
+
const serverMessage = typeof errorData.message === "string" ? errorData.message : void 0;
|
|
9017
|
+
if (serverMessage && /not an admin/i.test(serverMessage)) {
|
|
9018
|
+
throw new AuthenticationError(`Access denied for this agent: ${serverMessage}`, "no_agent_access", serverMessage);
|
|
9019
|
+
}
|
|
9020
|
+
const isExplicitCredential = !!serverMessage && /(invalid|expired|missing|no)\s+(api[\s_-]?key|token|credential)/i.test(serverMessage);
|
|
9021
|
+
const isBareAuthRejection = !serverMessage || /^unauthorized$/i.test(serverMessage);
|
|
9022
|
+
if (isExplicitCredential || isBareAuthRejection) {
|
|
9023
|
+
throw new AuthenticationError("Authentication failed. Your Lua credential may be invalid or expired.", "invalid_credentials", serverMessage);
|
|
9024
|
+
}
|
|
9025
|
+
throw new AuthenticationError(`Authentication failed: ${serverMessage}`, "unknown", serverMessage);
|
|
9026
|
+
}
|
|
9027
|
+
if (response.status === 403) {
|
|
9028
|
+
const detail = errorData.message || "You do not have permission to access this resource.";
|
|
9029
|
+
const serverCode = serverCodeOf(errorData.code, errorData.error);
|
|
9030
|
+
throw new CliError("forbidden", `Access denied (403): ${detail}${serverCode ? ` (${serverCode})` : ""}`, {
|
|
9031
|
+
exitCode: CLI_EXIT.FORBIDDEN,
|
|
9032
|
+
statusCode: 403,
|
|
9033
|
+
serverCode,
|
|
9034
|
+
issues: Array.isArray(errorData.issues) ? errorData.issues : void 0,
|
|
9035
|
+
hint: "Check that your Lua login has access to this agent or organization."
|
|
9036
|
+
});
|
|
9037
|
+
}
|
|
9038
|
+
return {
|
|
9039
|
+
success: false,
|
|
9040
|
+
error: {
|
|
9041
|
+
message: errorData.message || `HTTP ${response.status}: ${response.statusText}`,
|
|
9042
|
+
statusCode: response.status,
|
|
9043
|
+
error: errorData.error,
|
|
9044
|
+
retryAfterSeconds: parseRetryAfter(response.headers.get("retry-after")),
|
|
9045
|
+
...errorData
|
|
9046
|
+
}
|
|
9047
|
+
};
|
|
9048
|
+
}
|
|
9049
|
+
function serverCodeOf(code, error) {
|
|
9050
|
+
if (typeof code === "string" && code.length > 0) return code;
|
|
9051
|
+
if (typeof error === "string" && /^[A-Z0-9][A-Z0-9_]*$/.test(error)) return error;
|
|
9052
|
+
return void 0;
|
|
9053
|
+
}
|
|
9054
|
+
async function refusalFromResponse(response) {
|
|
9055
|
+
const { error } = await classifyErrorResponse(response);
|
|
9056
|
+
const serverCode = serverCodeOf(error?.code, error?.error);
|
|
9057
|
+
return CliError.fromStatus(
|
|
9058
|
+
error?.statusCode ?? response.status,
|
|
9059
|
+
error?.message ?? `HTTP ${response.status}: ${response.statusText}`,
|
|
9060
|
+
void 0,
|
|
9061
|
+
// LUA-810: `fromStatus` picks the UPSTREAM_UNAVAILABLE hint from the body's `upstream` / `requestId`.
|
|
9062
|
+
// LUA-812: and the VENDOR_UNAVAILABLE hint from `vendor` / `retryAfterSeconds` (whether a blind retry is safe).
|
|
9063
|
+
{
|
|
9064
|
+
serverCode,
|
|
9065
|
+
issues: error?.issues,
|
|
9066
|
+
upstream: error?.upstream,
|
|
9067
|
+
requestId: error?.requestId,
|
|
9068
|
+
vendor: error?.vendor,
|
|
9069
|
+
retryAfterSeconds: error?.retryAfterSeconds
|
|
9070
|
+
}
|
|
9071
|
+
);
|
|
9072
|
+
}
|
|
8722
9073
|
async function* parseSseStream(body, signal) {
|
|
8723
9074
|
const reader = body.getReader();
|
|
8724
9075
|
const decoder = new TextDecoder();
|
|
@@ -8899,42 +9250,7 @@ var init_http_client = __esm({
|
|
|
8899
9250
|
* @private
|
|
8900
9251
|
*/
|
|
8901
9252
|
async classifyErrorResponse(response) {
|
|
8902
|
-
|
|
8903
|
-
try {
|
|
8904
|
-
errorData = await response.json();
|
|
8905
|
-
} catch (jsonError) {
|
|
8906
|
-
errorData = {};
|
|
8907
|
-
}
|
|
8908
|
-
if (response.status === 401) {
|
|
8909
|
-
const serverMessage = typeof errorData.message === "string" ? errorData.message : void 0;
|
|
8910
|
-
if (serverMessage && /not an admin/i.test(serverMessage)) {
|
|
8911
|
-
throw new AuthenticationError(`Access denied for this agent: ${serverMessage}`, "no_agent_access", serverMessage);
|
|
8912
|
-
}
|
|
8913
|
-
const isExplicitCredential = !!serverMessage && /(invalid|expired|missing|no)\s+(api[\s_-]?key|token|credential)/i.test(serverMessage);
|
|
8914
|
-
const isBareAuthRejection = !serverMessage || /^unauthorized$/i.test(serverMessage);
|
|
8915
|
-
if (isExplicitCredential || isBareAuthRejection) {
|
|
8916
|
-
throw new AuthenticationError("Authentication failed. Your Lua credential may be invalid or expired.", "invalid_credentials", serverMessage);
|
|
8917
|
-
}
|
|
8918
|
-
throw new AuthenticationError(`Authentication failed: ${serverMessage}`, "unknown", serverMessage);
|
|
8919
|
-
}
|
|
8920
|
-
if (response.status === 403) {
|
|
8921
|
-
const detail = errorData.message || "You do not have permission to access this resource.";
|
|
8922
|
-
throw new CliError("forbidden", `Access denied (403): ${detail}`, {
|
|
8923
|
-
exitCode: CLI_EXIT.FORBIDDEN,
|
|
8924
|
-
statusCode: 403,
|
|
8925
|
-
hint: "Check that your Lua login has access to this agent or organization."
|
|
8926
|
-
});
|
|
8927
|
-
}
|
|
8928
|
-
return {
|
|
8929
|
-
success: false,
|
|
8930
|
-
error: {
|
|
8931
|
-
message: errorData.message || `HTTP ${response.status}: ${response.statusText}`,
|
|
8932
|
-
statusCode: response.status,
|
|
8933
|
-
error: errorData.error,
|
|
8934
|
-
retryAfterSeconds: parseRetryAfter(response.headers.get("retry-after")),
|
|
8935
|
-
...errorData
|
|
8936
|
-
}
|
|
8937
|
-
};
|
|
9253
|
+
return classifyErrorResponse(response);
|
|
8938
9254
|
}
|
|
8939
9255
|
/**
|
|
8940
9256
|
* Checks if an HTTP status code is retryable
|
|
@@ -8958,6 +9274,21 @@ var init_http_client = __esm({
|
|
|
8958
9274
|
return Math.max(100, Math.random() * exponential);
|
|
8959
9275
|
}
|
|
8960
9276
|
/**
|
|
9277
|
+
* The wait before the next attempt: the client's jittered exponential backoff, floored by the server's
|
|
9278
|
+
* `retryAfterSeconds` on a 429 (the limiter's word is final) and on an idempotent read (GET / HEAD). LUA-810: a
|
|
9279
|
+
* POST / PUT / PATCH / DELETE that met a 5xx keeps the client's own backoff — every 503 body carries
|
|
9280
|
+
* `retryAfterSeconds: 5` (`CONTROL_UNAVAILABLE`, `UPSTREAM_UNAVAILABLE`), which floored all three waits at 5 s:
|
|
9281
|
+
* a ≥15 s stall on a write that may already have landed, and retrying an ambiguous write harder does not make
|
|
9282
|
+
* it less ambiguous. The client's own schedule is ≤1 s + ≤2 s + ≤4 s.
|
|
9283
|
+
*/
|
|
9284
|
+
retryDelayMs(attempt, error, method) {
|
|
9285
|
+
const own = this.calculateBackoff(attempt);
|
|
9286
|
+
const advised = Number(error?.retryAfterSeconds ?? 0) * 1e3;
|
|
9287
|
+
const verb = (method ?? "GET").toUpperCase();
|
|
9288
|
+
const honourAdvice = error?.statusCode === 429 || verb === "GET" || verb === "HEAD";
|
|
9289
|
+
return honourAdvice ? Math.max(own, advised) : own;
|
|
9290
|
+
}
|
|
9291
|
+
/**
|
|
8961
9292
|
* Wraps request with retry logic for transient failures
|
|
8962
9293
|
* @param url - The full URL to request
|
|
8963
9294
|
* @param options - Fetch API request options
|
|
@@ -8991,8 +9322,7 @@ var init_http_client = __esm({
|
|
|
8991
9322
|
throw error;
|
|
8992
9323
|
}
|
|
8993
9324
|
if (attempt < maxRetries) {
|
|
8994
|
-
const
|
|
8995
|
-
const backoff = Math.max(this.calculateBackoff(attempt), serverDelay);
|
|
9325
|
+
const backoff = this.retryDelayMs(attempt, lastResult?.error, options.method);
|
|
8996
9326
|
await new Promise((resolve7) => setTimeout(resolve7, backoff));
|
|
8997
9327
|
}
|
|
8998
9328
|
}
|
|
@@ -9142,6 +9472,9 @@ var init_http_client = __esm({
|
|
|
9142
9472
|
};
|
|
9143
9473
|
}
|
|
9144
9474
|
};
|
|
9475
|
+
__name(classifyErrorResponse, "classifyErrorResponse");
|
|
9476
|
+
__name(serverCodeOf, "serverCodeOf");
|
|
9477
|
+
__name(refusalFromResponse, "refusalFromResponse");
|
|
9145
9478
|
__name(parseSseStream, "parseSseStream");
|
|
9146
9479
|
__name(parseRetryAfter, "parseRetryAfter");
|
|
9147
9480
|
__name(isCoreDrainApiError, "isCoreDrainApiError");
|
|
@@ -11568,8 +11901,14 @@ async function withErrorHandling(commandFn, commandName, opts) {
|
|
|
11568
11901
|
} catch {
|
|
11569
11902
|
}
|
|
11570
11903
|
}
|
|
11904
|
+
let json = false;
|
|
11905
|
+
try {
|
|
11906
|
+
json = typeof opts?.json === "function" ? !!opts.json() : !!opts?.json;
|
|
11907
|
+
} catch {
|
|
11908
|
+
}
|
|
11571
11909
|
const reported = reportCliError(error, {
|
|
11572
|
-
extraHint
|
|
11910
|
+
extraHint,
|
|
11911
|
+
json
|
|
11573
11912
|
});
|
|
11574
11913
|
process.exitCode = reported.exitCode;
|
|
11575
11914
|
await showUpdateWarningIfNeeded(versionCheckPromise);
|
|
@@ -25850,6 +26189,7 @@ var init_job_api_service = __esm({
|
|
|
25850
26189
|
"src/api/job.api.service.ts"() {
|
|
25851
26190
|
"use strict";
|
|
25852
26191
|
init_http_client();
|
|
26192
|
+
init_cli_error();
|
|
25853
26193
|
init_job_instance();
|
|
25854
26194
|
JobApi = class extends HttpClient {
|
|
25855
26195
|
static {
|
|
@@ -25906,7 +26246,7 @@ var init_job_api_service = __esm({
|
|
|
25906
26246
|
if (response.success && response.data) {
|
|
25907
26247
|
return new JobInstance(this, response.data);
|
|
25908
26248
|
}
|
|
25909
|
-
throw
|
|
26249
|
+
throw CliError.fromStatus(response.error?.statusCode, response.error?.message || "Failed to get job", void 0, apiErrorDetail(response.error));
|
|
25910
26250
|
}
|
|
25911
26251
|
/**
|
|
25912
26252
|
* Creates a new job for the agent.
|
|
@@ -27381,7 +27721,7 @@ async function fetchApprovedModelsOrThrow(apiKey, agentId, orgId) {
|
|
|
27381
27721
|
const agentApi = new AgentApi(BASE_URLS.API, apiKey);
|
|
27382
27722
|
const result = await agentApi.getApprovedModels(void 0, agentId, orgId);
|
|
27383
27723
|
if (!result.success) {
|
|
27384
|
-
throw CliError.fromStatus(result.error?.statusCode, `Could not fetch models from the server: ${result.error?.message || "Unknown error"}
|
|
27724
|
+
throw CliError.fromStatus(result.error?.statusCode, `Could not fetch models from the server: ${result.error?.message || "Unknown error"}`, void 0, apiErrorDetail(result.error));
|
|
27385
27725
|
}
|
|
27386
27726
|
return result.data ?? [];
|
|
27387
27727
|
}
|
|
@@ -29752,7 +30092,7 @@ async function handleAgentSwitch(credential, organizations, apiKey, existingYaml
|
|
|
29752
30092
|
});
|
|
29753
30093
|
writeSuccess("\u2705 lua.skill.yaml updated successfully!");
|
|
29754
30094
|
writeSuccess("\u2705 LuaAgent configuration updated!");
|
|
29755
|
-
writeInfo("\n\u{1F4A1} Your project now uses the new agent. Run 'lua
|
|
30095
|
+
writeInfo("\n\u{1F4A1} Your project now uses the new agent. Run 'lua sync' (or 'lua push all') to reconcile your skills.\n");
|
|
29756
30096
|
trackEvent("cli_init_agent_switched", {
|
|
29757
30097
|
model_selected: !!selectedModel,
|
|
29758
30098
|
model: selectedModel
|
|
@@ -30137,7 +30477,9 @@ async function syncCommand(options) {
|
|
|
30137
30477
|
let syncCompletedSuccessfully = false;
|
|
30138
30478
|
try {
|
|
30139
30479
|
writeProgress("\u{1F504} Compiling to get latest local state...");
|
|
30140
|
-
await compileCommand(
|
|
30480
|
+
await compileCommand({
|
|
30481
|
+
serverSync: true
|
|
30482
|
+
});
|
|
30141
30483
|
writeProgress("\u{1F504} Checking for drift between server and local code...");
|
|
30142
30484
|
const { agentId, apiKey } = await initializeCommand({
|
|
30143
30485
|
showProgress: false
|
|
@@ -34877,7 +35219,8 @@ var WorkflowHandler = class extends BaseVersionedHandler {
|
|
|
34877
35219
|
success: response.success,
|
|
34878
35220
|
error: response.error?.message,
|
|
34879
35221
|
statusCode: response.error?.statusCode,
|
|
34880
|
-
code: response.error?.code ?? response.error?.error
|
|
35222
|
+
code: response.error?.code ?? response.error?.error,
|
|
35223
|
+
issues: response.error?.issues
|
|
34881
35224
|
};
|
|
34882
35225
|
}
|
|
34883
35226
|
/**
|
|
@@ -35083,7 +35426,7 @@ async function compileCommand(options) {
|
|
|
35083
35426
|
const debugMode = options?.debug || debugEnabled();
|
|
35084
35427
|
const verboseMode = options?.verbose || debugMode;
|
|
35085
35428
|
const doSync = options?.sync === true;
|
|
35086
|
-
const doServerSync = options?.serverSync
|
|
35429
|
+
const doServerSync = options?.serverSync === true;
|
|
35087
35430
|
if (debugMode) {
|
|
35088
35431
|
console.log("\u{1F41B} Debug mode enabled");
|
|
35089
35432
|
}
|
|
@@ -35180,7 +35523,7 @@ async function compileCommand(options) {
|
|
|
35180
35523
|
let syncConfig = readYamlConfig();
|
|
35181
35524
|
const agentId = syncConfig?.agent?.agentId;
|
|
35182
35525
|
if (!doServerSync) {
|
|
35183
|
-
writeInfo("\u2139\uFE0F Server sync skipped
|
|
35526
|
+
writeInfo("\u2139\uFE0F Server sync skipped \u2014 nothing was sent to the server; `lua push` publishes.");
|
|
35184
35527
|
} else if (apiKey && agentId) {
|
|
35185
35528
|
writeProgress("\u{1F504} Syncing with server...");
|
|
35186
35529
|
const fetchResults = await Promise.all(syncableHandlers.map((h) => h.fetchServerState(apiKey, agentId)));
|
|
@@ -38458,7 +38801,8 @@ async function pushBackupCommand(options = {}) {
|
|
|
38458
38801
|
}
|
|
38459
38802
|
writeInfo("No compilation output found. Running compile first...");
|
|
38460
38803
|
await compileCommand({
|
|
38461
|
-
sync: false
|
|
38804
|
+
sync: false,
|
|
38805
|
+
serverSync: true
|
|
38462
38806
|
});
|
|
38463
38807
|
}
|
|
38464
38808
|
writeProgress("Pushing backup...");
|
|
@@ -39156,12 +39500,24 @@ function formatPushFailureSummary(failedItems) {
|
|
|
39156
39500
|
return lines.join("\n");
|
|
39157
39501
|
}
|
|
39158
39502
|
__name(formatPushFailureSummary, "formatPushFailureSummary");
|
|
39503
|
+
function pushRefusalError(handler, name, result) {
|
|
39504
|
+
const reason = result.error || "Unknown error";
|
|
39505
|
+
const isVersionConflict = reason.toLowerCase().includes("already exists");
|
|
39506
|
+
return new CliError("error", `${handler.displayName.toLowerCase()} "${name}" is not pushed: ${reason}`, {
|
|
39507
|
+
exitCode: CLI_EXIT.ERROR,
|
|
39508
|
+
statusCode: result.statusCode,
|
|
39509
|
+
serverCode: result.code,
|
|
39510
|
+
issues: result.issues,
|
|
39511
|
+
hint: isVersionConflict ? `Version conflict \u2014 this version already exists on the server. Auto-bump: lua push ${handler.kind} --force \xB7 or push all: lua push all --force` : void 0
|
|
39512
|
+
});
|
|
39513
|
+
}
|
|
39514
|
+
__name(pushRefusalError, "pushRefusalError");
|
|
39159
39515
|
function stalePushEntryError(handler, name, entityId, serverMessage) {
|
|
39160
39516
|
const field = handler.yamlConfig.idField;
|
|
39161
39517
|
return new CliError("not_found", `${handler.displayName} "${name}" (${entityId}) no longer exists on the server${serverMessage ? ` \u2014 ${serverMessage}` : ""}`, {
|
|
39162
39518
|
exitCode: CLI_EXIT.NOT_FOUND,
|
|
39163
39519
|
statusCode: 404,
|
|
39164
|
-
hint: `lua.skill.yaml still holds ${field}: ${entityId} for "${name}".
|
|
39520
|
+
hint: `lua.skill.yaml still holds ${field}: ${entityId} for "${name}". Remove that ${field}: line from lua.skill.yaml, then run \`lua push ${handler.displayName}\` again \u2014 its compile step registers the definition afresh and writes the new id.`
|
|
39165
39521
|
});
|
|
39166
39522
|
}
|
|
39167
39523
|
__name(stalePushEntryError, "stalePushEntryError");
|
|
@@ -39310,7 +39666,9 @@ __name(shouldDeployAfterPush, "shouldDeployAfterPush");
|
|
|
39310
39666
|
async function pushVersionedPrimitive(handler, options = {}) {
|
|
39311
39667
|
try {
|
|
39312
39668
|
writeProgress("\u{1F4E6} Compiling project...");
|
|
39313
|
-
await compileCommand(
|
|
39669
|
+
await compileCommand({
|
|
39670
|
+
serverSync: true
|
|
39671
|
+
});
|
|
39314
39672
|
writeSuccess("\u2705 Compilation complete");
|
|
39315
39673
|
const apiKey = await authenticateOrFail();
|
|
39316
39674
|
const config = readYamlConfig();
|
|
@@ -39332,7 +39690,7 @@ async function pushVersionedPrimitive(handler, options = {}) {
|
|
|
39332
39690
|
});
|
|
39333
39691
|
const entityId = selected[handler.yamlConfig.idField];
|
|
39334
39692
|
if (!entityId) {
|
|
39335
|
-
throw new Error(`${handler.displayName} "${selected.name}" has no server ID.
|
|
39693
|
+
throw new Error(`${handler.displayName} "${selected.name}" has no server ID \u2014 the create above failed. Fix it and run 'lua push ${handler.displayName}' again.`);
|
|
39336
39694
|
}
|
|
39337
39695
|
const manifest = loadManifest();
|
|
39338
39696
|
const bundleAccumulator = /* @__PURE__ */ new Map();
|
|
@@ -39363,24 +39721,7 @@ async function pushVersionedPrimitive(handler, options = {}) {
|
|
|
39363
39721
|
});
|
|
39364
39722
|
if (!result.success) {
|
|
39365
39723
|
if (result.statusCode === 404) throw stalePushEntryError(handler, selected.name, entityId, result.error);
|
|
39366
|
-
|
|
39367
|
-
if (isVersionConflict) {
|
|
39368
|
-
writeHintBlock({
|
|
39369
|
-
headline: "Version conflict \u2014 this version already exists on the server.",
|
|
39370
|
-
lines: [
|
|
39371
|
-
{
|
|
39372
|
-
label: "Auto-bump:",
|
|
39373
|
-
command: `lua push ${handler.kind} --force`
|
|
39374
|
-
},
|
|
39375
|
-
{
|
|
39376
|
-
label: "Or push all:",
|
|
39377
|
-
command: "lua push all --force"
|
|
39378
|
-
}
|
|
39379
|
-
],
|
|
39380
|
-
when: "error"
|
|
39381
|
-
});
|
|
39382
|
-
}
|
|
39383
|
-
throw new Error(`Push Error: ${result.error || "Unknown error"}`);
|
|
39724
|
+
throw pushRefusalError(handler, selected.name, result);
|
|
39384
39725
|
}
|
|
39385
39726
|
writeSuccess(`
|
|
39386
39727
|
\u2705 Successfully pushed ${selected.name} v${confirmedVersion}
|
|
@@ -39726,7 +40067,9 @@ async function runIncludeSourceHook(apiKey, agentId, selectedType) {
|
|
|
39726
40067
|
__name(runIncludeSourceHook, "runIncludeSourceHook");
|
|
39727
40068
|
async function pushAgentVersion(options = {}) {
|
|
39728
40069
|
writeProgress("\u{1F504} Compiling...");
|
|
39729
|
-
await compileCommand(
|
|
40070
|
+
await compileCommand({
|
|
40071
|
+
serverSync: true
|
|
40072
|
+
});
|
|
39730
40073
|
const config = readYamlConfig();
|
|
39731
40074
|
if (!config || !config.agent?.agentId) {
|
|
39732
40075
|
throw new Error("No agent configuration found. Please run 'lua init' first.");
|
|
@@ -39833,7 +40176,9 @@ __name(deployPersonaVersionAfterPush, "deployPersonaVersionAfterPush");
|
|
|
39833
40176
|
async function pushMCPServer(options = {}) {
|
|
39834
40177
|
try {
|
|
39835
40178
|
writeProgress("\u{1F4E6} Compiling project...");
|
|
39836
|
-
await compileCommand(
|
|
40179
|
+
await compileCommand({
|
|
40180
|
+
serverSync: true
|
|
40181
|
+
});
|
|
39837
40182
|
writeSuccess("\u2705 Compilation complete");
|
|
39838
40183
|
const apiKey = await authenticateOrFail();
|
|
39839
40184
|
writeSuccess("\u2705 Authentication verified");
|
|
@@ -39886,7 +40231,9 @@ async function pushAllCommand(options) {
|
|
|
39886
40231
|
writeInfo("\u{1F680} Auto-deploy to production is ENABLED\n");
|
|
39887
40232
|
}
|
|
39888
40233
|
writeProgress("\u{1F4E6} Compiling project...");
|
|
39889
|
-
await compileCommand(
|
|
40234
|
+
await compileCommand({
|
|
40235
|
+
serverSync: true
|
|
40236
|
+
});
|
|
39890
40237
|
const config = readYamlConfig();
|
|
39891
40238
|
if (!config?.agent?.agentId) {
|
|
39892
40239
|
throw new Error('No agent ID found in lua.skill.yaml. Run "lua init" first.');
|
|
@@ -39974,7 +40321,7 @@ ${icon} Pushing ${items.length} ${handler.displayName}(s)...`);
|
|
|
39974
40321
|
}
|
|
39975
40322
|
const entityId = item[handler.yamlConfig.idField];
|
|
39976
40323
|
if (!entityId) {
|
|
39977
|
-
console.warn(`\u26A0\uFE0F ${handler.displayName} "${item.name}" has no server ID, skipping.
|
|
40324
|
+
console.warn(`\u26A0\uFE0F ${handler.displayName} "${item.name}" has no server ID, skipping \u2014 the create above failed. Fix it and run 'lua push ${handler.displayName}' again.`);
|
|
39978
40325
|
continue;
|
|
39979
40326
|
}
|
|
39980
40327
|
if (!item.version) {
|
|
@@ -41921,7 +42268,9 @@ __name(chatCommand, "chatCommand");
|
|
|
41921
42268
|
async function setupChatEnvironment(chatEnv, config) {
|
|
41922
42269
|
writeProgress("\u{1F504} Setting up sandbox environment...");
|
|
41923
42270
|
writeProgress("\u{1F504} Compiling skill...");
|
|
41924
|
-
await compileCommand(
|
|
42271
|
+
await compileCommand({
|
|
42272
|
+
serverSync: true
|
|
42273
|
+
});
|
|
41925
42274
|
const manifest = loadManifest();
|
|
41926
42275
|
const skills = getPrimitivesByKind(manifest, PrimitiveKind.SKILL);
|
|
41927
42276
|
let sandboxIds = {};
|
|
@@ -45026,7 +45375,7 @@ function channelCreateError(error, alreadyConnected) {
|
|
|
45026
45375
|
return CliError.fromStatus(400, "Channel already exists", `${alreadyConnected}
|
|
45027
45376
|
Use 'lua channels' to list existing channels.`);
|
|
45028
45377
|
}
|
|
45029
|
-
return CliError.fromStatus(error?.statusCode, error?.message || "Unknown error", error?.error);
|
|
45378
|
+
return CliError.fromStatus(error?.statusCode, error?.message || "Unknown error", error?.error, apiErrorDetail(error));
|
|
45030
45379
|
}
|
|
45031
45380
|
__name(channelCreateError, "channelCreateError");
|
|
45032
45381
|
async function fetchChannelsCore(agentApi, agentId) {
|
|
@@ -45962,7 +46311,7 @@ async function nonInteractiveLogs(logsApi, agentId, apiKey, options) {
|
|
|
45962
46311
|
}
|
|
45963
46312
|
const response = await logsApi.getAgentLogs(agentId, options.limit || 20, options.page || 1, filters);
|
|
45964
46313
|
if (!response.success) {
|
|
45965
|
-
throw CliError.fromStatus(response.error?.statusCode, response.error?.message || "Unknown error");
|
|
46314
|
+
throw CliError.fromStatus(response.error?.statusCode, response.error?.message || "Unknown error", void 0, apiErrorDetail(response.error));
|
|
45966
46315
|
}
|
|
45967
46316
|
const data = response.data;
|
|
45968
46317
|
if (options.json) {
|
|
@@ -46174,7 +46523,7 @@ async function viewAgentLogsInteractive(logsApi, agentId, filters = {}) {
|
|
|
46174
46523
|
while (keepViewing) {
|
|
46175
46524
|
const response = await logsApi.getAgentLogs(agentId, limit, currentPage, filters);
|
|
46176
46525
|
if (!response.success) {
|
|
46177
|
-
throw CliError.fromStatus(response.error?.statusCode, response.error?.message || "Unknown error");
|
|
46526
|
+
throw CliError.fromStatus(response.error?.statusCode, response.error?.message || "Unknown error", void 0, apiErrorDetail(response.error));
|
|
46178
46527
|
}
|
|
46179
46528
|
const data = response.data;
|
|
46180
46529
|
displayLogsCore(data.logs, data.pagination, "All Agent Logs", true);
|
|
@@ -49703,7 +50052,7 @@ async function jobsCommand(action, cmdObj) {
|
|
|
49703
50052
|
}, "jobs");
|
|
49704
50053
|
}
|
|
49705
50054
|
__name(jobsCommand, "jobsCommand");
|
|
49706
|
-
async function displayJobsCore(context, jobs) {
|
|
50055
|
+
async function displayJobsCore(context, jobs, opts = {}) {
|
|
49707
50056
|
console.log("\n" + "=".repeat(60));
|
|
49708
50057
|
console.log("\u2699\uFE0F Production Jobs");
|
|
49709
50058
|
console.log("=".repeat(60) + "\n");
|
|
@@ -49726,7 +50075,14 @@ async function displayJobsCore(context, jobs) {
|
|
|
49726
50075
|
}
|
|
49727
50076
|
console.log();
|
|
49728
50077
|
} catch (error) {
|
|
49729
|
-
|
|
50078
|
+
if (CliError.isCliError(error) && error.statusCode === 404) {
|
|
50079
|
+
if (opts.single) {
|
|
50080
|
+
throw CliError.notFound(`Job "${job.name}" (${job.jobId}) no longer exists on the server \u2014 ${error.message}`, "lua.skill.yaml still lists it; `lua sync` reconciles the local config with the server.");
|
|
50081
|
+
}
|
|
50082
|
+
displayJobError(job, "not found on the server");
|
|
50083
|
+
continue;
|
|
50084
|
+
}
|
|
50085
|
+
throw error;
|
|
49730
50086
|
}
|
|
49731
50087
|
}
|
|
49732
50088
|
console.log("=".repeat(60));
|
|
@@ -49994,7 +50350,13 @@ async function executeNonInteractive7(context, config, action, options) {
|
|
|
49994
50350
|
console.log("\u2139\uFE0F No jobs found in configuration.");
|
|
49995
50351
|
return;
|
|
49996
50352
|
}
|
|
49997
|
-
|
|
50353
|
+
const viewed = options.jobName ? jobs.filter((j) => j.jobId === options.jobName || j.name === options.jobName) : jobs;
|
|
50354
|
+
if (viewed.length === 0) {
|
|
50355
|
+
throw CliError.notFound(`Job "${options.jobName}" not found`, listHint("Available jobs in local config:", jobs.map((j) => `${j.name} (${j.jobId})`)));
|
|
50356
|
+
}
|
|
50357
|
+
await displayJobsCore(context, viewed, {
|
|
50358
|
+
single: !!options.jobName
|
|
50359
|
+
});
|
|
49998
50360
|
return;
|
|
49999
50361
|
}
|
|
50000
50362
|
if (!options.jobName) {
|
|
@@ -50500,69 +50862,77 @@ function exitCodeForRunStatus(status) {
|
|
|
50500
50862
|
}
|
|
50501
50863
|
__name(exitCodeForRunStatus, "exitCodeForRunStatus");
|
|
50502
50864
|
async function workflowsCommand(action, target, extra, cmdObj) {
|
|
50503
|
-
return withErrorHandling(
|
|
50504
|
-
|
|
50505
|
-
|
|
50506
|
-
|
|
50507
|
-
|
|
50508
|
-
|
|
50509
|
-
|
|
50510
|
-
|
|
50511
|
-
|
|
50512
|
-
|
|
50513
|
-
|
|
50514
|
-
|
|
50515
|
-
|
|
50516
|
-
|
|
50517
|
-
|
|
50518
|
-
|
|
50519
|
-
|
|
50520
|
-
|
|
50521
|
-
|
|
50522
|
-
|
|
50523
|
-
|
|
50524
|
-
|
|
50525
|
-
|
|
50526
|
-
|
|
50527
|
-
|
|
50528
|
-
|
|
50529
|
-
|
|
50530
|
-
|
|
50531
|
-
|
|
50532
|
-
|
|
50533
|
-
|
|
50534
|
-
|
|
50535
|
-
|
|
50536
|
-
|
|
50537
|
-
|
|
50538
|
-
|
|
50539
|
-
|
|
50540
|
-
|
|
50541
|
-
|
|
50542
|
-
|
|
50865
|
+
return withErrorHandling(
|
|
50866
|
+
async () => {
|
|
50867
|
+
const options = {
|
|
50868
|
+
...cmdObj ?? {}
|
|
50869
|
+
};
|
|
50870
|
+
const json = !!options.json;
|
|
50871
|
+
let resolved;
|
|
50872
|
+
if (action) {
|
|
50873
|
+
resolved = validateOrSuggest("workflows.action", action);
|
|
50874
|
+
} else {
|
|
50875
|
+
const answer = await safePrompt([
|
|
50876
|
+
{
|
|
50877
|
+
type: "list",
|
|
50878
|
+
name: "action",
|
|
50879
|
+
message: "What would you like to do?",
|
|
50880
|
+
choices: [
|
|
50881
|
+
{
|
|
50882
|
+
name: "\u{1F4CB} List workflows",
|
|
50883
|
+
value: "list"
|
|
50884
|
+
},
|
|
50885
|
+
{
|
|
50886
|
+
name: "\u{1F9ED} Run a workflow locally",
|
|
50887
|
+
value: "run"
|
|
50888
|
+
},
|
|
50889
|
+
{
|
|
50890
|
+
name: "\u25B6\uFE0F Start a run",
|
|
50891
|
+
value: "start"
|
|
50892
|
+
},
|
|
50893
|
+
{
|
|
50894
|
+
name: "\u{1F5C2}\uFE0F List runs",
|
|
50895
|
+
value: "runs"
|
|
50896
|
+
}
|
|
50897
|
+
]
|
|
50898
|
+
}
|
|
50899
|
+
]);
|
|
50900
|
+
if (!answer) return;
|
|
50901
|
+
resolved = answer.action;
|
|
50902
|
+
}
|
|
50903
|
+
if (resolved === "run") {
|
|
50904
|
+
const outcome = await runWorkflowLocalFromProject(target ?? options.workflowName ?? null, options);
|
|
50905
|
+
process.exitCode = outcome.exitCode;
|
|
50906
|
+
trackEvent("cli_workflows_action", {
|
|
50907
|
+
action: "run",
|
|
50908
|
+
non_interactive: !!action
|
|
50909
|
+
});
|
|
50910
|
+
return;
|
|
50911
|
+
}
|
|
50912
|
+
const { agentId, apiKey } = await initializeCommand({
|
|
50913
|
+
showProgress: !json
|
|
50914
|
+
});
|
|
50915
|
+
const ctx = {
|
|
50916
|
+
agentId,
|
|
50917
|
+
apiKey,
|
|
50918
|
+
api: new WorkflowApi(BASE_URLS.API, apiKey, agentId),
|
|
50919
|
+
json
|
|
50920
|
+
};
|
|
50921
|
+
const code = await executeAction(ctx, resolved, target, extra, options);
|
|
50922
|
+
if (code !== void 0 && code !== 0) process.exitCode = code;
|
|
50543
50923
|
trackEvent("cli_workflows_action", {
|
|
50544
|
-
action:
|
|
50545
|
-
non_interactive: !!action
|
|
50924
|
+
action: resolved,
|
|
50925
|
+
non_interactive: !!action,
|
|
50926
|
+
exit_code: code ?? 0
|
|
50546
50927
|
});
|
|
50547
|
-
|
|
50928
|
+
},
|
|
50929
|
+
"workflows",
|
|
50930
|
+
// LUA-803: a typed refusal that escapes a verb under `--json` (a 403 the client threw, an unreachable host) is
|
|
50931
|
+
// the envelope on stdout — the same shape `apiFailure` prints for a refused verb — never the `✖` line.
|
|
50932
|
+
{
|
|
50933
|
+
json: /* @__PURE__ */ __name(() => !!cmdObj?.json, "json")
|
|
50548
50934
|
}
|
|
50549
|
-
|
|
50550
|
-
showProgress: !json
|
|
50551
|
-
});
|
|
50552
|
-
const ctx = {
|
|
50553
|
-
agentId,
|
|
50554
|
-
apiKey,
|
|
50555
|
-
api: new WorkflowApi(BASE_URLS.API, apiKey, agentId),
|
|
50556
|
-
json
|
|
50557
|
-
};
|
|
50558
|
-
const code = await executeAction(ctx, resolved, target, extra, options);
|
|
50559
|
-
if (code !== void 0 && code !== 0) process.exitCode = code;
|
|
50560
|
-
trackEvent("cli_workflows_action", {
|
|
50561
|
-
action: resolved,
|
|
50562
|
-
non_interactive: !!action,
|
|
50563
|
-
exit_code: code ?? 0
|
|
50564
|
-
});
|
|
50565
|
-
}, "workflows");
|
|
50935
|
+
);
|
|
50566
50936
|
}
|
|
50567
50937
|
__name(workflowsCommand, "workflowsCommand");
|
|
50568
50938
|
async function executeAction(ctx, action, target, extra, o) {
|
|
@@ -50664,18 +51034,12 @@ async function executeAction(ctx, action, target, extra, o) {
|
|
|
50664
51034
|
}
|
|
50665
51035
|
__name(executeAction, "executeAction");
|
|
50666
51036
|
async function requireName(name, verb, fn) {
|
|
50667
|
-
if (!name) {
|
|
50668
|
-
console.error(`\u274C ${verb}: a workflow name is required \u2014 lua workflows ${verb} <name> (or -i <name>)`);
|
|
50669
|
-
return WORKFLOW_EXIT.USAGE;
|
|
50670
|
-
}
|
|
51037
|
+
if (!name) throw CliError.usage(`${verb}: a workflow name is required`, `lua workflows ${verb} <name> (or -i <name>)`);
|
|
50671
51038
|
return fn();
|
|
50672
51039
|
}
|
|
50673
51040
|
__name(requireName, "requireName");
|
|
50674
51041
|
async function requireRun(runId, verb, fn) {
|
|
50675
|
-
if (!runId) {
|
|
50676
|
-
console.error(`\u274C ${verb}: a run id is required \u2014 lua workflows ${verb} <runId> (or -r <runId>)`);
|
|
50677
|
-
return WORKFLOW_EXIT.USAGE;
|
|
50678
|
-
}
|
|
51042
|
+
if (!runId) throw CliError.usage(`${verb}: a run id is required`, `lua workflows ${verb} <runId> (or -r <runId>)`);
|
|
50679
51043
|
return fn();
|
|
50680
51044
|
}
|
|
50681
51045
|
__name(requireRun, "requireRun");
|
|
@@ -50683,46 +51047,80 @@ function emitJson(ctx, res) {
|
|
|
50683
51047
|
if (ctx.json) console.log(JSON.stringify(res, null, 2));
|
|
50684
51048
|
}
|
|
50685
51049
|
__name(emitJson, "emitJson");
|
|
50686
|
-
|
|
50687
|
-
|
|
51050
|
+
var SCHEDULE_PROVISION_FAILED_HINT = "The schedule provider (EventBridge) refused this schedule \u2014 the reason above names what to change; re-run after fixing it. This is not a connectivity problem.";
|
|
51051
|
+
function refusalExitCode(status) {
|
|
51052
|
+
if (status === 0 || status !== void 0 && status >= 500) return WORKFLOW_EXIT.UNAVAILABLE;
|
|
51053
|
+
if (status === 404) return WORKFLOW_EXIT.NOT_FOUND;
|
|
51054
|
+
return WORKFLOW_EXIT.API;
|
|
51055
|
+
}
|
|
51056
|
+
__name(refusalExitCode, "refusalExitCode");
|
|
51057
|
+
function apiRefusal(res, verb, detail = {}) {
|
|
50688
51058
|
const err = res.error;
|
|
50689
51059
|
const status = err?.statusCode;
|
|
50690
51060
|
const code = err?.code ?? err?.error;
|
|
50691
|
-
const
|
|
50692
|
-
|
|
50693
|
-
|
|
51061
|
+
const reason = code === "SCHEDULE_PROVISION_FAILED" ? err?.reason : void 0;
|
|
51062
|
+
const serverMessage = `${err?.message ?? "Unknown error"}${typeof reason === "string" && reason ? `: ${reason}` : ""}`;
|
|
51063
|
+
const message = detail.message ? code ? `${detail.message} (${code})` : detail.message : code ? serverMessage === code ? `${verb} failed (${code})` : `${verb} failed (${code}): ${serverMessage}` : `${verb} failed: ${serverMessage}`;
|
|
51064
|
+
const issues = detail.issues ?? err?.issues;
|
|
51065
|
+
const exitCode = refusalExitCode(status);
|
|
51066
|
+
if (exitCode === WORKFLOW_EXIT.UNAVAILABLE) {
|
|
51067
|
+
return CliError.fromStatus(
|
|
51068
|
+
status,
|
|
51069
|
+
message,
|
|
51070
|
+
status === 503 && code === "CONTROL_UNAVAILABLE" ? CONTROL_UNAVAILABLE_HINT : code === "SCHEDULE_PROVISION_FAILED" ? SCHEDULE_PROVISION_FAILED_HINT : detail.hint,
|
|
51071
|
+
// LUA-810: `fromStatus` picks the UPSTREAM_UNAVAILABLE hint from `upstream` / `requestId` itself.
|
|
51072
|
+
// LUA-812: and the VENDOR_UNAVAILABLE hint from `vendor` / `retryAfterSeconds`.
|
|
51073
|
+
{
|
|
51074
|
+
serverCode: code,
|
|
51075
|
+
issues,
|
|
51076
|
+
upstream: err?.upstream,
|
|
51077
|
+
requestId: err?.requestId,
|
|
51078
|
+
vendor: err?.vendor,
|
|
51079
|
+
retryAfterSeconds: err?.retryAfterSeconds
|
|
51080
|
+
}
|
|
51081
|
+
);
|
|
51082
|
+
}
|
|
51083
|
+
return new CliError(exitCode === WORKFLOW_EXIT.NOT_FOUND ? "not_found" : "error", message, {
|
|
51084
|
+
exitCode,
|
|
51085
|
+
statusCode: status,
|
|
51086
|
+
serverCode: code,
|
|
51087
|
+
issues,
|
|
51088
|
+
hint: detail.hint
|
|
51089
|
+
});
|
|
51090
|
+
}
|
|
51091
|
+
__name(apiRefusal, "apiRefusal");
|
|
51092
|
+
function apiFailure(ctx, res, verb, detail = {}) {
|
|
51093
|
+
if (ctx.json) {
|
|
51094
|
+
emitJson(ctx, res);
|
|
51095
|
+
return refusalExitCode(res.error?.statusCode);
|
|
50694
51096
|
}
|
|
50695
|
-
|
|
50696
|
-
if (status === 404) return WORKFLOW_EXIT.NOT_FOUND;
|
|
50697
|
-
return WORKFLOW_EXIT.API;
|
|
51097
|
+
throw apiRefusal(res, verb, detail);
|
|
50698
51098
|
}
|
|
50699
51099
|
__name(apiFailure, "apiFailure");
|
|
50700
51100
|
async function resolveWorkflow(ctx, nameOrId) {
|
|
50701
|
-
|
|
50702
|
-
return list && pickWorkflow(list, nameOrId);
|
|
51101
|
+
return pickWorkflow(await loadWorkflowList(ctx), nameOrId);
|
|
50703
51102
|
}
|
|
50704
51103
|
__name(resolveWorkflow, "resolveWorkflow");
|
|
50705
51104
|
async function loadWorkflowList(ctx) {
|
|
50706
51105
|
const res = await ctx.api.getWorkflows({
|
|
50707
51106
|
includeDynamic: true
|
|
50708
51107
|
});
|
|
50709
|
-
if (!res.success || !res.data)
|
|
50710
|
-
console.error(`\u274C Failed to list workflows: ${res.error?.message ?? "Unknown error"}`);
|
|
50711
|
-
return void 0;
|
|
50712
|
-
}
|
|
51108
|
+
if (!res.success || !res.data) throw apiRefusal(res, "list");
|
|
50713
51109
|
return res.data.workflows;
|
|
50714
51110
|
}
|
|
50715
51111
|
__name(loadWorkflowList, "loadWorkflowList");
|
|
50716
51112
|
function pickWorkflow(list, nameOrId) {
|
|
50717
51113
|
const wf = list.find((w) => w.name === nameOrId) ?? list.find((w) => w.id === nameOrId);
|
|
50718
51114
|
if (!wf) {
|
|
50719
|
-
|
|
50720
|
-
const names = list.map((w) => w.name);
|
|
50721
|
-
if (names.length) console.log(` Available: ${names.join(", ")}`);
|
|
51115
|
+
throw CliError.notFound(`Workflow "${nameOrId}" not found`, listHint("Available:", list.map((w) => w.name)));
|
|
50722
51116
|
}
|
|
50723
51117
|
return wf;
|
|
50724
51118
|
}
|
|
50725
51119
|
__name(pickWorkflow, "pickWorkflow");
|
|
51120
|
+
function isDefinitionId(nameOrId) {
|
|
51121
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(nameOrId);
|
|
51122
|
+
}
|
|
51123
|
+
__name(isDefinitionId, "isDefinitionId");
|
|
50726
51124
|
var shortHash = /* @__PURE__ */ __name((h) => h ? h.replace(/^sha256-cj1:/, "").slice(0, 12) : "\u2014", "shortHash");
|
|
50727
51125
|
var when = /* @__PURE__ */ __name((iso) => iso ? new Date(iso).toLocaleString() : "\u2014", "when");
|
|
50728
51126
|
var clockOf = /* @__PURE__ */ __name((at) => {
|
|
@@ -50735,6 +51133,15 @@ var parseIntFlag = /* @__PURE__ */ __name((v, flag) => {
|
|
|
50735
51133
|
if (!Number.isFinite(n2)) throw new WorkflowLocalUsageError("usage", `${flag}: expected a number (got "${v}")`);
|
|
50736
51134
|
return n2;
|
|
50737
51135
|
}, "parseIntFlag");
|
|
51136
|
+
function parsedOrUsage(parse) {
|
|
51137
|
+
try {
|
|
51138
|
+
return parse();
|
|
51139
|
+
} catch (e) {
|
|
51140
|
+
if (e instanceof WorkflowLocalUsageError) throw CliError.usage(e.message);
|
|
51141
|
+
throw e;
|
|
51142
|
+
}
|
|
51143
|
+
}
|
|
51144
|
+
__name(parsedOrUsage, "parsedOrUsage");
|
|
50738
51145
|
async function listCore(ctx, opts) {
|
|
50739
51146
|
const res = await ctx.api.getWorkflows({
|
|
50740
51147
|
includeDynamic: opts.all
|
|
@@ -50921,35 +51328,22 @@ function startResultLine(d, requestedName) {
|
|
|
50921
51328
|
}
|
|
50922
51329
|
__name(startResultLine, "startResultLine");
|
|
50923
51330
|
async function startCore(ctx, name, o) {
|
|
50924
|
-
const
|
|
50925
|
-
|
|
50926
|
-
|
|
50927
|
-
|
|
50928
|
-
|
|
50929
|
-
try {
|
|
50930
|
-
if (o.input) input = parseJsonOrFile(o.input, "--input");
|
|
50931
|
-
waitSeconds = parseIntFlag(o.wait, "--wait");
|
|
50932
|
-
budgetCredits = parseIntegerFlag(o.budgetCredits, "--budget-credits", {
|
|
50933
|
-
min: 1
|
|
50934
|
-
});
|
|
50935
|
-
} catch (e) {
|
|
50936
|
-
if (e instanceof WorkflowLocalUsageError) {
|
|
50937
|
-
console.error(`\u274C ${e.message}`);
|
|
50938
|
-
return WORKFLOW_EXIT.USAGE;
|
|
50939
|
-
}
|
|
50940
|
-
throw e;
|
|
50941
|
-
}
|
|
51331
|
+
const input = parsedOrUsage(() => o.input ? parseJsonOrFile(o.input, "--input") : {});
|
|
51332
|
+
const waitSeconds = parsedOrUsage(() => parseIntFlag(o.wait, "--wait"));
|
|
51333
|
+
const budgetCredits = parsedOrUsage(() => parseIntegerFlag(o.budgetCredits, "--budget-credits", {
|
|
51334
|
+
min: 1
|
|
51335
|
+
}));
|
|
50942
51336
|
if (waitSeconds !== void 0 && (waitSeconds < 0 || waitSeconds > 55)) {
|
|
50943
|
-
|
|
50944
|
-
return WORKFLOW_EXIT.USAGE;
|
|
51337
|
+
throw CliError.usage("--wait must be 0..55 (a server long-poll; the CLI raises its own deadline to wait+10 s)");
|
|
50945
51338
|
}
|
|
50946
51339
|
const tags = o.tag === void 0 ? void 0 : Array.isArray(o.tag) ? o.tag : [
|
|
50947
51340
|
o.tag
|
|
50948
51341
|
];
|
|
50949
|
-
if (tags && tags.length > 10)
|
|
50950
|
-
|
|
50951
|
-
|
|
50952
|
-
|
|
51342
|
+
if (tags && tags.length > 10) throw CliError.usage("--tag: at most 10 tags");
|
|
51343
|
+
const wf = isDefinitionId(name) ? {
|
|
51344
|
+
id: name,
|
|
51345
|
+
name
|
|
51346
|
+
} : await resolveWorkflow(ctx, name);
|
|
50953
51347
|
let workflowVersionId;
|
|
50954
51348
|
if (o.workflowVersion) {
|
|
50955
51349
|
const ref = await resolveVersionRef(ctx, wf, o.workflowVersion, "start");
|
|
@@ -51021,8 +51415,7 @@ async function runsCore(ctx, o) {
|
|
|
51021
51415
|
try {
|
|
51022
51416
|
limit = parseIntFlag(o.limit, "--limit");
|
|
51023
51417
|
} catch (e) {
|
|
51024
|
-
|
|
51025
|
-
return WORKFLOW_EXIT.USAGE;
|
|
51418
|
+
throw CliError.usage(`${e.message}`);
|
|
51026
51419
|
}
|
|
51027
51420
|
const res = await ctx.api.getRuns({
|
|
51028
51421
|
workflowId,
|
|
@@ -51160,6 +51553,8 @@ function printRun(run, withSteps) {
|
|
|
51160
51553
|
console.log(`
|
|
51161
51554
|
\u23F8\uFE0F Paused \u2014 run budget reached (${budgetCopy(run)}):`);
|
|
51162
51555
|
console.log(` lua workflows raise-budget ${id} --credits <n>`);
|
|
51556
|
+
} else if (kind === "billing") {
|
|
51557
|
+
for (const line of billingParkLines(run)) console.log(line);
|
|
51163
51558
|
} else {
|
|
51164
51559
|
console.log(` Gate: ${kind}${run.gate.reason ? ` (${run.gate.reason})` : ""}${run.gate.since ? ` since ${when(run.gate.since)}` : ""}`);
|
|
51165
51560
|
}
|
|
@@ -51208,6 +51603,23 @@ function printRun(run, withSteps) {
|
|
|
51208
51603
|
}
|
|
51209
51604
|
}
|
|
51210
51605
|
__name(printRun, "printRun");
|
|
51606
|
+
function billingParkLines(run) {
|
|
51607
|
+
const id = runIdOf(run);
|
|
51608
|
+
const gate = run.gate ?? {
|
|
51609
|
+
kind: "billing"
|
|
51610
|
+
};
|
|
51611
|
+
const what = gate.code === "out_of_actions" ? "the workspace is out of actions" : "the workspace has no credits left";
|
|
51612
|
+
const step3 = gate.stepId ? ` before step ${gate.stepId}` : "";
|
|
51613
|
+
const out = [
|
|
51614
|
+
`
|
|
51615
|
+
\u23F8\uFE0F Paused \u2014 payment required (${what})${step3}:`
|
|
51616
|
+
];
|
|
51617
|
+
out.push(" top up the workspace (or ask a workspace admin to) \u2014 the run resumes on its own within a few minutes of the top-up");
|
|
51618
|
+
out.push(` to resume it right away after topping up: lua workflows retry-step ${id} --step ${gate.stepId ?? "<stepId>"}`);
|
|
51619
|
+
if (typeof gate.expiresAt === "number") out.push(` still unpaid at ${when(gate.expiresAt)} \u21D2 the run fails`);
|
|
51620
|
+
return out;
|
|
51621
|
+
}
|
|
51622
|
+
__name(billingParkLines, "billingParkLines");
|
|
51211
51623
|
function stepAttemptLines(s) {
|
|
51212
51624
|
const out = [];
|
|
51213
51625
|
const cause = stepFailureLine(s.error);
|
|
@@ -51315,15 +51727,8 @@ function attemptCountersLine(c) {
|
|
|
51315
51727
|
}
|
|
51316
51728
|
__name(attemptCountersLine, "attemptCountersLine");
|
|
51317
51729
|
async function watchCore(ctx, runId, o) {
|
|
51318
|
-
|
|
51319
|
-
|
|
51320
|
-
try {
|
|
51321
|
-
afterSeq = parseIntFlag(o.after, "--after");
|
|
51322
|
-
timeoutS = parseIntFlag(o.timeout, "--timeout");
|
|
51323
|
-
} catch (e) {
|
|
51324
|
-
console.error(`\u274C ${e.message}`);
|
|
51325
|
-
return WORKFLOW_EXIT.USAGE;
|
|
51326
|
-
}
|
|
51730
|
+
const afterSeq = parsedOrUsage(() => parseIntFlag(o.after, "--after"));
|
|
51731
|
+
const timeoutS = parsedOrUsage(() => parseIntFlag(o.timeout, "--timeout"));
|
|
51327
51732
|
const controller = new AbortController();
|
|
51328
51733
|
let timedOut = false;
|
|
51329
51734
|
const timer = timeoutS ? setTimeout(() => (timedOut = true, controller.abort()), timeoutS * 1e3) : void 0;
|
|
@@ -51332,7 +51737,7 @@ async function watchCore(ctx, runId, o) {
|
|
|
51332
51737
|
let lastEventId = afterSeq !== void 0 ? String(afterSeq) : void 0;
|
|
51333
51738
|
let exit;
|
|
51334
51739
|
let reconnects = 0;
|
|
51335
|
-
const
|
|
51740
|
+
const state3 = createWatchState();
|
|
51336
51741
|
try {
|
|
51337
51742
|
while (exit === void 0 && !controller.signal.aborted) {
|
|
51338
51743
|
const res = await ctx.api.watchEvents(runId, {
|
|
@@ -51347,7 +51752,7 @@ async function watchCore(ctx, runId, o) {
|
|
|
51347
51752
|
let sawEnd = false;
|
|
51348
51753
|
for await (const frame of res.data) {
|
|
51349
51754
|
if (frame.id !== void 0) lastEventId = frame.id;
|
|
51350
|
-
const verdict = handleWatchFrame(ctx, runId, frame, o,
|
|
51755
|
+
const verdict = await handleWatchFrame(ctx, runId, frame, o, state3);
|
|
51351
51756
|
if (verdict === "reconnect") break;
|
|
51352
51757
|
if (typeof verdict === "number") {
|
|
51353
51758
|
exit = verdict;
|
|
@@ -51357,10 +51762,10 @@ async function watchCore(ctx, runId, o) {
|
|
|
51357
51762
|
}
|
|
51358
51763
|
if (exit !== void 0 || controller.signal.aborted || sawEnd) break;
|
|
51359
51764
|
reconnects += 1;
|
|
51360
|
-
|
|
51361
|
-
|
|
51362
|
-
|
|
51363
|
-
}
|
|
51765
|
+
resetWatchReplay(state3);
|
|
51766
|
+
if (reconnects > 20) throw new CliError("error", "watch: too many reconnects", {
|
|
51767
|
+
exitCode: WORKFLOW_EXIT.API
|
|
51768
|
+
});
|
|
51364
51769
|
if (!ctx.json) console.error(`\u2026 reconnecting (Last-Event-ID ${lastEventId ?? "none"})`);
|
|
51365
51770
|
await new Promise((r) => setTimeout(r, Math.min(5e3, 250 * 2 ** reconnects)));
|
|
51366
51771
|
}
|
|
@@ -51385,7 +51790,55 @@ function throttledLine(throttled) {
|
|
|
51385
51790
|
].map(([k, n2]) => `${k} \xD7${n2}`).join(" \xB7 ")}`;
|
|
51386
51791
|
}
|
|
51387
51792
|
__name(throttledLine, "throttledLine");
|
|
51388
|
-
function
|
|
51793
|
+
function createWatchState() {
|
|
51794
|
+
return {
|
|
51795
|
+
throttled: /* @__PURE__ */ new Map(),
|
|
51796
|
+
signalNames: /* @__PURE__ */ new Map()
|
|
51797
|
+
};
|
|
51798
|
+
}
|
|
51799
|
+
__name(createWatchState, "createWatchState");
|
|
51800
|
+
function resetWatchReplay(state3) {
|
|
51801
|
+
state3.truth = void 0;
|
|
51802
|
+
state3.pending = void 0;
|
|
51803
|
+
}
|
|
51804
|
+
__name(resetWatchReplay, "resetWatchReplay");
|
|
51805
|
+
async function readWatchTruth(ctx, runId) {
|
|
51806
|
+
try {
|
|
51807
|
+
const res = await ctx.api.getRun(runId);
|
|
51808
|
+
if (!res?.success || !res.data) return null;
|
|
51809
|
+
const run = res.data;
|
|
51810
|
+
return {
|
|
51811
|
+
parked: run.status === "suspended" || run.status === "gated",
|
|
51812
|
+
watermark: typeof run.eventSeq === "number" && Number.isFinite(run.eventSeq) ? run.eventSeq : void 0
|
|
51813
|
+
};
|
|
51814
|
+
} catch {
|
|
51815
|
+
return null;
|
|
51816
|
+
}
|
|
51817
|
+
}
|
|
51818
|
+
__name(readWatchTruth, "readWatchTruth");
|
|
51819
|
+
function frameSeq(frame, ev) {
|
|
51820
|
+
const fromId = frame.id === void 0 ? NaN : Number(frame.id);
|
|
51821
|
+
if (Number.isFinite(fromId)) return fromId;
|
|
51822
|
+
return typeof ev.seq === "number" ? ev.seq : void 0;
|
|
51823
|
+
}
|
|
51824
|
+
__name(frameSeq, "frameSeq");
|
|
51825
|
+
async function watchBoundary(ctx, runId, state3, seq, line, code, emit2) {
|
|
51826
|
+
if (state3.truth === void 0 || state3.truth !== null && state3.truth.watermark === void 0) {
|
|
51827
|
+
state3.truth = await readWatchTruth(ctx, runId);
|
|
51828
|
+
}
|
|
51829
|
+
const truth = state3.truth;
|
|
51830
|
+
if (truth === null) return emit2(line, code);
|
|
51831
|
+
if (truth.watermark === void 0 || seq === void 0) return truth.parked ? emit2(line, code) : void 0;
|
|
51832
|
+
if (seq > truth.watermark) return emit2(line, code);
|
|
51833
|
+
if (!truth.parked) return void 0;
|
|
51834
|
+
state3.pending = {
|
|
51835
|
+
line,
|
|
51836
|
+
code
|
|
51837
|
+
};
|
|
51838
|
+
return void 0;
|
|
51839
|
+
}
|
|
51840
|
+
__name(watchBoundary, "watchBoundary");
|
|
51841
|
+
async function handleWatchFrame(ctx, runId, frame, o, state3) {
|
|
51389
51842
|
const data = frame.data ?? {};
|
|
51390
51843
|
if (o.events || ctx.json) console.log(JSON.stringify({
|
|
51391
51844
|
id: frame.id,
|
|
@@ -51398,10 +51851,17 @@ function handleWatchFrame(ctx, runId, frame, o, throttled) {
|
|
|
51398
51851
|
if (!ctx.json) console.error(" --wait-for-human: still following \u2014 Ctrl+C or --timeout to stop");
|
|
51399
51852
|
return void 0;
|
|
51400
51853
|
}, "humanBoundary");
|
|
51854
|
+
const flushPending = /* @__PURE__ */ __name(() => {
|
|
51855
|
+
const pending = state3.pending;
|
|
51856
|
+
if (!pending) return void 0;
|
|
51857
|
+
state3.pending = void 0;
|
|
51858
|
+
return humanBoundary(pending.line, pending.code);
|
|
51859
|
+
}, "flushPending");
|
|
51401
51860
|
switch (frame.event) {
|
|
51402
51861
|
case "heartbeat":
|
|
51403
|
-
return
|
|
51862
|
+
return flushPending();
|
|
51404
51863
|
case "reconnect":
|
|
51864
|
+
resetWatchReplay(state3);
|
|
51405
51865
|
return "reconnect";
|
|
51406
51866
|
case "error": {
|
|
51407
51867
|
const code = String(data.code ?? "unknown");
|
|
@@ -51418,10 +51878,15 @@ function handleWatchFrame(ctx, runId, frame, o, throttled) {
|
|
|
51418
51878
|
const type = frame.event || ev.type;
|
|
51419
51879
|
if (type === "step.throttled") {
|
|
51420
51880
|
const kind = String(ev.data?.kind ?? "throttled");
|
|
51421
|
-
throttled.set(kind, (throttled.get(kind) ?? 0) + 1);
|
|
51422
|
-
if (!ctx.json && !o.events) process.stdout.write(`\r ${throttledLine(throttled)}`);
|
|
51881
|
+
state3.throttled.set(kind, (state3.throttled.get(kind) ?? 0) + 1);
|
|
51882
|
+
if (!ctx.json && !o.events) process.stdout.write(`\r ${throttledLine(state3.throttled)}`);
|
|
51423
51883
|
return void 0;
|
|
51424
51884
|
}
|
|
51885
|
+
if (type === "step.suspended") {
|
|
51886
|
+
const d = ev.data;
|
|
51887
|
+
const stepId = ev.stepId ?? (typeof d?.stepId === "string" ? d.stepId : void 0);
|
|
51888
|
+
if (stepId && typeof d?.signalName === "string") state3.signalNames.set(stepId, d.signalName);
|
|
51889
|
+
}
|
|
51425
51890
|
if (!ctx.json && !o.events) {
|
|
51426
51891
|
const at = clockOf(ev.ts);
|
|
51427
51892
|
const subrun = subrunEventDetail({
|
|
@@ -51431,39 +51896,58 @@ function handleWatchFrame(ctx, runId, frame, o, throttled) {
|
|
|
51431
51896
|
const detail = subrun ? ` \xB7 ${subrun}` : ev.data ? ` ${JSON.stringify(scrubEventData(ev.data)).slice(0, 160)}` : "";
|
|
51432
51897
|
console.log(`[${at}] ${type}${ev.stepId ? ` \xB7 ${ev.stepId}` : ""}${detail}`);
|
|
51433
51898
|
}
|
|
51434
|
-
if (type === "run.
|
|
51435
|
-
|
|
51436
|
-
|
|
51437
|
-
|
|
51438
|
-
|
|
51439
|
-
|
|
51440
|
-
|
|
51441
|
-
|
|
51442
|
-
|
|
51443
|
-
|
|
51444
|
-
return humanBoundary(`\u23F8\uFE0F run budget reached \u2014 lua workflows raise-budget ${runId} --credits <n> (lua workflows status ${runId} says what a credit buys)`, WORKFLOW_EXIT.RUN_PARKED);
|
|
51445
|
-
}
|
|
51446
|
-
return humanBoundary(`\u23F8\uFE0F run gated (${gate ?? "consent"}) \u2014 approve it from the desktop; then: lua workflows watch ${runId}`, WORKFLOW_EXIT.RUN_GATED);
|
|
51447
|
-
}
|
|
51448
|
-
if (type === "run.suspended") {
|
|
51449
|
-
const kind = ev.data?.kind;
|
|
51450
|
-
const stepId = ev.data?.stepId ?? ev.stepId;
|
|
51451
|
-
if (kind === "approval" || kind === "input" || kind === "signal") {
|
|
51452
|
-
const verb = kind === "approval" ? `lua workflows approve ${runId} --approval <id> --decision approve|deny` : kind === "input" ? `lua workflows resume ${runId} --step ${stepId ?? "<stepId>"} --data <json>` : `lua workflows signal ${runId} <name> --payload <json>`;
|
|
51453
|
-
return humanBoundary(`\u23F8\uFE0F run waits for a person (${kind}${stepId ? ` \xB7 ${stepId}` : ""}) \u2014 ${verb}; then: lua workflows watch ${runId}`, WORKFLOW_EXIT.RUN_PARKED);
|
|
51454
|
-
}
|
|
51455
|
-
}
|
|
51456
|
-
if (type === "run.budget_parked") {
|
|
51457
|
-
return humanBoundary(`\u23F8\uFE0F run budget reached \u2014 lua workflows raise-budget ${runId} --credits <n> (lua workflows status ${runId} says what a credit buys)`, WORKFLOW_EXIT.RUN_PARKED);
|
|
51458
|
-
}
|
|
51459
|
-
if (type === "run.completed") return WORKFLOW_EXIT.OK;
|
|
51460
|
-
if (type === "run.failed" || type === "run.timed_out") return WORKFLOW_EXIT.RUN_FAILED;
|
|
51461
|
-
if (type === "run.cancelled" || type === "run.abandoned") return WORKFLOW_EXIT.RUN_CANCELLED;
|
|
51899
|
+
if (type === "run.resumed") state3.pending = void 0;
|
|
51900
|
+
const seq = frameSeq(frame, ev);
|
|
51901
|
+
const boundary = /* @__PURE__ */ __name((line, code) => watchBoundary(ctx, runId, state3, seq, line, code, humanBoundary), "boundary");
|
|
51902
|
+
const verdict = await boundaryVerdict(runId, {
|
|
51903
|
+
...ev,
|
|
51904
|
+
type
|
|
51905
|
+
}, state3, boundary);
|
|
51906
|
+
if (verdict !== void 0) return verdict;
|
|
51907
|
+
const watermark = state3.truth?.watermark;
|
|
51908
|
+
if (watermark !== void 0 && seq !== void 0 && seq >= watermark) return flushPending();
|
|
51462
51909
|
return void 0;
|
|
51463
51910
|
}
|
|
51464
51911
|
}
|
|
51465
51912
|
}
|
|
51466
51913
|
__name(handleWatchFrame, "handleWatchFrame");
|
|
51914
|
+
async function boundaryVerdict(runId, ev, state3, boundary) {
|
|
51915
|
+
const type = ev.type;
|
|
51916
|
+
if (type === "run.gated") {
|
|
51917
|
+
const gate = ev.data?.gate;
|
|
51918
|
+
const stepId = ev.data?.stepId;
|
|
51919
|
+
if (gate === "exception") {
|
|
51920
|
+
return boundary(`\u26A0\uFE0F run parked on an exception gate \u2014 a human decides next: lua workflows status ${runId}`, WORKFLOW_EXIT.RUN_PARKED);
|
|
51921
|
+
}
|
|
51922
|
+
if (gate === "billing") {
|
|
51923
|
+
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);
|
|
51924
|
+
}
|
|
51925
|
+
if (gate === "budget") {
|
|
51926
|
+
return boundary(`\u23F8\uFE0F run budget reached \u2014 lua workflows raise-budget ${runId} --credits <n> (lua workflows status ${runId} says what a credit buys)`, WORKFLOW_EXIT.RUN_PARKED);
|
|
51927
|
+
}
|
|
51928
|
+
return boundary(`\u23F8\uFE0F run gated (${gate ?? "consent"}) \u2014 approve it from the desktop; then: lua workflows watch ${runId}`, WORKFLOW_EXIT.RUN_GATED);
|
|
51929
|
+
}
|
|
51930
|
+
if (type === "run.suspended") {
|
|
51931
|
+
const kind = ev.data?.kind;
|
|
51932
|
+
const stepId = ev.data?.stepId ?? ev.stepId;
|
|
51933
|
+
if (kind === "billing") {
|
|
51934
|
+
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);
|
|
51935
|
+
}
|
|
51936
|
+
if (kind === "approval" || kind === "input" || kind === "signal") {
|
|
51937
|
+
const signalName = stepId ? state3.signalNames.get(stepId) : void 0;
|
|
51938
|
+
const verb = kind === "approval" ? `lua workflows approve ${runId} --approval <id> --decision approve|deny` : kind === "input" ? `lua workflows resume ${runId} --step ${stepId ?? "<stepId>"} --data <json>` : `lua workflows signal ${runId} ${signalName ?? "<name>"} --payload <json>`;
|
|
51939
|
+
return boundary(`\u23F8\uFE0F run waits for a person (${kind}${stepId ? ` \xB7 ${stepId}` : ""}) \u2014 ${verb}; then: lua workflows watch ${runId}`, WORKFLOW_EXIT.RUN_PARKED);
|
|
51940
|
+
}
|
|
51941
|
+
}
|
|
51942
|
+
if (type === "run.budget_parked") {
|
|
51943
|
+
return boundary(`\u23F8\uFE0F run budget reached \u2014 lua workflows raise-budget ${runId} --credits <n> (lua workflows status ${runId} says what a credit buys)`, WORKFLOW_EXIT.RUN_PARKED);
|
|
51944
|
+
}
|
|
51945
|
+
if (type === "run.completed") return WORKFLOW_EXIT.OK;
|
|
51946
|
+
if (type === "run.failed" || type === "run.timed_out") return WORKFLOW_EXIT.RUN_FAILED;
|
|
51947
|
+
if (type === "run.cancelled" || type === "run.abandoned") return WORKFLOW_EXIT.RUN_CANCELLED;
|
|
51948
|
+
return void 0;
|
|
51949
|
+
}
|
|
51950
|
+
__name(boundaryVerdict, "boundaryVerdict");
|
|
51467
51951
|
async function cancelCore(ctx, runId, o) {
|
|
51468
51952
|
const res = await ctx.api.cancelRun(runId, {
|
|
51469
51953
|
mode: o.force ? "force" : "request",
|
|
@@ -51486,45 +51970,48 @@ async function cancelCore(ctx, runId, o) {
|
|
|
51486
51970
|
}
|
|
51487
51971
|
__name(cancelCore, "cancelCore");
|
|
51488
51972
|
async function resumeCore(ctx, runId, o) {
|
|
51489
|
-
if (!o.step)
|
|
51490
|
-
|
|
51491
|
-
return WORKFLOW_EXIT.USAGE;
|
|
51492
|
-
}
|
|
51493
|
-
let resumeData = {};
|
|
51494
|
-
try {
|
|
51495
|
-
if (o.data) resumeData = parseJsonOrFile(o.data, "--data");
|
|
51496
|
-
} catch (e) {
|
|
51497
|
-
console.error(`\u274C ${e.message}`);
|
|
51498
|
-
return WORKFLOW_EXIT.USAGE;
|
|
51499
|
-
}
|
|
51973
|
+
if (!o.step) throw CliError.usage("resume: --step <id> is required");
|
|
51974
|
+
const resumeData = parsedOrUsage(() => o.data ? parseJsonOrFile(o.data, "--data") : {});
|
|
51500
51975
|
const res = await ctx.api.resumeRun(runId, o.step, {
|
|
51501
51976
|
resumeData
|
|
51502
51977
|
});
|
|
51503
|
-
const resumeCode = !res.success ? res.error?.code ?? res.error?.error : void 0;
|
|
51504
|
-
const resumeDetail = res.error;
|
|
51505
|
-
if (!ctx.json && res.error?.statusCode === 400 && resumeCode === "RESUME_SCHEMA_INVALID") {
|
|
51506
|
-
console.error(`\u274C resume rejected \u2014 --data does not match the resumeSchema step "${resumeDetail?.stepId ?? o.step}" declares:`);
|
|
51507
|
-
for (const issue of resumeDetail?.issues ?? []) console.error(` \u2022 ${issue.path || "/"}: ${issue.message ?? "invalid"}`);
|
|
51508
|
-
console.error(" fix the data and resume again (the step is still waiting for input)");
|
|
51509
|
-
} else if (!ctx.json && res.error?.statusCode === 422 && resumeCode === "RESUME_SCHEMA_UNCOMPILABLE") {
|
|
51510
|
-
console.error(`\u274C resume could not be checked \u2014 the resumeSchema step "${resumeDetail?.stepId ?? o.step}" declares does not compile:`);
|
|
51511
|
-
for (const issue of resumeDetail?.issues ?? []) console.error(` \u2022 ${issue.message ?? "schema does not compile"}`);
|
|
51512
|
-
console.error(" this is a workflow definition defect, not a data problem \u2014 fix the `resumeSchema` on the step in the workflow source, push a new version, then resume again");
|
|
51513
|
-
}
|
|
51514
51978
|
if (!res.success || !res.data) {
|
|
51515
51979
|
const code = res.error?.code ?? res.error?.error;
|
|
51516
|
-
|
|
51517
|
-
|
|
51518
|
-
|
|
51519
|
-
|
|
51520
|
-
|
|
51521
|
-
|
|
51522
|
-
|
|
51523
|
-
|
|
51524
|
-
|
|
51525
|
-
|
|
51980
|
+
const status = res.error?.statusCode;
|
|
51981
|
+
const stepOf3 = res.error?.stepId ?? o.step;
|
|
51982
|
+
let detail = {};
|
|
51983
|
+
if (status === 400 && code === "RESUME_SCHEMA_INVALID") {
|
|
51984
|
+
detail = {
|
|
51985
|
+
message: `resume rejected \u2014 --data does not match the resumeSchema step "${stepOf3}" declares`,
|
|
51986
|
+
issues: res.error?.issues,
|
|
51987
|
+
hint: "fix the data and resume again (the step is still waiting for input)"
|
|
51988
|
+
};
|
|
51989
|
+
} else if (status === 422 && code === "RESUME_SCHEMA_UNCOMPILABLE") {
|
|
51990
|
+
detail = {
|
|
51991
|
+
message: `resume could not be checked \u2014 the resumeSchema step "${stepOf3}" declares does not compile`,
|
|
51992
|
+
issues: (res.error?.issues ?? []).map((issue) => ({
|
|
51993
|
+
message: issue.message ?? "schema does not compile"
|
|
51994
|
+
})),
|
|
51995
|
+
hint: "this is a workflow definition defect, not a data problem \u2014 fix the `resumeSchema` on the step in the workflow source, push a new version, then resume again"
|
|
51996
|
+
};
|
|
51997
|
+
} else if (status === 404 && code === "STEP_NOT_FOUND") {
|
|
51998
|
+
detail = {
|
|
51999
|
+
message: `step "${o.step}" does not exist on run ${runId} \u2014 list its steps: lua workflows status ${runId} --steps`
|
|
52000
|
+
};
|
|
52001
|
+
} else if (status === 409 && (code === "approval_requires_human" || code === "APPROVAL_REQUIRES_HUMAN")) {
|
|
52002
|
+
detail = {
|
|
52003
|
+
message: `step "${o.step}" is an approval \u2014 resolve it with: lua workflows approve ${runId} --approval ${o.step} --decision approve`
|
|
52004
|
+
};
|
|
52005
|
+
} else if (status === 409 && (code === "use_signal_route" || code === "USE_SIGNAL_ROUTE")) {
|
|
52006
|
+
detail = {
|
|
52007
|
+
message: `step "${o.step}" waits for a signal \u2014 deliver it with: lua workflows signal ${runId} <name> --payload '{}'`
|
|
52008
|
+
};
|
|
52009
|
+
} else if (status === 409 && code === "NOT_SUSPENDED") {
|
|
52010
|
+
detail = {
|
|
52011
|
+
message: `step "${o.step}" is not suspended${res.error?.status ? ` (it is ${res.error.status})` : ""} \u2014 nothing to resume: lua workflows status ${runId} --steps`
|
|
52012
|
+
};
|
|
51526
52013
|
}
|
|
51527
|
-
return apiFailure(ctx, res, "resume");
|
|
52014
|
+
return apiFailure(ctx, res, "resume", detail);
|
|
51528
52015
|
}
|
|
51529
52016
|
emitJson(ctx, res);
|
|
51530
52017
|
if (!ctx.json) {
|
|
@@ -51539,8 +52026,7 @@ async function resumeCore(ctx, runId, o) {
|
|
|
51539
52026
|
__name(resumeCore, "resumeCore");
|
|
51540
52027
|
async function retryStepCore(ctx, runId, o) {
|
|
51541
52028
|
if (!o.step) {
|
|
51542
|
-
|
|
51543
|
-
return WORKFLOW_EXIT.USAGE;
|
|
52029
|
+
throw CliError.usage("--step <id> is required: lua workflows retry-step <runId> --step <id> [--note <text>]");
|
|
51544
52030
|
}
|
|
51545
52031
|
const res = await ctx.api.retryStep(runId, o.step, {
|
|
51546
52032
|
...o.note ? {
|
|
@@ -51548,21 +52034,30 @@ async function retryStepCore(ctx, runId, o) {
|
|
|
51548
52034
|
} : {}
|
|
51549
52035
|
});
|
|
51550
52036
|
if (!res.success || !res.data) {
|
|
52037
|
+
let detail = {};
|
|
51551
52038
|
const code = res.error?.code ?? res.error?.error;
|
|
51552
|
-
if (
|
|
51553
|
-
|
|
51554
|
-
|
|
51555
|
-
|
|
51556
|
-
|
|
52039
|
+
if (res.error?.statusCode === 404 && code === "STEP_NOT_FOUND") {
|
|
52040
|
+
detail = {
|
|
52041
|
+
message: `step "${o.step}" does not exist on run ${runId} \u2014 list its steps: lua workflows status ${runId} --steps`
|
|
52042
|
+
};
|
|
52043
|
+
} else if (res.error?.statusCode === 409) {
|
|
52044
|
+
if (code === "STEP_NOT_PARKED" || code === "step_not_parked") detail = {
|
|
52045
|
+
message: `step "${o.step}" is not parked (running, pending or already re-armed) \u2014 nothing to retry`
|
|
52046
|
+
};
|
|
52047
|
+
else if (code === "RUN_TERMINAL" || code === "run_terminal") detail = {
|
|
52048
|
+
message: `run ${runId} is terminal \u2014 start a new run instead`
|
|
52049
|
+
};
|
|
51557
52050
|
else if (code === "STEP_RETRY_CAP" || code === "step_retry_cap") {
|
|
51558
52051
|
const cap = res.error;
|
|
51559
52052
|
const at = typeof cap?.attempt === "number" && typeof cap?.maxAttempts === "number" ? ` (attempt ${cap.attempt} of ${cap.maxAttempts})` : "";
|
|
51560
|
-
|
|
51561
|
-
|
|
51562
|
-
|
|
52053
|
+
detail = {
|
|
52054
|
+
message: `step "${o.step}" has reached the retry cap${at} \u2014 resolve it or repair the run`,
|
|
52055
|
+
hint: `lua workflows resolve-step ${runId} --step ${o.step} --outcome skip|complete|fail
|
|
52056
|
+
to start a repair run instead, decide it from the desktop run page`
|
|
52057
|
+
};
|
|
51563
52058
|
}
|
|
51564
52059
|
}
|
|
51565
|
-
return apiFailure(ctx, res, "retry-step");
|
|
52060
|
+
return apiFailure(ctx, res, "retry-step", detail);
|
|
51566
52061
|
}
|
|
51567
52062
|
emitJson(ctx, res);
|
|
51568
52063
|
if (!ctx.json) {
|
|
@@ -51585,29 +52080,24 @@ __name(refusalIssues, "refusalIssues");
|
|
|
51585
52080
|
async function resolveStepCore(ctx, runId, o) {
|
|
51586
52081
|
const usage = "lua workflows resolve-step <runId> --step <id> --outcome skip|complete|fail [--output <json|@file>] [--note <text>]";
|
|
51587
52082
|
if (!o.step) {
|
|
51588
|
-
|
|
51589
|
-
return WORKFLOW_EXIT.USAGE;
|
|
52083
|
+
throw CliError.usage(`--step <id> is required: ${usage}`);
|
|
51590
52084
|
}
|
|
51591
52085
|
const raw = (o.outcome ?? o.action)?.trim().toLowerCase();
|
|
51592
52086
|
if (raw !== "skip" && raw !== "complete" && raw !== "fail") {
|
|
51593
|
-
|
|
51594
|
-
return WORKFLOW_EXIT.USAGE;
|
|
52087
|
+
throw CliError.usage(`--outcome must be skip|complete|fail${raw ? ` (got "${raw}")` : ""}: ${usage}`);
|
|
51595
52088
|
}
|
|
51596
52089
|
const outcome = raw;
|
|
51597
52090
|
let output;
|
|
51598
52091
|
try {
|
|
51599
52092
|
if (o.output !== void 0) output = parseJsonOrFile(o.output, "--output");
|
|
51600
52093
|
} catch (e) {
|
|
51601
|
-
|
|
51602
|
-
return WORKFLOW_EXIT.USAGE;
|
|
52094
|
+
throw CliError.usage(`${e.message}`);
|
|
51603
52095
|
}
|
|
51604
52096
|
if (outcome === "complete" && output === void 0) {
|
|
51605
|
-
|
|
51606
|
-
return WORKFLOW_EXIT.USAGE;
|
|
52097
|
+
throw CliError.usage(`--outcome complete needs --output <json|@file> (the output the step would have produced): ${usage}`);
|
|
51607
52098
|
}
|
|
51608
52099
|
if (outcome !== "complete" && output !== void 0) {
|
|
51609
|
-
|
|
51610
|
-
return WORKFLOW_EXIT.USAGE;
|
|
52100
|
+
throw CliError.usage(`--output rides with --outcome complete only (a ${outcome} carries no output)`);
|
|
51611
52101
|
}
|
|
51612
52102
|
const dto = {
|
|
51613
52103
|
outcome,
|
|
@@ -51620,27 +52110,43 @@ async function resolveStepCore(ctx, runId, o) {
|
|
|
51620
52110
|
};
|
|
51621
52111
|
const res = await ctx.api.resolveStep(runId, o.step, dto);
|
|
51622
52112
|
if (!res.success || !res.data) {
|
|
52113
|
+
let detail = {};
|
|
51623
52114
|
const err = res.error;
|
|
51624
52115
|
const code = err?.code ?? err?.error;
|
|
51625
52116
|
const status = err?.statusCode;
|
|
51626
|
-
if (
|
|
52117
|
+
if (err) {
|
|
51627
52118
|
if (status === 404 && code === "STEP_NOT_FOUND") {
|
|
51628
|
-
|
|
52119
|
+
detail = {
|
|
52120
|
+
message: `step "${o.step}" does not exist on run ${runId} \u2014 list its steps: lua workflows status ${runId} --steps`
|
|
52121
|
+
};
|
|
51629
52122
|
} else if (status === 409 && (code === "STEP_NOT_PARKED" || code === "step_not_parked")) {
|
|
51630
|
-
|
|
52123
|
+
detail = {
|
|
52124
|
+
message: `step "${o.step}" is not parked (running, pending or already decided) \u2014 nothing to resolve`
|
|
52125
|
+
};
|
|
51631
52126
|
} else if (status === 409 && (code === "RUN_TERMINAL" || code === "run_terminal")) {
|
|
51632
|
-
|
|
52127
|
+
detail = {
|
|
52128
|
+
message: `run ${runId} is terminal \u2014 start a new run instead`
|
|
52129
|
+
};
|
|
51633
52130
|
} else if (status === 400 && code === "RESOLVE_OUTPUT_INVALID") {
|
|
51634
|
-
|
|
51635
|
-
|
|
52131
|
+
detail = {
|
|
52132
|
+
message: `--output does not satisfy the outputSchema of step "${o.step}"`,
|
|
52133
|
+
issues: refusalIssues(err).map((i) => ({
|
|
52134
|
+
path: i.path ?? "$",
|
|
52135
|
+
message: i.message ?? i.code
|
|
52136
|
+
}))
|
|
52137
|
+
};
|
|
51636
52138
|
} else if (status === 403 && code === "APPROVAL_REQUIRES_HUMAN") {
|
|
51637
|
-
|
|
52139
|
+
detail = {
|
|
52140
|
+
message: "resolve-step is a person's decision \u2014 sign in (lua login) instead of an API key"
|
|
52141
|
+
};
|
|
51638
52142
|
} else if (status === 413 && code === "OUTPUT_TOO_LARGE") {
|
|
51639
52143
|
const { bytes, maxBytes } = err;
|
|
51640
|
-
|
|
52144
|
+
detail = {
|
|
52145
|
+
message: `--output is over the cap (${bytes ?? "?"} of ${maxBytes ?? 262144} bytes serialized)`
|
|
52146
|
+
};
|
|
51641
52147
|
}
|
|
51642
52148
|
}
|
|
51643
|
-
return apiFailure(ctx, res, "resolve-step");
|
|
52149
|
+
return apiFailure(ctx, res, "resolve-step", detail);
|
|
51644
52150
|
}
|
|
51645
52151
|
emitJson(ctx, res);
|
|
51646
52152
|
if (!ctx.json) {
|
|
@@ -51702,24 +52208,33 @@ async function raiseBudgetCore(ctx, runId, o) {
|
|
|
51702
52208
|
}
|
|
51703
52209
|
const res = await ctx.api.raiseBudget(runId, dto);
|
|
51704
52210
|
if (!res.success || !res.data) {
|
|
52211
|
+
let detail = {};
|
|
51705
52212
|
const err = res.error;
|
|
51706
52213
|
const code = err?.code ?? err?.error;
|
|
51707
52214
|
const status = err?.statusCode;
|
|
51708
|
-
if (
|
|
52215
|
+
if (err) {
|
|
51709
52216
|
if (status === 400 && code === "CAP_EXCEEDED") {
|
|
51710
52217
|
const { cap, value: value3, ceiling } = err;
|
|
51711
|
-
|
|
52218
|
+
detail = {
|
|
52219
|
+
message: `${budgetCapFlag(cap)} ${value3 ?? "?"} is above the org ceiling${ceiling !== void 0 ? ` (${ceiling})` : ""} \u2014 ask an org admin to raise the org cap, or cancel the run`
|
|
52220
|
+
};
|
|
51712
52221
|
} else if (status === 400 && code === "VALIDATION_FAILED") {
|
|
51713
|
-
|
|
51714
|
-
|
|
52222
|
+
detail = {
|
|
52223
|
+
issues: refusalIssues(err),
|
|
52224
|
+
hint: `the raise must be above the current cap \u2014 lua workflows status ${runId} shows it`
|
|
52225
|
+
};
|
|
51715
52226
|
} else if (status === 409 && code === "BUDGET_NOT_RAISABLE") {
|
|
51716
52227
|
const { status: runStatus, notRaisableReason } = err;
|
|
51717
|
-
|
|
52228
|
+
detail = {
|
|
52229
|
+
message: notRaisableReason === "raise_cap" ? `run ${runId} has reached its raise cap \u2014 cancel it, or start a new run with a larger --budget-credits` : `run ${runId} is ${runStatus ?? "not parked on its budget"} \u2014 only a run parked on its budget takes a raise`
|
|
52230
|
+
};
|
|
51718
52231
|
} else if (status === 403 && code === "NOT_RUN_CREATOR") {
|
|
51719
|
-
|
|
52232
|
+
detail = {
|
|
52233
|
+
message: "only the run creator or an org admin can raise a run budget"
|
|
52234
|
+
};
|
|
51720
52235
|
}
|
|
51721
52236
|
}
|
|
51722
|
-
return apiFailure(ctx, res, "raise-budget");
|
|
52237
|
+
return apiFailure(ctx, res, "raise-budget", detail);
|
|
51723
52238
|
}
|
|
51724
52239
|
emitJson(ctx, res);
|
|
51725
52240
|
if (!ctx.json) {
|
|
@@ -51746,24 +52261,20 @@ function approveResultLine(d) {
|
|
|
51746
52261
|
__name(approveResultLine, "approveResultLine");
|
|
51747
52262
|
async function approveCore(ctx, runId, o) {
|
|
51748
52263
|
if (!o.approval) {
|
|
51749
|
-
|
|
51750
|
-
return WORKFLOW_EXIT.USAGE;
|
|
52264
|
+
throw CliError.usage("approve: --approval <id> is required");
|
|
51751
52265
|
}
|
|
51752
52266
|
const decision = o.decision ?? "approve";
|
|
51753
52267
|
if (decision !== "approve" && decision !== "deny") {
|
|
51754
|
-
|
|
51755
|
-
return WORKFLOW_EXIT.USAGE;
|
|
52268
|
+
throw CliError.usage("approve: --decision must be approve|deny");
|
|
51756
52269
|
}
|
|
51757
52270
|
let editedPayload;
|
|
51758
52271
|
try {
|
|
51759
52272
|
if (o.edit) editedPayload = parseJsonOrFile(o.edit, "--edit");
|
|
51760
52273
|
} catch (e) {
|
|
51761
|
-
|
|
51762
|
-
return WORKFLOW_EXIT.USAGE;
|
|
52274
|
+
throw CliError.usage(`${e.message}`);
|
|
51763
52275
|
}
|
|
51764
52276
|
if (editedPayload !== void 0 && !o.fingerprint) {
|
|
51765
|
-
|
|
51766
|
-
return WORKFLOW_EXIT.USAGE;
|
|
52277
|
+
throw CliError.usage("approve: --fingerprint <f> is mandatory with --edit (the payloadFingerprint from approval-payload)");
|
|
51767
52278
|
}
|
|
51768
52279
|
const res = await ctx.api.resolveApproval(runId, o.approval, {
|
|
51769
52280
|
decision,
|
|
@@ -51772,15 +52283,22 @@ async function approveCore(ctx, runId, o) {
|
|
|
51772
52283
|
expectedFingerprint: o.fingerprint
|
|
51773
52284
|
});
|
|
51774
52285
|
if (!res.success || !res.data) {
|
|
52286
|
+
let detail = {};
|
|
51775
52287
|
const code = res.error?.code ?? res.error?.error;
|
|
51776
|
-
if (
|
|
51777
|
-
|
|
51778
|
-
|
|
51779
|
-
|
|
51780
|
-
} else if (
|
|
51781
|
-
|
|
52288
|
+
if (res.error?.statusCode === 404 && code === "APPROVAL_NOT_FOUND") {
|
|
52289
|
+
detail = {
|
|
52290
|
+
message: `approval "${o.approval}" not found on run ${runId} \u2014 pass the pending approval's wfa_\u2026 id: lua workflows status ${runId} --steps --json shows it as the suspended step's suspend.approvalId`
|
|
52291
|
+
};
|
|
52292
|
+
} else if (res.error?.statusCode === 409 && code === "PAYLOAD_MISMATCH") {
|
|
52293
|
+
detail = {
|
|
52294
|
+
message: `the payload changed since you looked \u2014 refetch: lua workflows approval-payload ${runId} --approval ${o.approval}`
|
|
52295
|
+
};
|
|
52296
|
+
} else if (res.error?.statusCode === 403 && code === "STEP_UP_REQUIRED") {
|
|
52297
|
+
detail = {
|
|
52298
|
+
message: "approve from the desktop with a fresh login (step-up required)"
|
|
52299
|
+
};
|
|
51782
52300
|
}
|
|
51783
|
-
return apiFailure(ctx, res, "approve");
|
|
52301
|
+
return apiFailure(ctx, res, "approve", detail);
|
|
51784
52302
|
}
|
|
51785
52303
|
emitJson(ctx, res);
|
|
51786
52304
|
if (!ctx.json) {
|
|
@@ -51794,8 +52312,7 @@ var indentBlock = /* @__PURE__ */ __name((text, pad2 = " ") => text.split("\
|
|
|
51794
52312
|
var APPROVAL_PAYLOAD_PAGE_MAX = 100;
|
|
51795
52313
|
async function approvalPayloadCore(ctx, runId, o) {
|
|
51796
52314
|
if (!o.approval) {
|
|
51797
|
-
|
|
51798
|
-
return WORKFLOW_EXIT.USAGE;
|
|
52315
|
+
throw CliError.usage("approval-payload: --approval <id> is required \u2014 lua workflows approval-payload <runId> --approval <wfa_\u2026> [--path <array.path>]");
|
|
51799
52316
|
}
|
|
51800
52317
|
let limit;
|
|
51801
52318
|
try {
|
|
@@ -51808,8 +52325,7 @@ async function approvalPayloadCore(ctx, runId, o) {
|
|
|
51808
52325
|
throw e;
|
|
51809
52326
|
}
|
|
51810
52327
|
if ((o.cursor || limit !== void 0) && !o.path) {
|
|
51811
|
-
|
|
51812
|
-
return WORKFLOW_EXIT.USAGE;
|
|
52328
|
+
throw CliError.usage("approval-payload: --cursor / --limit page one array \u2014 pass --path <array.path> with them");
|
|
51813
52329
|
}
|
|
51814
52330
|
const res = await ctx.api.getApprovalPayload(runId, o.approval, {
|
|
51815
52331
|
path: o.path,
|
|
@@ -51817,13 +52333,18 @@ async function approvalPayloadCore(ctx, runId, o) {
|
|
|
51817
52333
|
limit
|
|
51818
52334
|
});
|
|
51819
52335
|
if (!res.success || !res.data) {
|
|
52336
|
+
let detail = {};
|
|
51820
52337
|
const code = res.error?.code ?? res.error?.error;
|
|
51821
|
-
if (
|
|
51822
|
-
|
|
51823
|
-
|
|
51824
|
-
|
|
52338
|
+
if (res.error?.statusCode === 404 && code === "APPROVAL_NOT_FOUND") {
|
|
52339
|
+
detail = {
|
|
52340
|
+
message: `approval "${o.approval}" not found on run ${runId} \u2014 lua workflows status ${runId} --steps --json shows the suspended step's suspend.approvalId`
|
|
52341
|
+
};
|
|
52342
|
+
} else if (res.error?.statusCode === 413 && code === "PAYLOAD_PAGE_REQUIRED") {
|
|
52343
|
+
detail = {
|
|
52344
|
+
message: "the payload is too large to read whole \u2014 page an array with --path <array.path> [--limit <n>] [--cursor <c>]"
|
|
52345
|
+
};
|
|
51825
52346
|
}
|
|
51826
|
-
return apiFailure(ctx, res, "approval-payload");
|
|
52347
|
+
return apiFailure(ctx, res, "approval-payload", detail);
|
|
51827
52348
|
}
|
|
51828
52349
|
emitJson(ctx, res);
|
|
51829
52350
|
if (!ctx.json) {
|
|
@@ -51887,16 +52408,9 @@ function reservedSecretKeyPaths(value3, path25 = "", depth = 0, out = []) {
|
|
|
51887
52408
|
__name(reservedSecretKeyPaths, "reservedSecretKeyPaths");
|
|
51888
52409
|
async function signalCore(ctx, runId, name, o) {
|
|
51889
52410
|
if (!name) {
|
|
51890
|
-
|
|
51891
|
-
return WORKFLOW_EXIT.USAGE;
|
|
51892
|
-
}
|
|
51893
|
-
let payload;
|
|
51894
|
-
try {
|
|
51895
|
-
if (o.payload) payload = parseJsonOrFile(o.payload, "--payload");
|
|
51896
|
-
} catch (e) {
|
|
51897
|
-
console.error(`\u274C ${e.message}`);
|
|
51898
|
-
return WORKFLOW_EXIT.USAGE;
|
|
52411
|
+
throw CliError.usage("signal: a signal name is required", "lua workflows signal <runId> <name> [--payload <json|@file>]");
|
|
51899
52412
|
}
|
|
52413
|
+
const payload = parsedOrUsage(() => o.payload ? parseJsonOrFile(o.payload, "--payload") : void 0);
|
|
51900
52414
|
const reserved = reservedSecretKeyPaths(payload);
|
|
51901
52415
|
if (reserved.length > 0) {
|
|
51902
52416
|
const many = reserved.length > 1;
|
|
@@ -51908,22 +52422,24 @@ async function signalCore(ctx, runId, name, o) {
|
|
|
51908
52422
|
});
|
|
51909
52423
|
if (!res.success || !res.data) {
|
|
51910
52424
|
const code = res.error?.code ?? res.error?.error;
|
|
51911
|
-
|
|
51912
|
-
|
|
51913
|
-
|
|
51914
|
-
|
|
51915
|
-
|
|
51916
|
-
|
|
51917
|
-
|
|
51918
|
-
|
|
51919
|
-
|
|
51920
|
-
|
|
51921
|
-
|
|
51922
|
-
|
|
51923
|
-
|
|
51924
|
-
|
|
52425
|
+
const where = res.error?.stepId ? `step "${res.error.stepId}"` : "the waiting step";
|
|
52426
|
+
let detail = {};
|
|
52427
|
+
if (res.error?.statusCode === 400 && code === "SIGNAL_SCHEMA_INVALID") {
|
|
52428
|
+
detail = {
|
|
52429
|
+
message: `signal "${name}" rejected \u2014 the payload does not match the schema ${where} declares`,
|
|
52430
|
+
issues: res.error?.issues,
|
|
52431
|
+
hint: "fix the payload and send it again (a --dedupe-key is not consumed by a rejected signal)"
|
|
52432
|
+
};
|
|
52433
|
+
} else if (res.error?.statusCode === 422 && code === "SIGNAL_SCHEMA_UNCOMPILABLE") {
|
|
52434
|
+
detail = {
|
|
52435
|
+
message: `signal "${name}" could not be checked \u2014 the schema ${where} declares does not compile`,
|
|
52436
|
+
issues: (res.error?.issues ?? []).map((issue) => ({
|
|
52437
|
+
message: issue.message ?? "schema does not compile"
|
|
52438
|
+
})),
|
|
52439
|
+
hint: "this is a workflow definition defect, not a payload problem \u2014 fix the `schema` on the waitForSignal node in the workflow source, push a new version, then send the signal again"
|
|
52440
|
+
};
|
|
51925
52441
|
}
|
|
51926
|
-
return apiFailure(ctx, res, "signal");
|
|
52442
|
+
return apiFailure(ctx, res, "signal", detail);
|
|
51927
52443
|
}
|
|
51928
52444
|
emitJson(ctx, res);
|
|
51929
52445
|
const r = res.data;
|
|
@@ -51936,8 +52452,7 @@ async function signalCore(ctx, runId, name, o) {
|
|
|
51936
52452
|
__name(signalCore, "signalCore");
|
|
51937
52453
|
async function replayCore(ctx, runId, o) {
|
|
51938
52454
|
if (!o.local) {
|
|
51939
|
-
|
|
51940
|
-
return WORKFLOW_EXIT.USAGE;
|
|
52455
|
+
throw CliError.usage("replay: only `--local` is available (server-side replay is not a v1 route)");
|
|
51941
52456
|
}
|
|
51942
52457
|
const runRes = await ctx.api.getRun(runId);
|
|
51943
52458
|
if (!runRes.success || !runRes.data) return apiFailure(ctx, runRes, "replay");
|
|
@@ -51946,8 +52461,7 @@ async function replayCore(ctx, runId, o) {
|
|
|
51946
52461
|
try {
|
|
51947
52462
|
manifestWorkflows = getPrimitivesByKind(loadManifest(), PrimitiveKind.WORKFLOW);
|
|
51948
52463
|
} catch (e) {
|
|
51949
|
-
|
|
51950
|
-
return WORKFLOW_EXIT.USAGE;
|
|
52464
|
+
throw CliError.usage(`replay --local needs a compiled project: ${e.message}`);
|
|
51951
52465
|
}
|
|
51952
52466
|
const wf = (o.workflowName ? manifestWorkflows.find((w) => w.name === o.workflowName) : void 0) ?? manifestWorkflows.find((w) => w.graphHash === run.graphHash);
|
|
51953
52467
|
if (!wf) {
|
|
@@ -52193,11 +52707,11 @@ async function deleteRunCore(ctx, runId, o) {
|
|
|
52193
52707
|
const res = await ctx.api.eraseRun(runId);
|
|
52194
52708
|
if (!res.success || !res.data) {
|
|
52195
52709
|
const code = res.error?.code ?? res.error?.error;
|
|
52196
|
-
if (
|
|
52710
|
+
if (res.error?.statusCode === 409 && code === "RUN_NOT_TERMINAL") {
|
|
52197
52711
|
const status = res.error.status;
|
|
52198
|
-
|
|
52199
|
-
|
|
52200
|
-
|
|
52712
|
+
return apiFailure(ctx, res, "delete-run", {
|
|
52713
|
+
message: `run is \`${status ?? "live"}\`; cancel it first: lua workflows cancel ${runId}`
|
|
52714
|
+
});
|
|
52201
52715
|
}
|
|
52202
52716
|
return apiFailure(ctx, res, "delete-run");
|
|
52203
52717
|
}
|
|
@@ -52315,17 +52829,14 @@ async function archiveRunsCore(ctx, o) {
|
|
|
52315
52829
|
const now = Date.now();
|
|
52316
52830
|
const since = parseSinceFlag(o.since, now);
|
|
52317
52831
|
if (!Number.isFinite(since)) {
|
|
52318
|
-
|
|
52319
|
-
return WORKFLOW_EXIT.USAGE;
|
|
52832
|
+
throw CliError.usage("archive-runs: --since <iso|dur> is required (e.g. --since 8d)");
|
|
52320
52833
|
}
|
|
52321
52834
|
const until = o.until ? Date.parse(o.until) : void 0;
|
|
52322
52835
|
if (o.until && !Number.isFinite(until)) {
|
|
52323
|
-
|
|
52324
|
-
return WORKFLOW_EXIT.USAGE;
|
|
52836
|
+
throw CliError.usage(`archive-runs: --until is not an ISO timestamp ("${o.until}")`);
|
|
52325
52837
|
}
|
|
52326
52838
|
if (!o.out) {
|
|
52327
|
-
|
|
52328
|
-
return WORKFLOW_EXIT.USAGE;
|
|
52839
|
+
throw CliError.usage("archive-runs: --out <dir> is required");
|
|
52329
52840
|
}
|
|
52330
52841
|
if (/^(s3|gs):\/\//.test(o.out)) {
|
|
52331
52842
|
console.error(`\u274C archive-runs: remote sinks (${o.out}) need the org storage connection (--connection) \u2014 not wired in this build; archive to a local dir and sync it`);
|
|
@@ -52589,11 +53100,14 @@ async function workspaceCore(ctx, runId, o) {
|
|
|
52589
53100
|
note: o.note
|
|
52590
53101
|
} : {});
|
|
52591
53102
|
if (!res2.success || !res2.data) {
|
|
52592
|
-
|
|
53103
|
+
let detail = {};
|
|
53104
|
+
if (res2.error?.statusCode === 409) {
|
|
52593
53105
|
const stepId = res2.error.stepId;
|
|
52594
|
-
|
|
53106
|
+
detail = {
|
|
53107
|
+
message: `Workspace of ${runId} is in use${stepId ? ` by step ${stepId}` : ""} \u2014 cancel the run or wait for the step to finish`
|
|
53108
|
+
};
|
|
52595
53109
|
}
|
|
52596
|
-
return apiFailure(ctx, res2, "workspace");
|
|
53110
|
+
return apiFailure(ctx, res2, "workspace", detail);
|
|
52597
53111
|
}
|
|
52598
53112
|
emitJson(ctx, res2);
|
|
52599
53113
|
if (!ctx.json) {
|
|
@@ -52674,14 +53188,12 @@ function printJobHeader(v) {
|
|
|
52674
53188
|
__name(printJobHeader, "printJobHeader");
|
|
52675
53189
|
async function jobLogsCore(ctx, runId, stepId, o) {
|
|
52676
53190
|
if (!stepId) {
|
|
52677
|
-
|
|
52678
|
-
return WORKFLOW_EXIT.USAGE;
|
|
53191
|
+
throw CliError.usage(`job-logs: a step id is required \u2014 lua workflows job-logs ${runId} <stepId>`);
|
|
52679
53192
|
}
|
|
52680
53193
|
const attempt = o.attempt !== void 0 && o.attempt !== "" ? Number(o.attempt) : void 0;
|
|
52681
53194
|
const tail = o.tail !== void 0 && o.tail !== "" ? Number(o.tail) : JOB_LOG_TAIL_DEFAULT;
|
|
52682
53195
|
if (attempt !== void 0 && !(Number.isInteger(attempt) && attempt >= 1) || !(Number.isInteger(tail) && tail >= 1 && tail <= JOB_LOG_TAIL_MAX)) {
|
|
52683
|
-
|
|
52684
|
-
return WORKFLOW_EXIT.USAGE;
|
|
53196
|
+
throw CliError.usage(`job-logs: --attempt must be \u2265 1 and --tail an integer in 1..${JOB_LOG_TAIL_MAX}`);
|
|
52685
53197
|
}
|
|
52686
53198
|
let printed = 0;
|
|
52687
53199
|
let first = true;
|
|
@@ -52691,18 +53203,18 @@ async function jobLogsCore(ctx, runId, stepId, o) {
|
|
|
52691
53203
|
tail
|
|
52692
53204
|
});
|
|
52693
53205
|
if (!res.success || !res.data) {
|
|
52694
|
-
|
|
52695
|
-
|
|
52696
|
-
|
|
52697
|
-
|
|
52698
|
-
|
|
52699
|
-
|
|
52700
|
-
|
|
52701
|
-
|
|
52702
|
-
|
|
52703
|
-
|
|
53206
|
+
let detail = {};
|
|
53207
|
+
if (res.error?.statusCode === 404 && res.error?.code === "JOB_NOT_FOUND") {
|
|
53208
|
+
detail = {
|
|
53209
|
+
message: `${stepId} is not a Job-tier step of ${runId} (try: lua workflows jobs ${runId})`
|
|
53210
|
+
};
|
|
53211
|
+
} else if (res.error?.statusCode === 404 && res.error?.code === "JOB_LOGS_NOT_PERSISTED") {
|
|
53212
|
+
detail = {
|
|
53213
|
+
message: `job-logs: ${res.error.message}`,
|
|
53214
|
+
hint: `lua workflows status ${runId} --steps shows the step error; --attempt <n> reads another attempt.`
|
|
53215
|
+
};
|
|
52704
53216
|
}
|
|
52705
|
-
return apiFailure(ctx, res, "job-logs");
|
|
53217
|
+
return apiFailure(ctx, res, "job-logs", detail);
|
|
52706
53218
|
}
|
|
52707
53219
|
const v = res.data;
|
|
52708
53220
|
if (ctx.json && !o.follow) {
|
|
@@ -52965,38 +53477,54 @@ function subVerb(group, noun, raw, verbs) {
|
|
|
52965
53477
|
}
|
|
52966
53478
|
__name(subVerb, "subVerb");
|
|
52967
53479
|
function goalFailure(ctx, res, verb, ref) {
|
|
53480
|
+
let detail = {};
|
|
52968
53481
|
const err = res.error;
|
|
52969
53482
|
const code = err?.code ?? err?.error;
|
|
52970
53483
|
const status = err?.statusCode;
|
|
52971
|
-
if (
|
|
53484
|
+
if (err) {
|
|
52972
53485
|
if (status === 409 && code === "GOAL_NOT_ACTIVE") {
|
|
52973
53486
|
const now = err.status ?? "not active";
|
|
52974
53487
|
const rule = verb === "goals resume" ? "only a paused goal resumes" : verb === "goals pause" ? "only an active goal pauses" : "a done/closed goal stays closed (a lingering cadence Job goes with `lua workflows schedules delete <jobId>`)";
|
|
52975
|
-
|
|
52976
|
-
|
|
53488
|
+
detail = {
|
|
53489
|
+
message: `goal ${ref ?? ""} is ${now} \u2014 ${rule}`,
|
|
53490
|
+
hint: verb === "goals resume" && now === "paused" ? goalRaiseHint(ref ?? "<goalId>") : void 0
|
|
53491
|
+
};
|
|
52977
53492
|
} else if (status === 400 && code === "GOAL_RAISE_BELOW_SPENT") {
|
|
52978
53493
|
const { field, value: value3, spent } = err;
|
|
52979
53494
|
const flag = field === "maxRuns" ? "--max-runs" : "--max-credits";
|
|
52980
53495
|
const used = field === "maxRuns" ? "run(s) already used" : "credit(s) already spent";
|
|
52981
|
-
|
|
53496
|
+
detail = {
|
|
53497
|
+
message: `${flag} ${value3 ?? "?"} is not above the ${spent ?? "?"} ${used} \u2014 raise it past ${spent ?? "?"}`
|
|
53498
|
+
};
|
|
52982
53499
|
} else if (status === 409 && code === "GOAL_VERSION_CONFLICT") {
|
|
52983
53500
|
const at = err.updatedAt;
|
|
52984
|
-
|
|
53501
|
+
detail = {
|
|
53502
|
+
message: `goal ${ref ?? ""} changed since it was read${at ? ` (updatedAt ${at})` : ""} \u2014 re-run lua workflows goals get ${ref ?? "<goalId>"} and retry${at ? ` with --if-match ${at}` : ""}`
|
|
53503
|
+
};
|
|
52985
53504
|
} else if (status === 409 && code === "GOAL_CAP") {
|
|
52986
|
-
|
|
53505
|
+
detail = {
|
|
53506
|
+
message: `goal cap reached (${err.cap ?? "?"} per agent) \u2014 close or finish one first: lua workflows goals list --status active`
|
|
53507
|
+
};
|
|
52987
53508
|
} else if (status === 400 && code === "VALIDATION_FAILED") {
|
|
52988
|
-
|
|
52989
|
-
|
|
53509
|
+
detail = {
|
|
53510
|
+
issues: refusalIssues(err)
|
|
53511
|
+
};
|
|
52990
53512
|
} else if (status === 400 && code === "GOAL_MAX_RUNS_INVALID") {
|
|
52991
|
-
|
|
53513
|
+
detail = {
|
|
53514
|
+
message: `--max-runs must be 1..${GOAL_MAX_RUNS_CAP}`
|
|
53515
|
+
};
|
|
52992
53516
|
} else if (status === 400 && code === "WORKFLOW_NOT_ON_AGENT") {
|
|
52993
|
-
|
|
53517
|
+
detail = {
|
|
53518
|
+
message: `that workflow belongs to another agent \u2014 goals are scoped to ${ctx.agentId}`
|
|
53519
|
+
};
|
|
52994
53520
|
} else if (status === 409 && code === "GOAL_SCHEDULE") {
|
|
52995
53521
|
const goalId = err.goalId ?? "?";
|
|
52996
|
-
|
|
53522
|
+
detail = {
|
|
53523
|
+
message: `GOAL_SCHEDULE: ${goalScheduleRefusal(ref ?? "<jobId>", goalId)}`
|
|
53524
|
+
};
|
|
52997
53525
|
}
|
|
52998
53526
|
}
|
|
52999
|
-
return apiFailure(ctx, res, verb);
|
|
53527
|
+
return apiFailure(ctx, res, verb, detail);
|
|
53000
53528
|
}
|
|
53001
53529
|
__name(goalFailure, "goalFailure");
|
|
53002
53530
|
async function goalsCore(ctx, target, extra, o) {
|
|
@@ -53005,8 +53533,7 @@ async function goalsCore(ctx, target, extra, o) {
|
|
|
53005
53533
|
if (verb === "list") return goalsListCore(ctx, o, extra);
|
|
53006
53534
|
if (verb === "create") return goalsCreateCore(ctx, o, extra);
|
|
53007
53535
|
if (!extra) {
|
|
53008
|
-
|
|
53009
|
-
return WORKFLOW_EXIT.USAGE;
|
|
53536
|
+
throw CliError.usage(`goals ${verb}: a goal id is required \u2014 lua workflows goals ${verb} <goalId>`);
|
|
53010
53537
|
}
|
|
53011
53538
|
if (verb === "get") return goalsGetCore(ctx, extra);
|
|
53012
53539
|
if (verb === "edit") return goalsEditCore(ctx, extra, o);
|
|
@@ -53016,8 +53543,7 @@ async function goalsCore(ctx, target, extra, o) {
|
|
|
53016
53543
|
__name(goalsCore, "goalsCore");
|
|
53017
53544
|
async function goalsListCore(ctx, o, positional) {
|
|
53018
53545
|
if (o.status && !GOAL_STATUSES.includes(o.status)) {
|
|
53019
|
-
|
|
53020
|
-
return WORKFLOW_EXIT.USAGE;
|
|
53546
|
+
throw CliError.usage(`goals list: --status must be ${GOAL_STATUSES.join("|")} (got "${o.status}")`);
|
|
53021
53547
|
}
|
|
53022
53548
|
let limit;
|
|
53023
53549
|
try {
|
|
@@ -53026,8 +53552,7 @@ async function goalsListCore(ctx, o, positional) {
|
|
|
53026
53552
|
max: GOAL_PAGE_LIMIT
|
|
53027
53553
|
});
|
|
53028
53554
|
} catch (e) {
|
|
53029
|
-
|
|
53030
|
-
return WORKFLOW_EXIT.USAGE;
|
|
53555
|
+
throw CliError.usage(`${e.message}`);
|
|
53031
53556
|
}
|
|
53032
53557
|
const list = await loadWorkflowList(ctx);
|
|
53033
53558
|
if (!list) return WORKFLOW_EXIT.API;
|
|
@@ -53188,8 +53713,7 @@ async function goalsEditCore(ctx, goalId, o) {
|
|
|
53188
53713
|
if (Object.keys(dto).filter((k) => k !== "ifMatch").length === 0) throw usage("nothing to change \u2014 pass --objective, --judge-predicate, --cadence | --every, --max-runs, --max-credits <n|none> or --note");
|
|
53189
53714
|
} catch (e) {
|
|
53190
53715
|
if (e instanceof WorkflowLocalUsageError) {
|
|
53191
|
-
|
|
53192
|
-
return WORKFLOW_EXIT.USAGE;
|
|
53716
|
+
throw CliError.usage(`goals edit: ${e.message}`);
|
|
53193
53717
|
}
|
|
53194
53718
|
throw e;
|
|
53195
53719
|
}
|
|
@@ -53221,8 +53745,7 @@ async function goalsRaiseCore(ctx, goalId, o) {
|
|
|
53221
53745
|
if (ifMatch !== void 0) dto.ifMatch = ifMatch;
|
|
53222
53746
|
} catch (e) {
|
|
53223
53747
|
if (e instanceof WorkflowLocalUsageError) {
|
|
53224
|
-
|
|
53225
|
-
return WORKFLOW_EXIT.USAGE;
|
|
53748
|
+
throw CliError.usage(`goals raise: ${e.message}`);
|
|
53226
53749
|
}
|
|
53227
53750
|
throw e;
|
|
53228
53751
|
}
|
|
@@ -53308,20 +53831,16 @@ __name(parseCadenceFlag, "parseCadenceFlag");
|
|
|
53308
53831
|
async function goalsCreateCore(ctx, o, positional) {
|
|
53309
53832
|
const target = positional ?? o.workflowName ?? o.workflow;
|
|
53310
53833
|
if (!target) {
|
|
53311
|
-
|
|
53312
|
-
return WORKFLOW_EXIT.USAGE;
|
|
53834
|
+
throw CliError.usage("goals create: a workflow is required \u2014 lua workflows goals create <workflow> (or -i <workflow>)");
|
|
53313
53835
|
}
|
|
53314
53836
|
if (!o.objective?.trim()) {
|
|
53315
|
-
|
|
53316
|
-
return WORKFLOW_EXIT.USAGE;
|
|
53837
|
+
throw CliError.usage("goals create: --objective <text> is required");
|
|
53317
53838
|
}
|
|
53318
53839
|
if (o.judgeAgent === "") {
|
|
53319
|
-
|
|
53320
|
-
return WORKFLOW_EXIT.USAGE;
|
|
53840
|
+
throw CliError.usage("goals create: --judge-agent is empty \u2014 an unquoted $self is expanded by the shell to nothing; write '$self' (quoted) or self");
|
|
53321
53841
|
}
|
|
53322
53842
|
if (!o.judgePredicate && !o.judgeAgent) {
|
|
53323
|
-
|
|
53324
|
-
return WORKFLOW_EXIT.USAGE;
|
|
53843
|
+
throw CliError.usage("goals create: one of --judge-predicate <spec> | --judge-agent <agentId|'$self'> is required");
|
|
53325
53844
|
}
|
|
53326
53845
|
const usage = /* @__PURE__ */ __name((m) => new WorkflowLocalUsageError("usage", m), "usage");
|
|
53327
53846
|
let dto;
|
|
@@ -53381,8 +53900,7 @@ async function goalsCreateCore(ctx, o, positional) {
|
|
|
53381
53900
|
};
|
|
53382
53901
|
} catch (e) {
|
|
53383
53902
|
if (e instanceof WorkflowLocalUsageError) {
|
|
53384
|
-
|
|
53385
|
-
return WORKFLOW_EXIT.USAGE;
|
|
53903
|
+
throw CliError.usage(`${e.message}`);
|
|
53386
53904
|
}
|
|
53387
53905
|
throw e;
|
|
53388
53906
|
}
|
|
@@ -53424,8 +53942,7 @@ async function schedulesCore(ctx, target, extra, o) {
|
|
|
53424
53942
|
if (verb === "list") return schedulesListCore(ctx, o);
|
|
53425
53943
|
if (verb === "create") return schedulesCreateCore(ctx, o, extra);
|
|
53426
53944
|
if (!extra) {
|
|
53427
|
-
|
|
53428
|
-
return WORKFLOW_EXIT.USAGE;
|
|
53945
|
+
throw CliError.usage(`schedules ${verb}: a schedule (job) id is required \u2014 lua workflows schedules ${verb} <jobId>`);
|
|
53429
53946
|
}
|
|
53430
53947
|
if (verb === "delete") return schedulesDeleteCore(ctx, extra, o);
|
|
53431
53948
|
return schedulesPatchCore(ctx, extra, verb, o);
|
|
@@ -53480,17 +53997,19 @@ async function schedulesDeleteCore(ctx, jobId, o) {
|
|
|
53480
53997
|
const goalRes = await ctx.api.getGoal(goalId);
|
|
53481
53998
|
if (goalRes.success && goalRes.data) goalStatus = goalRes.data.status;
|
|
53482
53999
|
else if (goalRes.error?.statusCode !== 404) {
|
|
53483
|
-
|
|
53484
|
-
|
|
54000
|
+
return apiFailure(ctx, goalRes, "schedules delete", {
|
|
54001
|
+
message: `cannot prove goal ${goalId} of ${jobId} has ended (goal unreadable) \u2014 refusing to delete`
|
|
54002
|
+
});
|
|
53485
54003
|
}
|
|
53486
54004
|
} else {
|
|
53487
54005
|
const goals = await loadGoals(ctx, row2.workflowId);
|
|
53488
54006
|
if (goals.error) {
|
|
53489
|
-
if (!ctx.json) console.error(`\u274C cannot prove ${jobId} is not a goal's cadence (goals unavailable) \u2014 refusing to delete`);
|
|
53490
54007
|
return apiFailure(ctx, {
|
|
53491
54008
|
success: false,
|
|
53492
54009
|
error: goals.error
|
|
53493
|
-
}, "schedules delete"
|
|
54010
|
+
}, "schedules delete", {
|
|
54011
|
+
message: `cannot prove ${jobId} is not a goal's cadence (goals unavailable) \u2014 refusing to delete`
|
|
54012
|
+
});
|
|
53494
54013
|
}
|
|
53495
54014
|
const owner = goals.items.find((g) => g.jobId === jobId);
|
|
53496
54015
|
goalId = owner?.goalId;
|
|
@@ -53541,8 +54060,7 @@ var SCHEDULE_NOTIFY = [
|
|
|
53541
54060
|
async function schedulesCreateCore(ctx, o, positional) {
|
|
53542
54061
|
const target = positional ?? o.workflowName ?? o.workflow;
|
|
53543
54062
|
if (!target) {
|
|
53544
|
-
|
|
53545
|
-
return WORKFLOW_EXIT.USAGE;
|
|
54063
|
+
throw CliError.usage('schedules create: a workflow is required \u2014 lua workflows schedules create <workflow> --cadence "0 9 * * 1" --timezone Europe/London');
|
|
53546
54064
|
}
|
|
53547
54065
|
let draft;
|
|
53548
54066
|
try {
|
|
@@ -53669,11 +54187,12 @@ async function schedulesPatchCore(ctx, jobId, verb, o) {
|
|
|
53669
54187
|
if (!rowRes.success || !rowRes.data) return apiFailure(ctx, rowRes, label);
|
|
53670
54188
|
const owner = await scheduleGoalOwner(ctx, rowRes.data);
|
|
53671
54189
|
if (owner.error) {
|
|
53672
|
-
if (!ctx.json) console.error(`\u274C cannot prove ${jobId} is not a goal's cadence (goals unavailable) \u2014 refusing to ${verb}`);
|
|
53673
54190
|
return apiFailure(ctx, {
|
|
53674
54191
|
success: false,
|
|
53675
54192
|
error: owner.error
|
|
53676
|
-
}, label
|
|
54193
|
+
}, label, {
|
|
54194
|
+
message: `cannot prove ${jobId} is not a goal's cadence (goals unavailable) \u2014 refusing to ${verb}`
|
|
54195
|
+
});
|
|
53677
54196
|
}
|
|
53678
54197
|
if (owner.goalId) {
|
|
53679
54198
|
const message = `Schedule ${jobId} is the cadence of goal ${owner.goalId} and was NOT changed. Pause or resume the goal instead: lua workflows goals pause ${owner.goalId} / lua workflows goals resume ${owner.goalId} \u2014 a goal's Job follows its goal, never the other way round.`;
|
|
@@ -55353,6 +55872,7 @@ init_cli();
|
|
|
55353
55872
|
// src/api/marketplace.api.service.ts
|
|
55354
55873
|
init_constants();
|
|
55355
55874
|
init_lua_fetch();
|
|
55875
|
+
init_http_client();
|
|
55356
55876
|
init_request_credential();
|
|
55357
55877
|
var MarketplaceApiService = class {
|
|
55358
55878
|
static {
|
|
@@ -55377,8 +55897,7 @@ var MarketplaceApiService = class {
|
|
|
55377
55897
|
headers
|
|
55378
55898
|
});
|
|
55379
55899
|
if (!response.ok) {
|
|
55380
|
-
|
|
55381
|
-
throw new Error(`API Error: ${response.status} ${response.statusText} - ${errorText}`);
|
|
55900
|
+
throw await refusalFromResponse(response);
|
|
55382
55901
|
}
|
|
55383
55902
|
if (response.status === 204) {
|
|
55384
55903
|
return null;
|
|
@@ -55501,6 +56020,7 @@ import { readFileSync as readFileSync14 } from "fs";
|
|
|
55501
56020
|
// src/api/template.api.service.ts
|
|
55502
56021
|
init_constants();
|
|
55503
56022
|
init_lua_fetch();
|
|
56023
|
+
init_http_client();
|
|
55504
56024
|
init_request_credential();
|
|
55505
56025
|
var TemplateApiService = class {
|
|
55506
56026
|
static {
|
|
@@ -55523,8 +56043,7 @@ var TemplateApiService = class {
|
|
|
55523
56043
|
headers
|
|
55524
56044
|
});
|
|
55525
56045
|
if (!response.ok) {
|
|
55526
|
-
|
|
55527
|
-
throw new Error(`API Error: ${response.status} ${response.statusText} - ${errorText}`);
|
|
56046
|
+
throw await refusalFromResponse(response);
|
|
55528
56047
|
}
|
|
55529
56048
|
if (response.status === 204) {
|
|
55530
56049
|
return null;
|
|
@@ -55747,6 +56266,11 @@ function sleep2(ms) {
|
|
|
55747
56266
|
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
55748
56267
|
}
|
|
55749
56268
|
__name(sleep2, "sleep");
|
|
56269
|
+
function missingVersionOrRethrow(error) {
|
|
56270
|
+
if (CliError.isCliError(error) && error.statusCode === 404) return null;
|
|
56271
|
+
throw error;
|
|
56272
|
+
}
|
|
56273
|
+
__name(missingVersionOrRethrow, "missingVersionOrRethrow");
|
|
55750
56274
|
async function resolveTemplateId(templateApi, options, message) {
|
|
55751
56275
|
if (options.templateId) return options.templateId;
|
|
55752
56276
|
writeProgress("\u{1F504} Loading your templates...");
|
|
@@ -56123,8 +56647,8 @@ async function templateViewAction(templateApi, options) {
|
|
|
56123
56647
|
if (!Number.isFinite(versionNum) || versionNum <= 0) {
|
|
56124
56648
|
throw new Error(`Invalid --version "${options.version}": must be a positive integer.`);
|
|
56125
56649
|
}
|
|
56126
|
-
const version = await templateApi.getVersion(templateId, versionNum).catch(
|
|
56127
|
-
if (!version) throw
|
|
56650
|
+
const version = await templateApi.getVersion(templateId, versionNum).catch(missingVersionOrRethrow);
|
|
56651
|
+
if (!version) throw CliError.notFound(`Version v${versionNum} not found for this template.`);
|
|
56128
56652
|
if (options.json) {
|
|
56129
56653
|
console.log(JSON.stringify(version, null, 2));
|
|
56130
56654
|
return;
|
|
@@ -56288,8 +56812,8 @@ async function templateApplyAction(templateApi, options) {
|
|
|
56288
56812
|
throw new Error("This template has no published versions. Run `lua marketplace template publish` first.");
|
|
56289
56813
|
}
|
|
56290
56814
|
const versionNum = options.version ? Number.parseInt(options.version, 10) : template3.latestVersion;
|
|
56291
|
-
const versionObj = await templateApi.getVersion(templateId, versionNum).catch(
|
|
56292
|
-
if (!versionObj) throw
|
|
56815
|
+
const versionObj = await templateApi.getVersion(templateId, versionNum).catch(missingVersionOrRethrow);
|
|
56816
|
+
if (!versionObj) throw CliError.notFound(`Version v${versionNum} not found for this template.`);
|
|
56293
56817
|
if (!options.force) {
|
|
56294
56818
|
console.log(`
|
|
56295
56819
|
Apply plan:`);
|
|
@@ -56540,45 +57064,57 @@ var SKILL_ACTION_LABELS = {
|
|
|
56540
57064
|
org: "View this organization's owned skills"
|
|
56541
57065
|
};
|
|
56542
57066
|
async function marketplaceCommand(noun, action, options = {}) {
|
|
56543
|
-
return withErrorHandling(
|
|
56544
|
-
|
|
56545
|
-
|
|
56546
|
-
|
|
56547
|
-
|
|
56548
|
-
|
|
56549
|
-
|
|
56550
|
-
|
|
56551
|
-
|
|
56552
|
-
message: "What would you like to browse?",
|
|
56553
|
-
choices: [
|
|
56554
|
-
{
|
|
56555
|
-
name: "Skills",
|
|
56556
|
-
value: "skill"
|
|
56557
|
-
},
|
|
56558
|
-
{
|
|
56559
|
-
name: "Agent templates",
|
|
56560
|
-
value: "template"
|
|
56561
|
-
},
|
|
56562
|
-
{
|
|
56563
|
-
name: "Exit",
|
|
56564
|
-
value: "exit"
|
|
56565
|
-
}
|
|
56566
|
-
]
|
|
56567
|
-
}
|
|
56568
|
-
]);
|
|
56569
|
-
if (!domainAnswer || domainAnswer.domain === "exit") {
|
|
56570
|
-
console.log("\n\u{1F44B} Goodbye!\n");
|
|
56571
|
-
return;
|
|
56572
|
-
}
|
|
56573
|
-
domain = domainAnswer.domain;
|
|
56574
|
-
}
|
|
56575
|
-
if (domain === "template") {
|
|
56576
|
-
return templateCommand(action, options);
|
|
57067
|
+
return withErrorHandling(
|
|
57068
|
+
async () => {
|
|
57069
|
+
await marketplaceDispatch(noun, action, options);
|
|
57070
|
+
},
|
|
57071
|
+
"marketplace",
|
|
57072
|
+
// LUA-803: under `--json` an escaped refusal (a template 403 / 404, a network failure) is the typed envelope on
|
|
57073
|
+
// stdout, not the `✖` line.
|
|
57074
|
+
{
|
|
57075
|
+
json: /* @__PURE__ */ __name(() => !!options.json, "json")
|
|
56577
57076
|
}
|
|
56578
|
-
|
|
56579
|
-
}, "marketplace");
|
|
57077
|
+
);
|
|
56580
57078
|
}
|
|
56581
57079
|
__name(marketplaceCommand, "marketplaceCommand");
|
|
57080
|
+
async function marketplaceDispatch(noun, action, options) {
|
|
57081
|
+
let domain;
|
|
57082
|
+
if (noun) {
|
|
57083
|
+
domain = validateOrSuggest("marketplace.noun", noun);
|
|
57084
|
+
} else {
|
|
57085
|
+
const domainAnswer = await safePrompt([
|
|
57086
|
+
{
|
|
57087
|
+
type: "list",
|
|
57088
|
+
name: "domain",
|
|
57089
|
+
message: "What would you like to browse?",
|
|
57090
|
+
choices: [
|
|
57091
|
+
{
|
|
57092
|
+
name: "Skills",
|
|
57093
|
+
value: "skill"
|
|
57094
|
+
},
|
|
57095
|
+
{
|
|
57096
|
+
name: "Agent templates",
|
|
57097
|
+
value: "template"
|
|
57098
|
+
},
|
|
57099
|
+
{
|
|
57100
|
+
name: "Exit",
|
|
57101
|
+
value: "exit"
|
|
57102
|
+
}
|
|
57103
|
+
]
|
|
57104
|
+
}
|
|
57105
|
+
]);
|
|
57106
|
+
if (!domainAnswer || domainAnswer.domain === "exit") {
|
|
57107
|
+
console.log("\n\u{1F44B} Goodbye!\n");
|
|
57108
|
+
return;
|
|
57109
|
+
}
|
|
57110
|
+
domain = domainAnswer.domain;
|
|
57111
|
+
}
|
|
57112
|
+
if (domain === "template") {
|
|
57113
|
+
return templateCommand(action, options);
|
|
57114
|
+
}
|
|
57115
|
+
return skillMarketplaceCommand(action, options);
|
|
57116
|
+
}
|
|
57117
|
+
__name(marketplaceDispatch, "marketplaceDispatch");
|
|
56582
57118
|
async function skillMarketplaceCommand(action, options = {}) {
|
|
56583
57119
|
const { config, apiKey } = await initializeCommand();
|
|
56584
57120
|
const marketplaceApi = new MarketplaceApiService(apiKey, config.agent?.orgId);
|
|
@@ -56735,7 +57271,7 @@ async function listSkillNonInteractive(marketplaceApi, config, apiKey, options)
|
|
|
56735
57271
|
writeProgress("\u{1F504} Verifying skill...");
|
|
56736
57272
|
const agentSkillsResponse = await skillApi.getSkills();
|
|
56737
57273
|
if (!agentSkillsResponse.success || !agentSkillsResponse.data) {
|
|
56738
|
-
throw CliError.fromStatus(agentSkillsResponse.error?.statusCode, `Failed to fetch agent skills: ${agentSkillsResponse.error?.message ?? agentSkillsResponse.message ?? "Unknown error"}
|
|
57274
|
+
throw CliError.fromStatus(agentSkillsResponse.error?.statusCode, `Failed to fetch agent skills: ${agentSkillsResponse.error?.message ?? agentSkillsResponse.message ?? "Unknown error"}`, void 0, apiErrorDetail(agentSkillsResponse.error));
|
|
56739
57275
|
}
|
|
56740
57276
|
const skill = agentSkillsResponse.data.skills?.find((s) => s.name === skillName);
|
|
56741
57277
|
if (!skill) {
|
|
@@ -64712,7 +65248,7 @@ Examples:
|
|
|
64712
65248
|
$ lua init --from-agent-id baseAgent_agent_xxx Duplicate agent + scaffold project
|
|
64713
65249
|
$ lua init --from-agent-id baseAgent_agent_xxx --org-id <id> Cross-org duplicate
|
|
64714
65250
|
`).action(initCommand);
|
|
64715
|
-
program2.command("compile").description("\u{1F4E6} Compile skill to deployable format").option("--verbose", "Show detailed progress output").option("--debug", "Enable debug mode with extra verbose logging and temp file preservation").option("--sync", "
|
|
65251
|
+
program2.command("compile").description("\u{1F4E6} Compile skill to deployable format").option("--verbose", "Show detailed progress output").option("--debug", "Enable debug mode with extra verbose logging and temp file preservation").option("--sync", "Check for drift against the server before compiling (reads only \u2014 nothing is written)").action((opts) => compileCommand({
|
|
64716
65252
|
...opts,
|
|
64717
65253
|
topLevel: true
|
|
64718
65254
|
}));
|