@eigenpal/cli 0.16.8 → 0.16.9
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/CHANGELOG.md +6 -0
- package/dist/cli.js +906 -256
- package/dist/docs-bundle.json +33 -12
- package/dist/skill/reference/cli/agents.md +41 -20
- package/dist/skill/reference/cli/reviews.md +154 -0
- package/dist/skill/reference/cli/surface.md +14 -0
- package/dist/skill/reference/cli/workflow.md +105 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7671,9 +7671,51 @@ var require_picocolors = __commonJS(function(exports, module) {
|
|
|
7671
7671
|
module.exports.createColors = createColors;
|
|
7672
7672
|
});
|
|
7673
7673
|
|
|
7674
|
+
// ../../node_modules/nanoid/index.js
|
|
7675
|
+
import { webcrypto as crypto } from "node:crypto";
|
|
7676
|
+
function fillPool(bytes) {
|
|
7677
|
+
if (!pool || pool.length < bytes) {
|
|
7678
|
+
pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER);
|
|
7679
|
+
crypto.getRandomValues(pool);
|
|
7680
|
+
poolOffset = 0;
|
|
7681
|
+
} else if (poolOffset + bytes > pool.length) {
|
|
7682
|
+
crypto.getRandomValues(pool);
|
|
7683
|
+
poolOffset = 0;
|
|
7684
|
+
}
|
|
7685
|
+
poolOffset += bytes;
|
|
7686
|
+
}
|
|
7687
|
+
function random(bytes) {
|
|
7688
|
+
fillPool(bytes |= 0);
|
|
7689
|
+
return pool.subarray(poolOffset - bytes, poolOffset);
|
|
7690
|
+
}
|
|
7691
|
+
function customRandom(alphabet, defaultSize, getRandom) {
|
|
7692
|
+
let mask = (2 << 31 - Math.clz32(alphabet.length - 1 | 1)) - 1;
|
|
7693
|
+
let step = Math.ceil(1.6 * mask * defaultSize / alphabet.length);
|
|
7694
|
+
return (size = defaultSize) => {
|
|
7695
|
+
if (!size)
|
|
7696
|
+
return "";
|
|
7697
|
+
let id = "";
|
|
7698
|
+
while (true) {
|
|
7699
|
+
let bytes = getRandom(step);
|
|
7700
|
+
let i = step;
|
|
7701
|
+
while (i--) {
|
|
7702
|
+
id += alphabet[bytes[i] & mask] || "";
|
|
7703
|
+
if (id.length >= size)
|
|
7704
|
+
return id;
|
|
7705
|
+
}
|
|
7706
|
+
}
|
|
7707
|
+
};
|
|
7708
|
+
}
|
|
7709
|
+
function customAlphabet(alphabet, size = 21) {
|
|
7710
|
+
return customRandom(alphabet, size, random);
|
|
7711
|
+
}
|
|
7712
|
+
var POOL_SIZE_MULTIPLIER = 128, pool, poolOffset;
|
|
7713
|
+
var init_nanoid = () => {};
|
|
7714
|
+
|
|
7674
7715
|
// ../types/src/core/common.ts
|
|
7675
|
-
var ID_PREFIXES, NANOID_SUFFIX_PATTERN = "[A-Za-z0-9_-]{21}", TemplateIdSchema, TemplateRevisionIdSchema, TimestampSchema, JsonSchemaSchema, BaseEntitySchema;
|
|
7716
|
+
var ID_PREFIXES, generateRandomId, NANOID_SUFFIX_PATTERN = "[A-Za-z0-9_-]{21}", TemplateIdSchema, TemplateRevisionIdSchema, TimestampSchema, JsonSchemaSchema, BaseEntitySchema;
|
|
7676
7717
|
var init_common = __esm(() => {
|
|
7718
|
+
init_nanoid();
|
|
7677
7719
|
init_zod();
|
|
7678
7720
|
ID_PREFIXES = {
|
|
7679
7721
|
WORKFLOW: "wf",
|
|
@@ -7731,6 +7773,7 @@ var init_common = __esm(() => {
|
|
|
7731
7773
|
OCR_JOB: "opj",
|
|
7732
7774
|
SANDBOX_WS_TOKEN: "sws"
|
|
7733
7775
|
};
|
|
7776
|
+
generateRandomId = customAlphabet("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 21);
|
|
7734
7777
|
TemplateIdSchema = string2().regex(new RegExp(`^${ID_PREFIXES.TEMPLATE}_${NANOID_SUFFIX_PATTERN}$`), "Expected tmpl_… id; file_… ids are not public template identities");
|
|
7735
7778
|
TemplateRevisionIdSchema = string2().regex(new RegExp(`^${ID_PREFIXES.TEMPLATE_REVISION}_${NANOID_SUFFIX_PATTERN}$`), "Expected tmpr_… id");
|
|
7736
7779
|
TimestampSchema = union([date3(), string2().datetime()]).transform((val2) => {
|
|
@@ -206235,7 +206278,7 @@ import { fileURLToPath as fileURLToPath8 } from "url";
|
|
|
206235
206278
|
// package.json
|
|
206236
206279
|
var package_default = {
|
|
206237
206280
|
name: "@eigenpal/cli",
|
|
206238
|
-
version: "0.16.
|
|
206281
|
+
version: "0.16.9",
|
|
206239
206282
|
description: "Eigenpal CLI — author and run document workflows from your terminal. Agent-ready.",
|
|
206240
206283
|
keywords: [
|
|
206241
206284
|
"eigenpal",
|
|
@@ -207042,6 +207085,47 @@ function resolveBaseUrlFromActionArgs(args) {
|
|
|
207042
207085
|
}
|
|
207043
207086
|
}
|
|
207044
207087
|
|
|
207088
|
+
// src/lib/non-interactive.ts
|
|
207089
|
+
import { createInterface } from "node:readline/promises";
|
|
207090
|
+
function isInteractiveStderr() {
|
|
207091
|
+
return Boolean(process.stdin.isTTY && process.stderr.isTTY);
|
|
207092
|
+
}
|
|
207093
|
+
function isInteractiveStdout() {
|
|
207094
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
207095
|
+
}
|
|
207096
|
+
function nonInteractiveYesRequired(action) {
|
|
207097
|
+
return `${action} requires --yes when run non-interactively (CI, pipes, or agent terminals without a TTY).`;
|
|
207098
|
+
}
|
|
207099
|
+
function requireYesInNonInteractive(yes, action) {
|
|
207100
|
+
if (yes || isInteractiveStderr())
|
|
207101
|
+
return;
|
|
207102
|
+
throw new Error(nonInteractiveYesRequired(action));
|
|
207103
|
+
}
|
|
207104
|
+
async function confirmTyped(id, actionName) {
|
|
207105
|
+
if (!isInteractiveStderr())
|
|
207106
|
+
return false;
|
|
207107
|
+
process.stderr.write(`
|
|
207108
|
+
${ui.warn("!")} About to ${actionName} for ${ui.bold(id)}.
|
|
207109
|
+
Type ${ui.bold(id)} to confirm: `);
|
|
207110
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
207111
|
+
try {
|
|
207112
|
+
return (await rl.question("")).trim() === id;
|
|
207113
|
+
} finally {
|
|
207114
|
+
rl.close();
|
|
207115
|
+
}
|
|
207116
|
+
}
|
|
207117
|
+
async function requireTypedConfirmation(opts) {
|
|
207118
|
+
if (opts.yes)
|
|
207119
|
+
return;
|
|
207120
|
+
if (!isInteractiveStderr()) {
|
|
207121
|
+
throw new Error(nonInteractiveYesRequired(`Typed confirmation to ${opts.actionName}`));
|
|
207122
|
+
}
|
|
207123
|
+
const ok = await confirmTyped(opts.id, opts.actionName);
|
|
207124
|
+
if (!ok) {
|
|
207125
|
+
throw new Error(opts.cancelledMessage ?? `${opts.actionName} aborted`);
|
|
207126
|
+
}
|
|
207127
|
+
}
|
|
207128
|
+
|
|
207045
207129
|
// src/commands/git/index.ts
|
|
207046
207130
|
init_src();
|
|
207047
207131
|
init_zod();
|
|
@@ -209049,6 +209133,27 @@ function registerGitCommands(program) {
|
|
|
209049
209133
|
credentialHelper.hidden = true;
|
|
209050
209134
|
}
|
|
209051
209135
|
|
|
209136
|
+
// src/commands/workflow/lifecycle-shared.ts
|
|
209137
|
+
function buildClient(opts) {
|
|
209138
|
+
const config = resolveConfig(opts);
|
|
209139
|
+
requireApiKey(config);
|
|
209140
|
+
return new ApiClient(config);
|
|
209141
|
+
}
|
|
209142
|
+
function printJson(value) {
|
|
209143
|
+
console.log(JSON.stringify(value, null, 2));
|
|
209144
|
+
}
|
|
209145
|
+
async function fetchAutomation(client, automationId) {
|
|
209146
|
+
return await client.get(`/v1/automations/${encodeURIComponent(automationId)}`);
|
|
209147
|
+
}
|
|
209148
|
+
function parseAutomationDeleteResult(result) {
|
|
209149
|
+
if (result == null)
|
|
209150
|
+
return { deleted: true };
|
|
209151
|
+
if (typeof result === "object" && result !== null && "deleted" in result) {
|
|
209152
|
+
return result;
|
|
209153
|
+
}
|
|
209154
|
+
return { deleted: true };
|
|
209155
|
+
}
|
|
209156
|
+
|
|
209052
209157
|
// ../../node_modules/fflate/esm/index.mjs
|
|
209053
209158
|
import { createRequire as createRequire2 } from "module";
|
|
209054
209159
|
var require2 = createRequire2("/");
|
|
@@ -209696,47 +209801,6 @@ function zipSync(data, opts) {
|
|
|
209696
209801
|
import { existsSync as existsSync8, promises as fs3 } from "node:fs";
|
|
209697
209802
|
import path8 from "node:path";
|
|
209698
209803
|
|
|
209699
|
-
// src/lib/non-interactive.ts
|
|
209700
|
-
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
209701
|
-
function isInteractiveStderr() {
|
|
209702
|
-
return Boolean(process.stdin.isTTY && process.stderr.isTTY);
|
|
209703
|
-
}
|
|
209704
|
-
function isInteractiveStdout() {
|
|
209705
|
-
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
209706
|
-
}
|
|
209707
|
-
function nonInteractiveYesRequired(action) {
|
|
209708
|
-
return `${action} requires --yes when run non-interactively (CI, pipes, or agent terminals without a TTY).`;
|
|
209709
|
-
}
|
|
209710
|
-
function requireYesInNonInteractive(yes, action) {
|
|
209711
|
-
if (yes || isInteractiveStderr())
|
|
209712
|
-
return;
|
|
209713
|
-
throw new Error(nonInteractiveYesRequired(action));
|
|
209714
|
-
}
|
|
209715
|
-
async function confirmTyped(id, actionName) {
|
|
209716
|
-
if (!isInteractiveStderr())
|
|
209717
|
-
return false;
|
|
209718
|
-
process.stderr.write(`
|
|
209719
|
-
${ui.warn("!")} About to ${actionName} for ${ui.bold(id)}.
|
|
209720
|
-
Type ${ui.bold(id)} to confirm: `);
|
|
209721
|
-
const rl = createInterface2({ input: process.stdin, output: process.stderr });
|
|
209722
|
-
try {
|
|
209723
|
-
return (await rl.question("")).trim() === id;
|
|
209724
|
-
} finally {
|
|
209725
|
-
rl.close();
|
|
209726
|
-
}
|
|
209727
|
-
}
|
|
209728
|
-
async function requireTypedConfirmation(opts) {
|
|
209729
|
-
if (opts.yes)
|
|
209730
|
-
return;
|
|
209731
|
-
if (!isInteractiveStderr()) {
|
|
209732
|
-
throw new Error(nonInteractiveYesRequired(`Typed confirmation to ${opts.actionName}`));
|
|
209733
|
-
}
|
|
209734
|
-
const ok = await confirmTyped(opts.id, opts.actionName);
|
|
209735
|
-
if (!ok) {
|
|
209736
|
-
throw new Error(opts.cancelledMessage ?? `${opts.actionName} aborted`);
|
|
209737
|
-
}
|
|
209738
|
-
}
|
|
209739
|
-
|
|
209740
209804
|
// src/commands/agents/shared.ts
|
|
209741
209805
|
init_src();
|
|
209742
209806
|
import { existsSync as existsSync6, promises as fs } from "node:fs";
|
|
@@ -209760,7 +209824,7 @@ function agentAutomationId(value) {
|
|
|
209760
209824
|
return value;
|
|
209761
209825
|
return `agents.${value}`;
|
|
209762
209826
|
}
|
|
209763
|
-
function
|
|
209827
|
+
function buildClient2(opts) {
|
|
209764
209828
|
const config = resolveConfig(opts);
|
|
209765
209829
|
requireApiKey(config);
|
|
209766
209830
|
return new ApiClient(config);
|
|
@@ -209780,7 +209844,7 @@ async function pollRun(client, executionId, interval, maxWait, json = false) {
|
|
|
209780
209844
|
}
|
|
209781
209845
|
if (Date.now() - started > maxWait * 1000) {
|
|
209782
209846
|
if (json)
|
|
209783
|
-
|
|
209847
|
+
printJson2(payload);
|
|
209784
209848
|
process.stderr.write(`Timed out waiting for run ${executionId}
|
|
209785
209849
|
`);
|
|
209786
209850
|
process.exit(2);
|
|
@@ -209808,7 +209872,7 @@ async function pollExperiment(client, automationId, batchId, interval, maxWait,
|
|
|
209808
209872
|
return payload;
|
|
209809
209873
|
if (Date.now() - started > maxWait * 1000) {
|
|
209810
209874
|
if (json)
|
|
209811
|
-
|
|
209875
|
+
printJson2(lastPayload ?? { batchId, status: "pending" });
|
|
209812
209876
|
process.stderr.write(`Timed out waiting for experiment ${batchId}
|
|
209813
209877
|
`);
|
|
209814
209878
|
process.exit(2);
|
|
@@ -209818,10 +209882,10 @@ async function pollExperiment(client, automationId, batchId, interval, maxWait,
|
|
|
209818
209882
|
}
|
|
209819
209883
|
function renderRunPayload(payload, opts) {
|
|
209820
209884
|
if (opts.json)
|
|
209821
|
-
return
|
|
209885
|
+
return printJson2(payload);
|
|
209822
209886
|
const run = payload;
|
|
209823
209887
|
if (!run || run.id === undefined)
|
|
209824
|
-
return
|
|
209888
|
+
return printJson2(payload);
|
|
209825
209889
|
const status = run.execution?.status ?? (run.finished === true ? "completed" : "running");
|
|
209826
209890
|
success(`Run ${run.id} is ${status}`);
|
|
209827
209891
|
}
|
|
@@ -209834,7 +209898,7 @@ function setExitCodeForFailedTerminalRun(payload) {
|
|
|
209834
209898
|
}
|
|
209835
209899
|
function renderGeneric(payload, opts, message) {
|
|
209836
209900
|
if (opts.json)
|
|
209837
|
-
return
|
|
209901
|
+
return printJson2(payload);
|
|
209838
209902
|
success(message);
|
|
209839
209903
|
}
|
|
209840
209904
|
function compactParams(opts) {
|
|
@@ -209846,7 +209910,7 @@ function compactParams(opts) {
|
|
|
209846
209910
|
}
|
|
209847
209911
|
return params;
|
|
209848
209912
|
}
|
|
209849
|
-
function
|
|
209913
|
+
function printJson2(value) {
|
|
209850
209914
|
console.log(JSON.stringify(value, null, 2));
|
|
209851
209915
|
}
|
|
209852
209916
|
function parseDatasetMode(value) {
|
|
@@ -210230,11 +210294,11 @@ Layout (mirrors the server import rules)
|
|
|
210230
210294
|
`).action(action(validateDatasetCommand));
|
|
210231
210295
|
}
|
|
210232
210296
|
async function listDataset(agentId, opts) {
|
|
210233
|
-
const client =
|
|
210297
|
+
const client = buildClient2(opts);
|
|
210234
210298
|
const payload = await client.get(`/v1/automations/${encodeURIComponent(agentAutomationId(agentId))}/examples`, compactParams(opts));
|
|
210235
210299
|
const examples = payload.data ?? [];
|
|
210236
210300
|
if (opts.json)
|
|
210237
|
-
return
|
|
210301
|
+
return printJson2(payload);
|
|
210238
210302
|
console.log(table(examples.map((row) => ({ id: row.id, name: row.name })), [
|
|
210239
210303
|
{ key: "id", header: "ID" },
|
|
210240
210304
|
{ key: "name", header: "NAME" }
|
|
@@ -210256,14 +210320,14 @@ async function pushDataset(agentId, opts) {
|
|
|
210256
210320
|
const form = new FormData;
|
|
210257
210321
|
form.set("file", new Blob([archive], { type: "application/zip" }), stat.isDirectory() ? "dataset.zip" : path8.basename(resolved));
|
|
210258
210322
|
form.set("mode", opts.mode);
|
|
210259
|
-
const client =
|
|
210323
|
+
const client = buildClient2(opts);
|
|
210260
210324
|
const payload = await client.postFormData(`/v1/automations/${encodeURIComponent(agentAutomationId(agentId))}/dataset/import`, form);
|
|
210261
210325
|
if (opts.json)
|
|
210262
|
-
return
|
|
210326
|
+
return printJson2(payload);
|
|
210263
210327
|
success(`${opts.mode === "replace" ? "Replaced" : "Uploaded"} dataset archive`);
|
|
210264
210328
|
}
|
|
210265
210329
|
async function pullDataset(agentId, opts) {
|
|
210266
|
-
const client =
|
|
210330
|
+
const client = buildClient2(opts);
|
|
210267
210331
|
const res = await client.getStream(`/v1/automations/${encodeURIComponent(agentAutomationId(agentId))}/dataset/export`);
|
|
210268
210332
|
const archive = Buffer.from(await res.arrayBuffer());
|
|
210269
210333
|
const out = path8.resolve(opts.out ?? DATASET_DIR);
|
|
@@ -210276,7 +210340,7 @@ async function validateDatasetCommand(dir = DATASET_DIR, opts) {
|
|
|
210276
210340
|
agentDir: path8.resolve(opts.agentDir ?? ".")
|
|
210277
210341
|
});
|
|
210278
210342
|
if (opts.json)
|
|
210279
|
-
return
|
|
210343
|
+
return printJson2(result);
|
|
210280
210344
|
if (result.valid)
|
|
210281
210345
|
return success("Dataset is valid");
|
|
210282
210346
|
for (const issue of result.errors)
|
|
@@ -210348,7 +210412,7 @@ async function pullAgentEnv(target, opts) {
|
|
|
210348
210412
|
if (format !== "shell" && format !== "dotenv") {
|
|
210349
210413
|
throw new Error("--format must be shell or dotenv");
|
|
210350
210414
|
}
|
|
210351
|
-
const client =
|
|
210415
|
+
const client = buildClient2(opts);
|
|
210352
210416
|
const requests = target ? await collectEncryptedSecretsForTarget(client, target) : await collectEncryptedSecrets(path9.resolve(opts.dir ?? "."));
|
|
210353
210417
|
if (requests.length === 0)
|
|
210354
210418
|
return;
|
|
@@ -211173,7 +211237,7 @@ function registerExperimentCommands(agent) {
|
|
|
211173
211237
|
addJsonFlag(withBaseUrl(experiment.command("cancel <agent-id-or-slug> <batch-id>"))).description("Cancel every active execution in an experiment.").option("--yes", "Skip confirmation (required in CI / agent terminals without a TTY)").action(action(cancelExperiment));
|
|
211174
211238
|
}
|
|
211175
211239
|
async function runExperiment(agentId, opts) {
|
|
211176
|
-
const client =
|
|
211240
|
+
const client = buildClient2(opts);
|
|
211177
211241
|
const automationId = agentAutomationId(agentId);
|
|
211178
211242
|
let payload = await client.post(`/v1/automations/${encodeURIComponent(automationId)}/experiments`, {
|
|
211179
211243
|
...opts.exampleId ? { examples: [opts.exampleId] } : {}
|
|
@@ -211197,7 +211261,7 @@ async function runExperiment(agentId, opts) {
|
|
|
211197
211261
|
}
|
|
211198
211262
|
}
|
|
211199
211263
|
async function experimentStatus(agentId, batchId, opts) {
|
|
211200
|
-
const client =
|
|
211264
|
+
const client = buildClient2(opts);
|
|
211201
211265
|
const automationId = agentAutomationId(agentId);
|
|
211202
211266
|
const payload = opts.watch ? await pollExperiment(client, automationId, batchId, opts.interval, opts.maxWait, opts.json) : await client.get(`/v1/automations/${encodeURIComponent(automationId)}/experiments/${encodeURIComponent(batchId)}`);
|
|
211203
211267
|
renderGeneric(payload, opts, `Experiment ${batchId}`);
|
|
@@ -211209,7 +211273,7 @@ async function experimentStatus(agentId, batchId, opts) {
|
|
|
211209
211273
|
}
|
|
211210
211274
|
}
|
|
211211
211275
|
async function experimentResults(agentId, batchId, opts) {
|
|
211212
|
-
const client =
|
|
211276
|
+
const client = buildClient2(opts);
|
|
211213
211277
|
const automationId = agentAutomationId(agentId);
|
|
211214
211278
|
if (opts.json && opts.format !== "json") {
|
|
211215
211279
|
throw new Error("--json cannot be combined with --format csv");
|
|
@@ -211257,7 +211321,7 @@ async function experimentResults(agentId, batchId, opts) {
|
|
|
211257
211321
|
}
|
|
211258
211322
|
}
|
|
211259
211323
|
async function listExperiments(agentId, opts) {
|
|
211260
|
-
const client =
|
|
211324
|
+
const client = buildClient2(opts);
|
|
211261
211325
|
const automationId = agentAutomationId(agentId);
|
|
211262
211326
|
const payload = await client.get(`/v1/automations/${encodeURIComponent(automationId)}/experiments`, compactParams(opts));
|
|
211263
211327
|
const experiments = payload.data ?? [];
|
|
@@ -211265,7 +211329,7 @@ async function listExperiments(agentId, opts) {
|
|
|
211265
211329
|
payload.data = experiments.filter((row) => row.id === opts.batchId || row.batchId === opts.batchId);
|
|
211266
211330
|
}
|
|
211267
211331
|
if (opts.json)
|
|
211268
|
-
return
|
|
211332
|
+
return printJson2(payload);
|
|
211269
211333
|
console.log(table(payload.data ?? experiments, [
|
|
211270
211334
|
{ key: "id", header: "EXPERIMENT" },
|
|
211271
211335
|
{ key: "runCount", header: "RUNS" }
|
|
@@ -211277,7 +211341,7 @@ async function compareExperiments(batchIdA, batchIdB, opts) {
|
|
|
211277
211341
|
if (!Number.isFinite(threshold) || threshold < 0) {
|
|
211278
211342
|
throw new Error("--regression-threshold must be a non-negative number");
|
|
211279
211343
|
}
|
|
211280
|
-
const client =
|
|
211344
|
+
const client = buildClient2(opts);
|
|
211281
211345
|
if (opts.outputs) {
|
|
211282
211346
|
const [outputsA, outputsB] = await Promise.all([
|
|
211283
211347
|
fetchExperimentOutputs(client, batchIdA),
|
|
@@ -211293,7 +211357,7 @@ async function compareExperiments(batchIdA, batchIdB, opts) {
|
|
|
211293
211357
|
rowsB: outputsB.rows
|
|
211294
211358
|
});
|
|
211295
211359
|
if (opts.json)
|
|
211296
|
-
return
|
|
211360
|
+
return printJson2(diff);
|
|
211297
211361
|
renderExperimentOutputDiffHuman(diff);
|
|
211298
211362
|
return;
|
|
211299
211363
|
}
|
|
@@ -211310,12 +211374,12 @@ async function compareExperiments(batchIdA, batchIdB, opts) {
|
|
|
211310
211374
|
regressionThreshold: threshold
|
|
211311
211375
|
});
|
|
211312
211376
|
if (opts.json)
|
|
211313
|
-
return
|
|
211377
|
+
return printJson2(diff);
|
|
211314
211378
|
renderBatchDiffHuman(diff);
|
|
211315
211379
|
}
|
|
211316
211380
|
async function cancelExperiment(agentId, batchId, opts) {
|
|
211317
211381
|
requireYesInNonInteractive(opts.yes, "Cancel experiment batch");
|
|
211318
|
-
const client =
|
|
211382
|
+
const client = buildClient2(opts);
|
|
211319
211383
|
const payload = await client.post(`/v1/automations/${encodeURIComponent(agentAutomationId(agentId))}/experiments/${encodeURIComponent(batchId)}/cancel`);
|
|
211320
211384
|
renderGeneric(payload, opts, `Cancelled experiment ${batchId}`);
|
|
211321
211385
|
}
|
|
@@ -211334,24 +211398,24 @@ function registerAgentFileCommands(agent) {
|
|
|
211334
211398
|
addJsonFlag(withBaseUrl(file.command("diff <agent-id-or-slug> <remote-path> <local-path>"))).description("Compare one live agent file against a local file.").action(action(diffAgentFile));
|
|
211335
211399
|
}
|
|
211336
211400
|
async function listAgentFiles(agentId, opts) {
|
|
211337
|
-
const client =
|
|
211401
|
+
const client = buildClient2(opts);
|
|
211338
211402
|
const packagePath = await resolveAgentPackagePath2(client, agentId);
|
|
211339
211403
|
const payload = await client.get("/v1/source/tree", {
|
|
211340
211404
|
packagePath,
|
|
211341
211405
|
...opts.path ? { prefix: normalizeAgentFilePath(opts.path, { allowEmpty: true }) } : {}
|
|
211342
211406
|
});
|
|
211343
211407
|
if (opts.json)
|
|
211344
|
-
return
|
|
211408
|
+
return printJson2(payload);
|
|
211345
211409
|
console.log(table((payload.files ?? []).map((name) => ({ name })), [{ key: "name", header: "PATH" }]));
|
|
211346
211410
|
}
|
|
211347
211411
|
async function getAgentFile(agentId, remotePath, opts) {
|
|
211348
211412
|
if (opts.json && opts.out) {
|
|
211349
211413
|
throw new Error("--json and --out are mutually exclusive");
|
|
211350
211414
|
}
|
|
211351
|
-
const client =
|
|
211415
|
+
const client = buildClient2(opts);
|
|
211352
211416
|
const payload = await readAgentFile(client, agentId, remotePath);
|
|
211353
211417
|
if (opts.json)
|
|
211354
|
-
return
|
|
211418
|
+
return printJson2(payload);
|
|
211355
211419
|
const out = path10.resolve(opts.out ?? payload.path);
|
|
211356
211420
|
await writeBase64File(out, payload.contentBase64);
|
|
211357
211421
|
success(`Downloaded ${payload.path} to ${ui.bold(out)}`);
|
|
@@ -211359,11 +211423,11 @@ async function getAgentFile(agentId, remotePath, opts) {
|
|
|
211359
211423
|
async function diffAgentFile(agentId, remotePath, localPath, opts) {
|
|
211360
211424
|
const report = await buildAgentFileDiff(agentId, remotePath, path10.resolve(localPath), opts);
|
|
211361
211425
|
if (opts.json)
|
|
211362
|
-
return
|
|
211426
|
+
return printJson2(report);
|
|
211363
211427
|
renderAgentFileDiff(report);
|
|
211364
211428
|
}
|
|
211365
211429
|
async function buildAgentFileDiff(agentId, remotePath, localPath, opts) {
|
|
211366
|
-
const client =
|
|
211430
|
+
const client = buildClient2(opts);
|
|
211367
211431
|
const local = await fs6.readFile(localPath);
|
|
211368
211432
|
let remote = null;
|
|
211369
211433
|
let serverPath = normalizeAgentFilePath(remotePath);
|
|
@@ -211471,10 +211535,10 @@ function registerSessionCommands(agent) {
|
|
|
211471
211535
|
addJsonFlag(withBaseUrl(session.command("stop <session-id>"))).description("Stop a builder session.").option("--yes", "Skip confirmation (required in CI / agent terminals without a TTY)").action(action(stopSession));
|
|
211472
211536
|
}
|
|
211473
211537
|
async function listSessions(agentId, opts) {
|
|
211474
|
-
const client =
|
|
211538
|
+
const client = buildClient2(opts);
|
|
211475
211539
|
const payload = await client.get(`/v1/agents/${encodeURIComponent(agentId)}/sessions`, compactParams(opts));
|
|
211476
211540
|
if (opts.json)
|
|
211477
|
-
return
|
|
211541
|
+
return printJson2(payload);
|
|
211478
211542
|
console.log(table(payload.sessions, [
|
|
211479
211543
|
{ key: "id", header: "ID" },
|
|
211480
211544
|
{ key: "status", header: "STATUS" },
|
|
@@ -211482,24 +211546,24 @@ async function listSessions(agentId, opts) {
|
|
|
211482
211546
|
]));
|
|
211483
211547
|
}
|
|
211484
211548
|
async function getSession(sessionId, opts) {
|
|
211485
|
-
const client =
|
|
211549
|
+
const client = buildClient2(opts);
|
|
211486
211550
|
renderGeneric(await client.get(`/v1/agents/sessions/${encodeURIComponent(sessionId)}`), opts, `Session ${sessionId}`);
|
|
211487
211551
|
}
|
|
211488
211552
|
async function startSession(agentId, opts) {
|
|
211489
|
-
const client =
|
|
211553
|
+
const client = buildClient2(opts);
|
|
211490
211554
|
renderGeneric(await client.post(`/v1/agents/${encodeURIComponent(agentId)}/sessions`, {
|
|
211491
211555
|
...opts.title ? { title: opts.title } : {}
|
|
211492
211556
|
}), opts, "Started session");
|
|
211493
211557
|
}
|
|
211494
211558
|
async function messageSession(sessionId, opts) {
|
|
211495
|
-
const client =
|
|
211559
|
+
const client = buildClient2(opts);
|
|
211496
211560
|
renderGeneric(await client.post(`/v1/agents/sessions/${encodeURIComponent(sessionId)}`, {
|
|
211497
211561
|
text: opts.text
|
|
211498
211562
|
}), opts, "Sent message");
|
|
211499
211563
|
}
|
|
211500
211564
|
async function stopSession(sessionId, opts) {
|
|
211501
211565
|
requireYesInNonInteractive(opts.yes, "Stop builder session");
|
|
211502
|
-
const client =
|
|
211566
|
+
const client = buildClient2(opts);
|
|
211503
211567
|
renderGeneric(await client.delete(`/v1/agents/sessions/${encodeURIComponent(sessionId)}`), opts, "Stopped session");
|
|
211504
211568
|
}
|
|
211505
211569
|
|
|
@@ -239676,7 +239740,7 @@ async function runExample(agentId, opts) {
|
|
|
239676
239740
|
if (opts.failOnMismatch && !opts.wait) {
|
|
239677
239741
|
throw new Error("--fail-on-mismatch requires --wait because the evaluator verdict is asynchronous");
|
|
239678
239742
|
}
|
|
239679
|
-
const client =
|
|
239743
|
+
const client = buildClient2(opts);
|
|
239680
239744
|
const started = await client.post(`/v1/automations/${encodeURIComponent(agentAutomationId(agentId))}/experiments`, {
|
|
239681
239745
|
examples: [opts.example],
|
|
239682
239746
|
...opts.sourceRef ? { sourceRef: opts.sourceRef } : {}
|
|
@@ -239722,7 +239786,7 @@ async function runExample(agentId, opts) {
|
|
|
239722
239786
|
status: "pending"
|
|
239723
239787
|
};
|
|
239724
239788
|
if (opts.json)
|
|
239725
|
-
return
|
|
239789
|
+
return printJson2(payload);
|
|
239726
239790
|
success(`Run ${runId ?? ""} queued for example ${opts.example}`);
|
|
239727
239791
|
}
|
|
239728
239792
|
async function waitForExampleEvalRollup(client, agentId, runId) {
|
|
@@ -239806,7 +239870,7 @@ function projectionIncludeSource(opts) {
|
|
|
239806
239870
|
return parts.length > 0 ? parts.join(",") : undefined;
|
|
239807
239871
|
}
|
|
239808
239872
|
async function getRun(executionId, opts) {
|
|
239809
|
-
const client =
|
|
239873
|
+
const client = buildClient2(opts);
|
|
239810
239874
|
const run = toLegacyRunView(await client.get(`/v1/runs/${encodeURIComponent(executionId)}`, {
|
|
239811
239875
|
expand: serverExpandParam({ expand: opts.expand, include: opts.include })
|
|
239812
239876
|
}));
|
|
@@ -239818,10 +239882,10 @@ async function getRun(executionId, opts) {
|
|
|
239818
239882
|
const projectionIncludes = workflowStepProjectionIncludes(projectionIncludeSource(opts));
|
|
239819
239883
|
const projectedRun = opts.step ? { ...run, stepExecutions: projectWorkflowSteps(steps, projectionIncludes) } : run;
|
|
239820
239884
|
if (opts.select) {
|
|
239821
|
-
return
|
|
239885
|
+
return printJson2(selectJsonValue(projectedRun, opts.select));
|
|
239822
239886
|
}
|
|
239823
239887
|
if (opts.json) {
|
|
239824
|
-
return
|
|
239888
|
+
return printJson2(projectedRun);
|
|
239825
239889
|
}
|
|
239826
239890
|
console.log(renderFrame(toExecutionSnapshot(projectedRun, executionId)));
|
|
239827
239891
|
process.stderr.write(`${ui.dim(`use --json for the full payload, then pipe to jq for field projection`)}
|
|
@@ -239829,7 +239893,7 @@ async function getRun(executionId, opts) {
|
|
|
239829
239893
|
return;
|
|
239830
239894
|
}
|
|
239831
239895
|
if (opts.select)
|
|
239832
|
-
return
|
|
239896
|
+
return printJson2(selectJsonValue(run, opts.select));
|
|
239833
239897
|
renderRunPayload(run, opts);
|
|
239834
239898
|
}
|
|
239835
239899
|
function isWorkflowRun(run) {
|
|
@@ -240010,7 +240074,7 @@ function previewOutput(value) {
|
|
|
240010
240074
|
return flat.length > PREVIEW_MAX ? `${flat.slice(0, PREVIEW_MAX - 3)}...` : flat;
|
|
240011
240075
|
}
|
|
240012
240076
|
async function rerunRun(executionId, opts) {
|
|
240013
|
-
const client =
|
|
240077
|
+
const client = buildClient2(opts);
|
|
240014
240078
|
const params = new URLSearchParams;
|
|
240015
240079
|
const version = (opts.sourceRef ?? opts.version)?.trim();
|
|
240016
240080
|
if (version && version !== "latest") {
|
|
@@ -240030,21 +240094,21 @@ async function rerunRun(executionId, opts) {
|
|
|
240030
240094
|
return;
|
|
240031
240095
|
}
|
|
240032
240096
|
if (opts.json)
|
|
240033
|
-
return
|
|
240097
|
+
return printJson2(payload);
|
|
240034
240098
|
success(`Started rerun ${ui.bold(rerunId)} from ${executionId}`);
|
|
240035
240099
|
}
|
|
240036
240100
|
async function promoteRun(executionId, opts) {
|
|
240037
|
-
const client =
|
|
240101
|
+
const client = buildClient2(opts);
|
|
240038
240102
|
const body = {};
|
|
240039
240103
|
if (opts.name)
|
|
240040
240104
|
body.name = opts.name;
|
|
240041
240105
|
const payload = await client.post(`/v1/runs/${encodeURIComponent(executionId)}/promote`, body);
|
|
240042
240106
|
if (opts.json)
|
|
240043
|
-
return
|
|
240107
|
+
return printJson2(payload);
|
|
240044
240108
|
success(`Promoted ${executionId} to example ${ui.bold(payload.name ?? payload.exampleId ?? "")}` + `${payload.automationId ? ` on ${payload.automationType ?? ""} ${payload.automationId}`.trimEnd() : ""}`);
|
|
240045
240109
|
}
|
|
240046
240110
|
async function fetchRunArtifacts(executionId, opts) {
|
|
240047
|
-
const client =
|
|
240111
|
+
const client = buildClient2(opts);
|
|
240048
240112
|
const baseRun = toLegacyRunView(await client.get(`/v1/runs/${encodeURIComponent(executionId)}`, {
|
|
240049
240113
|
expand: "input,execution"
|
|
240050
240114
|
}));
|
|
@@ -240077,7 +240141,7 @@ async function fetchRunArtifacts(executionId, opts) {
|
|
|
240077
240141
|
}
|
|
240078
240142
|
};
|
|
240079
240143
|
if (opts.json)
|
|
240080
|
-
return
|
|
240144
|
+
return printJson2(summary);
|
|
240081
240145
|
success(`Fetched run artifacts for ${executionId} to ${out}`);
|
|
240082
240146
|
dim(`Wrote ${written.length} artifact${written.length === 1 ? "" : "s"}${skipped.length ? `; skipped missing ${skipped.join(", ")}` : ""}`);
|
|
240083
240147
|
}
|
|
@@ -240112,7 +240176,7 @@ async function inspectRunArtifact(runId, artifactPathArg, opts) {
|
|
|
240112
240176
|
if (source.kind === "local") {
|
|
240113
240177
|
buffer = await fs15.readFile(source.path);
|
|
240114
240178
|
} else {
|
|
240115
|
-
const client =
|
|
240179
|
+
const client = buildClient2(opts);
|
|
240116
240180
|
const response = await client.getStream(`/v1/runs/${encodeURIComponent(source.runId)}/artifacts/${encodeRunArtifactPath(source.artifactPath)}`);
|
|
240117
240181
|
buffer = Buffer.from(await response.arrayBuffer());
|
|
240118
240182
|
}
|
|
@@ -240121,13 +240185,13 @@ async function inspectRunArtifact(runId, artifactPathArg, opts) {
|
|
|
240121
240185
|
...source.kind === "local" ? { file: source.path } : { runId: source.runId, artifactPath: source.artifactPath },
|
|
240122
240186
|
...inspect
|
|
240123
240187
|
};
|
|
240124
|
-
|
|
240188
|
+
printJson2(payload);
|
|
240125
240189
|
}
|
|
240126
240190
|
async function listRunArtifacts(executionId, opts) {
|
|
240127
|
-
const client =
|
|
240191
|
+
const client = buildClient2(opts);
|
|
240128
240192
|
const artifacts = await listCanonicalRunArtifacts(client, executionId);
|
|
240129
240193
|
if (opts.json)
|
|
240130
|
-
return
|
|
240194
|
+
return printJson2({ runId: executionId, artifacts });
|
|
240131
240195
|
console.log(table(artifacts, [
|
|
240132
240196
|
{ key: "kind", header: "KIND" },
|
|
240133
240197
|
{ key: "name", header: "NAME" },
|
|
@@ -240238,7 +240302,7 @@ async function writeRunArtifact(client, executionId, out, artifactPath, run) {
|
|
|
240238
240302
|
return artifactPath;
|
|
240239
240303
|
}
|
|
240240
240304
|
async function traceRun(executionId, opts) {
|
|
240241
|
-
const client =
|
|
240305
|
+
const client = buildClient2(opts);
|
|
240242
240306
|
const text = await downloadTraceText(client, executionId);
|
|
240243
240307
|
if (text.length === 0) {
|
|
240244
240308
|
warn(`No trace events recorded for run ${executionId}.`);
|
|
@@ -240253,7 +240317,7 @@ async function traceRun(executionId, opts) {
|
|
|
240253
240317
|
success(`Downloaded trace for ${executionId} to ${ui.bold(out)}`);
|
|
240254
240318
|
}
|
|
240255
240319
|
async function compareRun(referenceId, executionId, opts) {
|
|
240256
|
-
const client =
|
|
240320
|
+
const client = buildClient2(opts);
|
|
240257
240321
|
const target = toLegacyRunView(await client.get(`/v1/runs/${encodeURIComponent(executionId)}`, {
|
|
240258
240322
|
expand: "execution"
|
|
240259
240323
|
}));
|
|
@@ -240264,7 +240328,7 @@ async function compareRun(referenceId, executionId, opts) {
|
|
|
240264
240328
|
if (isWorkflowRun(reference) && isWorkflowRun(target)) {
|
|
240265
240329
|
const report = compareWorkflowRuns(referenceId, reference, executionId, target, opts.step);
|
|
240266
240330
|
if (opts.json) {
|
|
240267
|
-
|
|
240331
|
+
printJson2(report);
|
|
240268
240332
|
} else {
|
|
240269
240333
|
renderWorkflowComparisonReport(report);
|
|
240270
240334
|
}
|
|
@@ -240303,7 +240367,7 @@ async function compareRun(referenceId, executionId, opts) {
|
|
|
240303
240367
|
};
|
|
240304
240368
|
await fs15.writeFile(path15.join(out, "comparison.json"), JSON.stringify(report, null, 2));
|
|
240305
240369
|
if (opts.json) {
|
|
240306
|
-
|
|
240370
|
+
printJson2(report);
|
|
240307
240371
|
} else {
|
|
240308
240372
|
renderComparisonReport(report);
|
|
240309
240373
|
}
|
|
@@ -240420,7 +240484,7 @@ function compareOutputs(reference, target) {
|
|
|
240420
240484
|
return `differs (A=${referenceJson.length}b, B=${targetJson.length}b)`;
|
|
240421
240485
|
}
|
|
240422
240486
|
async function listRuns(source, opts) {
|
|
240423
|
-
const client =
|
|
240487
|
+
const client = buildClient2(opts);
|
|
240424
240488
|
const parsedAgentTarget = source && (opts.type === "agent" || source.startsWith("agents.") || source.includes("@")) ? parseAgentTarget(source) : null;
|
|
240425
240489
|
const resolvedWorkflowSource = source && opts.type === "workflow" ? await resolveWorkflowId(client, source) : undefined;
|
|
240426
240490
|
const params = {
|
|
@@ -240431,7 +240495,7 @@ async function listRuns(source, opts) {
|
|
|
240431
240495
|
const payload = await client.get("/v1/runs", params);
|
|
240432
240496
|
const viewRuns = payload.runs.map(toLegacyRunView);
|
|
240433
240497
|
if (opts.json)
|
|
240434
|
-
return
|
|
240498
|
+
return printJson2({ ...payload, runs: viewRuns });
|
|
240435
240499
|
const rows = opts.compact ? viewRuns.map(compactRunRow) : viewRuns;
|
|
240436
240500
|
if (payload.scanLimited)
|
|
240437
240501
|
warn("Filtered run list scanned only the first matching window.");
|
|
@@ -240476,7 +240540,7 @@ function buildRunListParams(opts) {
|
|
|
240476
240540
|
});
|
|
240477
240541
|
}
|
|
240478
240542
|
async function updateRunReview(executionId, opts) {
|
|
240479
|
-
const client =
|
|
240543
|
+
const client = buildClient2(opts);
|
|
240480
240544
|
const body = {};
|
|
240481
240545
|
if (opts.status)
|
|
240482
240546
|
body.status = opts.status;
|
|
@@ -240498,7 +240562,7 @@ async function updateRunReview(executionId, opts) {
|
|
|
240498
240562
|
renderGeneric(payload, opts, `Updated review for ${executionId}`);
|
|
240499
240563
|
}
|
|
240500
240564
|
async function closeRunReview(executionId, opts) {
|
|
240501
|
-
const client =
|
|
240565
|
+
const client = buildClient2(opts);
|
|
240502
240566
|
const body = { status: opts.status ?? "closed" };
|
|
240503
240567
|
if (opts.noteFile)
|
|
240504
240568
|
body.note = await fs15.readFile(opts.noteFile, "utf-8");
|
|
@@ -240531,7 +240595,7 @@ async function clearRunReview(executionId, opts) {
|
|
|
240531
240595
|
actionName: "clear review artifacts",
|
|
240532
240596
|
cancelledMessage: "Clear cancelled"
|
|
240533
240597
|
});
|
|
240534
|
-
const client =
|
|
240598
|
+
const client = buildClient2(opts);
|
|
240535
240599
|
const payload = await client.delete(`/v1/runs/${encodeURIComponent(executionId)}/reviews`);
|
|
240536
240600
|
renderGeneric(payload, opts, `Cleared review for ${executionId}`);
|
|
240537
240601
|
}
|
|
@@ -240545,16 +240609,16 @@ async function readRunExpected(client, executionId) {
|
|
|
240545
240609
|
};
|
|
240546
240610
|
}
|
|
240547
240611
|
async function listRunExpected(executionId, opts) {
|
|
240548
|
-
const client =
|
|
240612
|
+
const client = buildClient2(opts);
|
|
240549
240613
|
const payload = await readRunExpected(client, executionId);
|
|
240550
240614
|
if (opts.json)
|
|
240551
|
-
return
|
|
240615
|
+
return printJson2(payload);
|
|
240552
240616
|
console.log(table(payload.files, [{ key: "name", header: "NAME" }]));
|
|
240553
240617
|
if (payload.expected != null)
|
|
240554
240618
|
dim("expected.json present");
|
|
240555
240619
|
}
|
|
240556
240620
|
async function pullRunExpected(executionId, opts) {
|
|
240557
|
-
const client =
|
|
240621
|
+
const client = buildClient2(opts);
|
|
240558
240622
|
const payload = await readRunExpected(client, executionId);
|
|
240559
240623
|
const out = path15.resolve(opts.out ?? path15.join(executionId, "expected"));
|
|
240560
240624
|
await fs15.mkdir(out, { recursive: true });
|
|
@@ -240578,7 +240642,7 @@ async function downloadExpectedFiles(client, executionId, out, files) {
|
|
|
240578
240642
|
return written.filter((name) => Boolean(name));
|
|
240579
240643
|
}
|
|
240580
240644
|
async function uploadRunExpected(executionId, file, opts) {
|
|
240581
|
-
const client =
|
|
240645
|
+
const client = buildClient2(opts);
|
|
240582
240646
|
const form = new FormData;
|
|
240583
240647
|
const data = await fs15.readFile(file);
|
|
240584
240648
|
form.append("file", new Blob([data]), path15.basename(file));
|
|
@@ -240588,7 +240652,7 @@ async function uploadRunExpected(executionId, file, opts) {
|
|
|
240588
240652
|
renderGeneric(payload, opts, `Uploaded expected file for ${executionId}`);
|
|
240589
240653
|
}
|
|
240590
240654
|
async function copyOutputToExpected(executionId, outputFile, opts) {
|
|
240591
|
-
const client =
|
|
240655
|
+
const client = buildClient2(opts);
|
|
240592
240656
|
const payload = await client.post(`/v1/runs/${encodeURIComponent(executionId)}/reviews/expected`, {
|
|
240593
240657
|
outputFileName: outputFile,
|
|
240594
240658
|
...opts.name ? { expectedName: opts.name } : {}
|
|
@@ -240596,7 +240660,7 @@ async function copyOutputToExpected(executionId, outputFile, opts) {
|
|
|
240596
240660
|
renderGeneric(payload, opts, `Copied output file to expected for ${executionId}`);
|
|
240597
240661
|
}
|
|
240598
240662
|
async function renameRunExpected(executionId, oldName, newName, opts) {
|
|
240599
|
-
const client =
|
|
240663
|
+
const client = buildClient2(opts);
|
|
240600
240664
|
const payload = await client.patch(`/v1/runs/${encodeURIComponent(executionId)}/reviews/expected/${encodeURIComponent(oldName)}`, { name: newName });
|
|
240601
240665
|
renderGeneric(payload, opts, `Renamed expected file for ${executionId}`);
|
|
240602
240666
|
}
|
|
@@ -240607,12 +240671,12 @@ async function deleteRunExpected(executionId, name, opts) {
|
|
|
240607
240671
|
actionName: "delete expected file",
|
|
240608
240672
|
cancelledMessage: "Delete cancelled"
|
|
240609
240673
|
});
|
|
240610
|
-
const client =
|
|
240674
|
+
const client = buildClient2(opts);
|
|
240611
240675
|
await client.delete(`/v1/runs/${encodeURIComponent(executionId)}/reviews/expected/${encodeURIComponent(name)}`);
|
|
240612
240676
|
renderGeneric({ ok: true }, opts, `Deleted expected file ${name}`);
|
|
240613
240677
|
}
|
|
240614
240678
|
async function watchRunCommand(executionId, opts) {
|
|
240615
|
-
const client =
|
|
240679
|
+
const client = buildClient2(opts);
|
|
240616
240680
|
if (opts.json) {
|
|
240617
240681
|
const payload = await pollRun(client, executionId, opts.interval, opts.maxWait, opts.json);
|
|
240618
240682
|
renderRunPayload(payload, opts);
|
|
@@ -240642,10 +240706,10 @@ Detached after ${opts.maxWait}s without reaching terminal status. Re-run \`eigen
|
|
|
240642
240706
|
}
|
|
240643
240707
|
async function cancelRun(executionId, opts) {
|
|
240644
240708
|
requireYesInNonInteractive(opts.yes, "Cancel run");
|
|
240645
|
-
const client =
|
|
240709
|
+
const client = buildClient2(opts);
|
|
240646
240710
|
const payload = await client.post(`/v1/runs/${encodeURIComponent(executionId)}/cancel`, {});
|
|
240647
240711
|
if (opts.json) {
|
|
240648
|
-
|
|
240712
|
+
printJson2(payload);
|
|
240649
240713
|
return;
|
|
240650
240714
|
}
|
|
240651
240715
|
success(`Cancellation requested for run ${executionId}.`);
|
|
@@ -240906,6 +240970,14 @@ function registerAgentCommands(program) {
|
|
|
240906
240970
|
process.exit(2);
|
|
240907
240971
|
});
|
|
240908
240972
|
addJsonFlag(withPagination(withBaseUrl(agent.command("list")), 50)).description("List agents.").option("--search <q>", "Search by slug, name, or description").action(action(listAgents));
|
|
240973
|
+
addJsonFlag(withBaseUrl(agent.command("delete <agent-id-or-slug>"))).description("Delete an agent and its versions from the server.").option("--yes", "Skip typed-id confirmation (required in CI / agent terminals without a TTY)").addHelpText("after", `
|
|
240974
|
+
Permanently deletes the agent implementation, versions, and builder sessions.
|
|
240975
|
+
Unified prior runs remain in run history. This matches Studio agent deletion and
|
|
240976
|
+
cannot be undone.
|
|
240977
|
+
|
|
240978
|
+
Pass \`--yes\` in scripts, CI, and agent terminals (non-TTY). In a TTY, type the
|
|
240979
|
+
agent id (for example \`agents.invoice\`) to confirm.
|
|
240980
|
+
`).action(action(deleteAgent));
|
|
240909
240981
|
registerAgentFileCommands(agent);
|
|
240910
240982
|
addJsonFlag(agent.command("validate [dir]")).description("Validate a local agent package (layout, manifest, schemas, and Git source rules).").action(action(validateAgentCommand));
|
|
240911
240983
|
registerAgentSourceCommands(agent);
|
|
@@ -240915,14 +240987,40 @@ function registerAgentCommands(program) {
|
|
|
240915
240987
|
registerEnvCommands(agent);
|
|
240916
240988
|
registerSecretsExportCommands(agent);
|
|
240917
240989
|
}
|
|
240990
|
+
async function deleteAgent(agentRef, opts) {
|
|
240991
|
+
requireYesInNonInteractive(opts.yes, "delete agent");
|
|
240992
|
+
const automationId = agentAutomationId(agentRef);
|
|
240993
|
+
const client = buildClient2(opts);
|
|
240994
|
+
const automation = await fetchAutomation(client, automationId);
|
|
240995
|
+
if (automation.type != null && automation.type !== "agent") {
|
|
240996
|
+
throw new Error(`${automationId} is a workflow, not an agent. Use \`eigenpal workflow delete\` instead.`);
|
|
240997
|
+
}
|
|
240998
|
+
const confirmId = automationId;
|
|
240999
|
+
const label = automation.name ?? automation.slug ?? confirmId;
|
|
241000
|
+
warn(`This permanently deletes the agent "${label}", its versions, and builder sessions. Unified prior runs remain in run history. This cannot be undone.`);
|
|
241001
|
+
if (!opts.yes && isInteractiveStderr()) {
|
|
241002
|
+
await requireTypedConfirmation({
|
|
241003
|
+
id: confirmId,
|
|
241004
|
+
actionName: "delete agent",
|
|
241005
|
+
cancelledMessage: "Agent delete aborted"
|
|
241006
|
+
});
|
|
241007
|
+
}
|
|
241008
|
+
const result = await client.delete(`/v1/automations/${encodeURIComponent(automationId)}`);
|
|
241009
|
+
const parsed = parseAutomationDeleteResult(result);
|
|
241010
|
+
if (opts.json) {
|
|
241011
|
+
printJson2({ ...parsed, id: automationId, slug: automation.slug ?? null });
|
|
241012
|
+
return;
|
|
241013
|
+
}
|
|
241014
|
+
success(`Deleted agent ${ui.bold(label)} ${ui.dim(`(${automationId})`)}`);
|
|
241015
|
+
}
|
|
240918
241016
|
async function listAgents(opts) {
|
|
240919
|
-
const client =
|
|
241017
|
+
const client = buildClient2(opts);
|
|
240920
241018
|
const payload = await client.get("/v1/automations", {
|
|
240921
241019
|
...compactParams(opts),
|
|
240922
241020
|
type: "agent"
|
|
240923
241021
|
});
|
|
240924
241022
|
if (opts.json)
|
|
240925
|
-
return
|
|
241023
|
+
return printJson2(payload);
|
|
240926
241024
|
console.log(table(payload.data, [
|
|
240927
241025
|
{ key: "slug", header: "SLUG" },
|
|
240928
241026
|
{ key: "name", header: "NAME" },
|
|
@@ -240944,7 +241042,7 @@ async function validateAgentCommand(dir = ".", opts) {
|
|
|
240944
241042
|
}
|
|
240945
241043
|
}
|
|
240946
241044
|
if (opts.json) {
|
|
240947
|
-
|
|
241045
|
+
printJson2(result);
|
|
240948
241046
|
if (!result.valid)
|
|
240949
241047
|
process.exit(1);
|
|
240950
241048
|
return;
|
|
@@ -241473,7 +241571,7 @@ function registerDocsCommands(program) {
|
|
|
241473
241571
|
addJsonFlag(command.command("list [prefix]")).description("List bundled documentation topics, optionally under a path prefix.").option("--source <source>", "Filter by public, agent-reference, or api").action(action(async (prefix, opts) => {
|
|
241474
241572
|
const results = listDocs(prefix, opts.source);
|
|
241475
241573
|
if (opts.json) {
|
|
241476
|
-
|
|
241574
|
+
printJson2(results.map(({ content: _content, ...doc }) => doc));
|
|
241477
241575
|
return;
|
|
241478
241576
|
}
|
|
241479
241577
|
console.log(table(results, [
|
|
@@ -241485,7 +241583,7 @@ function registerDocsCommands(program) {
|
|
|
241485
241583
|
addJsonFlag(command.command("search <query>")).description("Search every public page and detailed agent reference.").option("--limit <n>", "Maximum matches", intArg, 20).action(action(async (query, opts) => {
|
|
241486
241584
|
const results = searchDocs(query, opts.limit);
|
|
241487
241585
|
if (opts.json) {
|
|
241488
|
-
|
|
241586
|
+
printJson2(results.map(({ content: _content, ...doc }) => doc));
|
|
241489
241587
|
return;
|
|
241490
241588
|
}
|
|
241491
241589
|
console.log(table(results.map((doc) => ({ ...doc, match: doc.snippet || doc.description })), [
|
|
@@ -241497,7 +241595,7 @@ function registerDocsCommands(program) {
|
|
|
241497
241595
|
addJsonFlag(command.command("read <topic>")).description("Print one bundled documentation topic to stdout.").action(action(async (topic, opts) => {
|
|
241498
241596
|
const doc = resolveDoc(topic);
|
|
241499
241597
|
if (opts.json) {
|
|
241500
|
-
|
|
241598
|
+
printJson2(doc);
|
|
241501
241599
|
return;
|
|
241502
241600
|
}
|
|
241503
241601
|
process.stdout.write(doc.content.endsWith(`
|
|
@@ -241865,12 +241963,12 @@ var LIST_COLUMNS = [
|
|
|
241865
241963
|
format: (value) => formatTimestamp(value)
|
|
241866
241964
|
}
|
|
241867
241965
|
];
|
|
241868
|
-
function
|
|
241966
|
+
function buildClient3(opts) {
|
|
241869
241967
|
const config = resolveConfig(opts);
|
|
241870
241968
|
requireApiKey(config);
|
|
241871
241969
|
return new ApiClient(config);
|
|
241872
241970
|
}
|
|
241873
|
-
function
|
|
241971
|
+
function printJson3(value) {
|
|
241874
241972
|
console.log(JSON.stringify(value, null, 2));
|
|
241875
241973
|
}
|
|
241876
241974
|
function sharedCreateOptions(cmd) {
|
|
@@ -241902,7 +242000,7 @@ function registerEmailServersCommands(program) {
|
|
|
241902
242000
|
const emailServers = program.command("email-servers").alias("email-server").description("Manage outbound email servers (ems_…): list, inspect, create, update, delete, and send a real test message.").addHelpText("after", EMAIL_SERVERS_EXAMPLES);
|
|
241903
242001
|
const listCmd = emailServers.command("list").description("List outbound email servers for the current workspace.");
|
|
241904
242002
|
addJsonFlag(withBaseUrl(withPagination(listCmd))).action(action(async (opts) => {
|
|
241905
|
-
const client =
|
|
242003
|
+
const client = buildClient3(opts);
|
|
241906
242004
|
const raw = await client.get(apiPath("/email-servers"), {
|
|
241907
242005
|
limit: String(opts.limit),
|
|
241908
242006
|
offset: String(opts.offset)
|
|
@@ -241914,11 +242012,11 @@ function registerEmailServersCommands(program) {
|
|
|
241914
242012
|
}));
|
|
241915
242013
|
const getCmd = emailServers.command("get <id>").description("Inspect one email server. Human output is redacted even if the API regresses.");
|
|
241916
242014
|
addJsonFlag(withBaseUrl(getCmd)).action(action(async (id, opts) => {
|
|
241917
|
-
const client =
|
|
242015
|
+
const client = buildClient3(opts);
|
|
241918
242016
|
const raw = await client.get(apiPath(`/email-servers/${encodeURIComponent(id)}`));
|
|
241919
242017
|
const redacted = redactEmailServerPayload(raw);
|
|
241920
242018
|
if (opts.json) {
|
|
241921
|
-
|
|
242019
|
+
printJson3(redacted);
|
|
241922
242020
|
return;
|
|
241923
242021
|
}
|
|
241924
242022
|
console.log(formatEmailServerHuman(redacted));
|
|
@@ -241926,11 +242024,11 @@ function registerEmailServersCommands(program) {
|
|
|
241926
242024
|
const createCmd = emailServers.command("create").description("Create an outbound email server. Resend requires an API key; SMTP accepts optional username/password except with --security none, plus optional CA PEM, and defaults to starttls on port 587.");
|
|
241927
242025
|
addJsonFlag(withBaseUrl(sharedCreateOptions(createCmd))).action(action(async (opts) => {
|
|
241928
242026
|
const body = await buildCreateRequest(opts);
|
|
241929
|
-
const client =
|
|
242027
|
+
const client = buildClient3(opts);
|
|
241930
242028
|
const created = await client.post(apiPath("/email-servers"), body);
|
|
241931
242029
|
const redacted = redactEmailServerPayload(created);
|
|
241932
242030
|
if (opts.json) {
|
|
241933
|
-
|
|
242031
|
+
printJson3(redacted);
|
|
241934
242032
|
return;
|
|
241935
242033
|
}
|
|
241936
242034
|
success(`Created ${ui.bold(redacted.id)} (${redacted.transport})`);
|
|
@@ -241938,13 +242036,13 @@ function registerEmailServersCommands(program) {
|
|
|
241938
242036
|
}));
|
|
241939
242037
|
const updateCmd = emailServers.command("update <id>").description("Update metadata or replace transport configuration. Omitted secrets are retained. Passing --transport smtp requires --host, --port, --security, --from-email, and --from-name (no security/port defaults). Metadata-only updates omit --transport.");
|
|
241940
242038
|
addJsonFlag(withBaseUrl(sharedUpdateOptions(updateCmd))).action(action(async (id, opts) => {
|
|
241941
|
-
const client =
|
|
242039
|
+
const client = buildClient3(opts);
|
|
241942
242040
|
const existing = await client.get(apiPath(`/email-servers/${encodeURIComponent(id)}`));
|
|
241943
242041
|
const body = await buildUpdateRequest({ existing, opts });
|
|
241944
242042
|
const updated = await client.patch(apiPath(`/email-servers/${encodeURIComponent(id)}`), body);
|
|
241945
242043
|
const redacted = redactEmailServerPayload(updated);
|
|
241946
242044
|
if (opts.json) {
|
|
241947
|
-
|
|
242045
|
+
printJson3(redacted);
|
|
241948
242046
|
return;
|
|
241949
242047
|
}
|
|
241950
242048
|
success(`Updated ${ui.bold(redacted.id)}`);
|
|
@@ -241955,22 +242053,22 @@ function registerEmailServersCommands(program) {
|
|
|
241955
242053
|
if (!opts.yes && !process.stdout.isTTY) {
|
|
241956
242054
|
throw new Error("email-servers delete is destructive and requires --yes when run non-interactively");
|
|
241957
242055
|
}
|
|
241958
|
-
const client =
|
|
242056
|
+
const client = buildClient3(opts);
|
|
241959
242057
|
const result = await client.delete(apiPath(`/email-servers/${encodeURIComponent(id)}`));
|
|
241960
242058
|
if (opts.json) {
|
|
241961
|
-
|
|
242059
|
+
printJson3(result);
|
|
241962
242060
|
return;
|
|
241963
242061
|
}
|
|
241964
242062
|
success(`Deleted ${ui.bold(id)}`);
|
|
241965
242063
|
}));
|
|
241966
242064
|
const testCmd = emailServers.command("test <id>").description("Send a real connectivity test email through the stored server to --to. Disabled servers fail with a conflict.").requiredOption("--to <email>", "Recipient for the live test message");
|
|
241967
242065
|
addJsonFlag(withBaseUrl(testCmd)).action(action(async (id, opts) => {
|
|
241968
|
-
const client =
|
|
242066
|
+
const client = buildClient3(opts);
|
|
241969
242067
|
const result = await client.post(apiPath(`/email-servers/${encodeURIComponent(id)}/test`), {
|
|
241970
242068
|
to: opts.to
|
|
241971
242069
|
});
|
|
241972
242070
|
if (opts.json) {
|
|
241973
|
-
|
|
242071
|
+
printJson3(result);
|
|
241974
242072
|
if (!result.ok)
|
|
241975
242073
|
process.exit(1);
|
|
241976
242074
|
return;
|
|
@@ -242173,56 +242271,8 @@ Examples:
|
|
|
242173
242271
|
}));
|
|
242174
242272
|
}
|
|
242175
242273
|
|
|
242176
|
-
// src/commands/
|
|
242177
|
-
init_src();
|
|
242178
|
-
|
|
242179
|
-
// src/commands/run-form-data.ts
|
|
242274
|
+
// src/commands/reviews.ts
|
|
242180
242275
|
import { promises as fs16 } from "node:fs";
|
|
242181
|
-
import path18 from "node:path";
|
|
242182
|
-
|
|
242183
|
-
// src/lib/upload-limits.ts
|
|
242184
|
-
var DEFAULT_MULTIPART_MAX_BYTES = Math.floor(4.5 * 1024 * 1024);
|
|
242185
|
-
var MULTIPART_ENVELOPE_HEADROOM_BYTES = 256 * 1024;
|
|
242186
|
-
function multipartFileByteBudget(multipartMaxBytes = multipartMaxBytesFromEnv()) {
|
|
242187
|
-
if (multipartMaxBytes === null)
|
|
242188
|
-
return null;
|
|
242189
|
-
return Math.max(0, multipartMaxBytes - MULTIPART_ENVELOPE_HEADROOM_BYTES);
|
|
242190
|
-
}
|
|
242191
|
-
function indicesRequiringPreUpload(files, multipartMaxBytes = multipartMaxBytesFromEnv()) {
|
|
242192
|
-
const budget = multipartFileByteBudget(multipartMaxBytes);
|
|
242193
|
-
const toPreUpload = new Set;
|
|
242194
|
-
if (budget === null)
|
|
242195
|
-
return toPreUpload;
|
|
242196
|
-
files.forEach((file, index) => {
|
|
242197
|
-
if (file.size > budget) {
|
|
242198
|
-
toPreUpload.add(index);
|
|
242199
|
-
}
|
|
242200
|
-
});
|
|
242201
|
-
let multipartTotal = 0;
|
|
242202
|
-
files.forEach((file, index) => {
|
|
242203
|
-
if (!toPreUpload.has(index))
|
|
242204
|
-
multipartTotal += file.size;
|
|
242205
|
-
});
|
|
242206
|
-
const candidates = files.map((file, index) => ({ file, index })).filter(({ index }) => !toPreUpload.has(index)).slice().sort((a, b) => b.file.size - a.file.size || a.index - b.index);
|
|
242207
|
-
for (const { file, index } of candidates) {
|
|
242208
|
-
if (multipartTotal <= budget)
|
|
242209
|
-
break;
|
|
242210
|
-
toPreUpload.add(index);
|
|
242211
|
-
multipartTotal -= file.size;
|
|
242212
|
-
}
|
|
242213
|
-
return toPreUpload;
|
|
242214
|
-
}
|
|
242215
|
-
function multipartMaxBytesFromEnv(raw = env.EIGENPAL_MULTIPART_MAX_BYTES) {
|
|
242216
|
-
if (raw == null || raw.trim() === "")
|
|
242217
|
-
return DEFAULT_MULTIPART_MAX_BYTES;
|
|
242218
|
-
const normalized = raw.trim().toLowerCase();
|
|
242219
|
-
if (normalized === "none" || normalized === "null" || normalized === "unlimited")
|
|
242220
|
-
return null;
|
|
242221
|
-
const parsed = Number(normalized);
|
|
242222
|
-
if (Number.isSafeInteger(parsed) && parsed >= 0)
|
|
242223
|
-
return parsed;
|
|
242224
|
-
throw new Error("EIGENPAL_MULTIPART_MAX_BYTES must be a non-negative integer or one of: none, null, unlimited.");
|
|
242225
|
-
}
|
|
242226
242276
|
|
|
242227
242277
|
// src/lib/upload-reusable-file.ts
|
|
242228
242278
|
import { randomUUID } from "node:crypto";
|
|
@@ -242604,6 +242654,306 @@ async function readWholeFile(filePath) {
|
|
|
242604
242654
|
return readFile(filePath);
|
|
242605
242655
|
}
|
|
242606
242656
|
|
|
242657
|
+
// src/lib/reviews-cli.ts
|
|
242658
|
+
var REVIEW_LIST_COLUMNS = [
|
|
242659
|
+
{ key: "id", header: "ID" },
|
|
242660
|
+
{ key: "status", header: "STATUS" },
|
|
242661
|
+
{
|
|
242662
|
+
key: "confirmedCount",
|
|
242663
|
+
header: "CONFIRMED",
|
|
242664
|
+
format: (_value, row) => `${row.confirmedCount}/${row.requiredCount}`
|
|
242665
|
+
},
|
|
242666
|
+
{ key: "automationName", header: "AUTOMATION" },
|
|
242667
|
+
{ key: "sourceLabel", header: "SOURCE" },
|
|
242668
|
+
{ key: "executionId", header: "RUN" },
|
|
242669
|
+
{ key: "version", header: "VER" },
|
|
242670
|
+
{ key: "createdAt", header: "CREATED", format: formatTimestamp }
|
|
242671
|
+
];
|
|
242672
|
+
var REVIEW_DECISION_COLUMNS = [
|
|
242673
|
+
{ key: "path", header: "PATH" },
|
|
242674
|
+
{
|
|
242675
|
+
key: "required",
|
|
242676
|
+
header: "REQ",
|
|
242677
|
+
format: (value) => value ? "yes" : "no"
|
|
242678
|
+
},
|
|
242679
|
+
{
|
|
242680
|
+
key: "currentValue",
|
|
242681
|
+
header: "VALUE",
|
|
242682
|
+
format: (value) => formatScalarForDisplay(value)
|
|
242683
|
+
},
|
|
242684
|
+
{ key: "confirmed", header: "CONFIRMED" },
|
|
242685
|
+
{ key: "reason", header: "REASON" }
|
|
242686
|
+
];
|
|
242687
|
+
function buildReviewListParams(opts) {
|
|
242688
|
+
const params = {};
|
|
242689
|
+
if (opts.automationId)
|
|
242690
|
+
params.automationId = opts.automationId;
|
|
242691
|
+
if (opts.waitingBefore)
|
|
242692
|
+
params.waitingBefore = opts.waitingBefore;
|
|
242693
|
+
if (opts.cursor)
|
|
242694
|
+
params.cursor = opts.cursor;
|
|
242695
|
+
if (opts.limit != null)
|
|
242696
|
+
params.limit = String(opts.limit);
|
|
242697
|
+
return params;
|
|
242698
|
+
}
|
|
242699
|
+
function parseReviewScalarValue(raw) {
|
|
242700
|
+
const trimmed = raw.trim();
|
|
242701
|
+
if (trimmed === "null")
|
|
242702
|
+
return null;
|
|
242703
|
+
if (trimmed === "true")
|
|
242704
|
+
return true;
|
|
242705
|
+
if (trimmed === "false")
|
|
242706
|
+
return false;
|
|
242707
|
+
if (/^-?\d+(?:\.\d+)?$/.test(trimmed)) {
|
|
242708
|
+
const asNumber = Number(trimmed);
|
|
242709
|
+
if (Number.isFinite(asNumber))
|
|
242710
|
+
return asNumber;
|
|
242711
|
+
}
|
|
242712
|
+
return raw;
|
|
242713
|
+
}
|
|
242714
|
+
function parseReviewJsonScalar(value) {
|
|
242715
|
+
if (value === null)
|
|
242716
|
+
return null;
|
|
242717
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
242718
|
+
return value;
|
|
242719
|
+
}
|
|
242720
|
+
throw new Error("Review field values must be scalar JSON: string, number, boolean, or null.");
|
|
242721
|
+
}
|
|
242722
|
+
function resolveReviewIdempotencyKey(explicit) {
|
|
242723
|
+
const key = explicit?.trim();
|
|
242724
|
+
if (key)
|
|
242725
|
+
return key;
|
|
242726
|
+
return newIdempotencyKey();
|
|
242727
|
+
}
|
|
242728
|
+
function formatScalarForDisplay(value) {
|
|
242729
|
+
if (value === null)
|
|
242730
|
+
return "null";
|
|
242731
|
+
if (typeof value === "string")
|
|
242732
|
+
return value;
|
|
242733
|
+
return JSON.stringify(value);
|
|
242734
|
+
}
|
|
242735
|
+
function decisionRows(task) {
|
|
242736
|
+
return (task.decisions ?? []).map((decision) => ({
|
|
242737
|
+
path: decision.path,
|
|
242738
|
+
required: decision.required,
|
|
242739
|
+
currentValue: decision.currentValue,
|
|
242740
|
+
confirmed: decision.confirmedAt ? "yes" : "no",
|
|
242741
|
+
reason: decision.reason
|
|
242742
|
+
}));
|
|
242743
|
+
}
|
|
242744
|
+
function formatReviewTaskSummary(task) {
|
|
242745
|
+
return [
|
|
242746
|
+
`ID ${task.id}`,
|
|
242747
|
+
`Status ${task.status}`,
|
|
242748
|
+
`Automation ${task.automationName} (${task.automationId})`,
|
|
242749
|
+
`Run ${task.executionId}`,
|
|
242750
|
+
`Source ${task.sourceKind} · ${task.sourceLabel}`,
|
|
242751
|
+
`Progress ${task.confirmedCount}/${task.requiredCount} confirmed · version ${task.version}`,
|
|
242752
|
+
`Created ${formatTimestamp(task.createdAt)}`,
|
|
242753
|
+
`Updated ${formatTimestamp(task.updatedAt)}`
|
|
242754
|
+
].join(`
|
|
242755
|
+
`);
|
|
242756
|
+
}
|
|
242757
|
+
function formatReviewTaskDetail(task) {
|
|
242758
|
+
const lines = [formatReviewTaskSummary(task)];
|
|
242759
|
+
if (task.instructions) {
|
|
242760
|
+
lines.push("", "Instructions", task.instructions);
|
|
242761
|
+
}
|
|
242762
|
+
if (task.files?.length) {
|
|
242763
|
+
lines.push("", "Files");
|
|
242764
|
+
for (const file of task.files) {
|
|
242765
|
+
lines.push(` ${file.fileId} ${file.filename}${file.fieldName ? ` (${file.fieldName})` : ""}`);
|
|
242766
|
+
}
|
|
242767
|
+
}
|
|
242768
|
+
return lines.join(`
|
|
242769
|
+
`);
|
|
242770
|
+
}
|
|
242771
|
+
|
|
242772
|
+
// src/commands/reviews.ts
|
|
242773
|
+
function buildClient4(opts) {
|
|
242774
|
+
const config = resolveConfig(opts);
|
|
242775
|
+
requireApiKey(config);
|
|
242776
|
+
return new ApiClient(config);
|
|
242777
|
+
}
|
|
242778
|
+
function printJson4(value) {
|
|
242779
|
+
console.log(JSON.stringify(value, null, 2));
|
|
242780
|
+
}
|
|
242781
|
+
function taskPath(taskId, suffix = "") {
|
|
242782
|
+
return apiPath(`/human-reviews/${encodeURIComponent(taskId)}${suffix}`);
|
|
242783
|
+
}
|
|
242784
|
+
function renderTaskResult(task, json) {
|
|
242785
|
+
if (json) {
|
|
242786
|
+
printJson4({ task });
|
|
242787
|
+
return;
|
|
242788
|
+
}
|
|
242789
|
+
console.log(formatReviewTaskDetail(task));
|
|
242790
|
+
const rows = decisionRows(task);
|
|
242791
|
+
if (rows.length > 0) {
|
|
242792
|
+
console.log("");
|
|
242793
|
+
console.log(table(rows, REVIEW_DECISION_COLUMNS));
|
|
242794
|
+
}
|
|
242795
|
+
}
|
|
242796
|
+
var REVIEWS_EXAMPLES = `
|
|
242797
|
+
Examples:
|
|
242798
|
+
$ eigenpal reviews list
|
|
242799
|
+
$ eigenpal reviews list --automation-id auto_... --limit 20 --json
|
|
242800
|
+
$ eigenpal reviews get hrt_...
|
|
242801
|
+
$ eigenpal reviews confirm hrt_... --path /vendor --value "Acme" --expected-version 3
|
|
242802
|
+
$ eigenpal reviews confirm hrt_... --path /total --value 42 --expected-version 3 --withdraw
|
|
242803
|
+
$ eigenpal reviews approve hrt_... --expected-version 3
|
|
242804
|
+
$ eigenpal reviews reject hrt_... --reason "Missing PO number" --expected-version 3
|
|
242805
|
+
$ eigenpal reviews download hrt_... file_... --out invoice.pdf
|
|
242806
|
+
|
|
242807
|
+
Notes:
|
|
242808
|
+
Tasks are created by workflow human-review steps and finish through approve or reject.
|
|
242809
|
+
Use \`eigenpal runs cancel <run-id>\` to abort a paused run without approving review.
|
|
242810
|
+
Post-run eval corrections live under \`eigenpal runs reviews\`, not here.
|
|
242811
|
+
`;
|
|
242812
|
+
function registerReviewsCommands(program) {
|
|
242813
|
+
const reviews = program.command("reviews").description("Work the live human-review queue for paused runs: list pending tasks, confirm fields, approve, reject, and download attachments.").addHelpText("after", REVIEWS_EXAMPLES).action(() => {
|
|
242814
|
+
process.stderr.write("`eigenpal reviews` requires a subcommand. Run `eigenpal reviews --help`.\n");
|
|
242815
|
+
process.exit(2);
|
|
242816
|
+
});
|
|
242817
|
+
addJsonFlag(withBaseUrl(reviews.command("list").alias("ls").description("List pending human-review tasks (oldest first, cursor-paginated).").option("--automation-id <id>", "Filter to one automation id").option("--waiting-before <iso>", "Only tasks created before this ISO timestamp (queue age filter)").option("--cursor <token>", "Pagination cursor from a previous list response").option("--limit <n>", "Page size (1–100)", intArg, 50))).action(action(listReviews));
|
|
242818
|
+
addJsonFlag(withBaseUrl(reviews.command("get <task-id>").description("Get one human-review task with its field decisions and attached files."))).action(action(getReview));
|
|
242819
|
+
addJsonFlag(withBaseUrl(reviews.command("confirm <task-id>").description("Confirm or edit one scalar review field. Use --withdraw to persist a draft edit without confirming.").requiredOption("--path <json-pointer>", "Field JSON pointer (for example /vendor or /items/0/name)").option("--value <scalar>", "Scalar value: string, number, true, false, or null").option("--value-json <json>", "Scalar JSON literal (alternative to --value)").requiredOption("--expected-version <n>", "Optimistic concurrency version from get/list", intArg).option("--idempotency-key <key>", "Durable idempotency key (auto-generated when omitted)").option("--withdraw", "Persist the edit without confirming (confirmed=false)"))).action(action(confirmReviewField));
|
|
242820
|
+
addJsonFlag(withBaseUrl(reviews.command("approve <task-id>").description("Approve a review task after all required fields are confirmed.").requiredOption("--expected-version <n>", "Optimistic concurrency version from get/list", intArg))).action(action(approveReview));
|
|
242821
|
+
addJsonFlag(withBaseUrl(reviews.command("reject <task-id>").description("Reject a review task and fail the paused run with a reason.").requiredOption("--reason <text>", "Human-readable rejection reason").requiredOption("--expected-version <n>", "Optimistic concurrency version from get/list", intArg).option("--idempotency-key <key>", "Durable idempotency key (auto-generated when omitted)"))).action(action(rejectReview));
|
|
242822
|
+
withBaseUrl(reviews.command("download <task-id> <file-id>").description("Download one file attached to a review task.").requiredOption("--out <path>", "Write bytes to this file path")).action(action(downloadReviewFile));
|
|
242823
|
+
}
|
|
242824
|
+
async function listReviews(opts) {
|
|
242825
|
+
const client = buildClient4(opts);
|
|
242826
|
+
const payload = await client.get(apiPath("/human-reviews"), buildReviewListParams(opts));
|
|
242827
|
+
if (opts.json) {
|
|
242828
|
+
printJson4(payload);
|
|
242829
|
+
writeListHint(payload);
|
|
242830
|
+
return;
|
|
242831
|
+
}
|
|
242832
|
+
console.log(table(payload.tasks ?? [], REVIEW_LIST_COLUMNS));
|
|
242833
|
+
writeListHint(payload);
|
|
242834
|
+
}
|
|
242835
|
+
function writeListHint(payload) {
|
|
242836
|
+
const count = payload.tasks?.length ?? 0;
|
|
242837
|
+
if (count === 0)
|
|
242838
|
+
return;
|
|
242839
|
+
const cursorHint = payload.nextCursor ? ` · next page: --cursor ${payload.nextCursor}` : "";
|
|
242840
|
+
process.stderr.write(dim(`${count} pending task${count === 1 ? "" : "s"}${cursorHint} · use --json for machine-readable output`) + `
|
|
242841
|
+
`);
|
|
242842
|
+
}
|
|
242843
|
+
async function getReview(taskId, opts) {
|
|
242844
|
+
const client = buildClient4(opts);
|
|
242845
|
+
const payload = await client.get(taskPath(taskId));
|
|
242846
|
+
renderTaskResult(payload.task, opts.json);
|
|
242847
|
+
}
|
|
242848
|
+
async function confirmReviewField(taskId, opts) {
|
|
242849
|
+
if (opts.value !== undefined && opts.valueJson !== undefined) {
|
|
242850
|
+
throw new Error("Pass only one of --value or --value-json.");
|
|
242851
|
+
}
|
|
242852
|
+
const rawValue = opts.valueJson ?? opts.value;
|
|
242853
|
+
if (rawValue === undefined) {
|
|
242854
|
+
throw new Error("Missing field value. Pass --value <scalar> or --value-json <json>.");
|
|
242855
|
+
}
|
|
242856
|
+
const value = opts.valueJson !== undefined ? parseReviewJsonScalar(JSON.parse(opts.valueJson)) : parseReviewScalarValue(rawValue);
|
|
242857
|
+
const client = buildClient4(opts);
|
|
242858
|
+
const payload = await client.put(taskPath(taskId, "/fields"), {
|
|
242859
|
+
path: opts.path,
|
|
242860
|
+
value,
|
|
242861
|
+
expectedVersion: opts.expectedVersion,
|
|
242862
|
+
idempotencyKey: resolveReviewIdempotencyKey(opts.idempotencyKey),
|
|
242863
|
+
confirmed: opts.withdraw ? false : true
|
|
242864
|
+
});
|
|
242865
|
+
if (opts.json) {
|
|
242866
|
+
printJson4(payload);
|
|
242867
|
+
return;
|
|
242868
|
+
}
|
|
242869
|
+
success(`Updated ${ui.bold(payload.task.id)} (${payload.task.confirmedCount}/${payload.task.requiredCount} confirmed)`);
|
|
242870
|
+
console.log(formatReviewTaskSummary(payload.task));
|
|
242871
|
+
}
|
|
242872
|
+
async function approveReview(taskId, opts) {
|
|
242873
|
+
const client = buildClient4(opts);
|
|
242874
|
+
const payload = await client.post(taskPath(taskId, "/approve"), {
|
|
242875
|
+
expectedVersion: opts.expectedVersion
|
|
242876
|
+
});
|
|
242877
|
+
if (opts.json) {
|
|
242878
|
+
printJson4(payload);
|
|
242879
|
+
return;
|
|
242880
|
+
}
|
|
242881
|
+
success(`Approved ${ui.bold(payload.task.id)} · run ${payload.task.executionId} resumed`);
|
|
242882
|
+
console.log(formatReviewTaskSummary(payload.task));
|
|
242883
|
+
}
|
|
242884
|
+
async function rejectReview(taskId, opts) {
|
|
242885
|
+
const client = buildClient4(opts);
|
|
242886
|
+
const payload = await client.post(taskPath(taskId, "/reject"), {
|
|
242887
|
+
reason: opts.reason,
|
|
242888
|
+
expectedVersion: opts.expectedVersion,
|
|
242889
|
+
idempotencyKey: resolveReviewIdempotencyKey(opts.idempotencyKey)
|
|
242890
|
+
});
|
|
242891
|
+
if (opts.json) {
|
|
242892
|
+
printJson4(payload);
|
|
242893
|
+
return;
|
|
242894
|
+
}
|
|
242895
|
+
success(`Rejected ${ui.bold(payload.task.id)} · run ${payload.task.executionId} failed`);
|
|
242896
|
+
console.log(formatReviewTaskSummary(payload.task));
|
|
242897
|
+
}
|
|
242898
|
+
async function downloadReviewFile(taskId, fileId, opts) {
|
|
242899
|
+
const client = buildClient4(opts);
|
|
242900
|
+
const res = await client.getStream(taskPath(taskId, `/files/${encodeURIComponent(fileId)}/content`));
|
|
242901
|
+
const buf = Buffer.from(await res.arrayBuffer());
|
|
242902
|
+
await fs16.writeFile(opts.out, buf);
|
|
242903
|
+
success(`Wrote ${ui.bold(opts.out)} ${ui.dim(`(${buf.byteLength} bytes)`)}`);
|
|
242904
|
+
}
|
|
242905
|
+
|
|
242906
|
+
// src/commands/run.ts
|
|
242907
|
+
init_src();
|
|
242908
|
+
|
|
242909
|
+
// src/commands/run-form-data.ts
|
|
242910
|
+
import { promises as fs17 } from "node:fs";
|
|
242911
|
+
import path18 from "node:path";
|
|
242912
|
+
|
|
242913
|
+
// src/lib/upload-limits.ts
|
|
242914
|
+
var DEFAULT_MULTIPART_MAX_BYTES = Math.floor(4.5 * 1024 * 1024);
|
|
242915
|
+
var MULTIPART_ENVELOPE_HEADROOM_BYTES = 256 * 1024;
|
|
242916
|
+
function multipartFileByteBudget(multipartMaxBytes = multipartMaxBytesFromEnv()) {
|
|
242917
|
+
if (multipartMaxBytes === null)
|
|
242918
|
+
return null;
|
|
242919
|
+
return Math.max(0, multipartMaxBytes - MULTIPART_ENVELOPE_HEADROOM_BYTES);
|
|
242920
|
+
}
|
|
242921
|
+
function indicesRequiringPreUpload(files, multipartMaxBytes = multipartMaxBytesFromEnv()) {
|
|
242922
|
+
const budget = multipartFileByteBudget(multipartMaxBytes);
|
|
242923
|
+
const toPreUpload = new Set;
|
|
242924
|
+
if (budget === null)
|
|
242925
|
+
return toPreUpload;
|
|
242926
|
+
files.forEach((file, index) => {
|
|
242927
|
+
if (file.size > budget) {
|
|
242928
|
+
toPreUpload.add(index);
|
|
242929
|
+
}
|
|
242930
|
+
});
|
|
242931
|
+
let multipartTotal = 0;
|
|
242932
|
+
files.forEach((file, index) => {
|
|
242933
|
+
if (!toPreUpload.has(index))
|
|
242934
|
+
multipartTotal += file.size;
|
|
242935
|
+
});
|
|
242936
|
+
const candidates = files.map((file, index) => ({ file, index })).filter(({ index }) => !toPreUpload.has(index)).slice().sort((a, b) => b.file.size - a.file.size || a.index - b.index);
|
|
242937
|
+
for (const { file, index } of candidates) {
|
|
242938
|
+
if (multipartTotal <= budget)
|
|
242939
|
+
break;
|
|
242940
|
+
toPreUpload.add(index);
|
|
242941
|
+
multipartTotal -= file.size;
|
|
242942
|
+
}
|
|
242943
|
+
return toPreUpload;
|
|
242944
|
+
}
|
|
242945
|
+
function multipartMaxBytesFromEnv(raw = env.EIGENPAL_MULTIPART_MAX_BYTES) {
|
|
242946
|
+
if (raw == null || raw.trim() === "")
|
|
242947
|
+
return DEFAULT_MULTIPART_MAX_BYTES;
|
|
242948
|
+
const normalized = raw.trim().toLowerCase();
|
|
242949
|
+
if (normalized === "none" || normalized === "null" || normalized === "unlimited")
|
|
242950
|
+
return null;
|
|
242951
|
+
const parsed = Number(normalized);
|
|
242952
|
+
if (Number.isSafeInteger(parsed) && parsed >= 0)
|
|
242953
|
+
return parsed;
|
|
242954
|
+
throw new Error("EIGENPAL_MULTIPART_MAX_BYTES must be a non-negative integer or one of: none, null, unlimited.");
|
|
242955
|
+
}
|
|
242956
|
+
|
|
242607
242957
|
// src/commands/run-form-data.ts
|
|
242608
242958
|
var RESERVED_FIELD_NAMES = new Set([
|
|
242609
242959
|
"_json",
|
|
@@ -242620,7 +242970,7 @@ async function buildPreparedRunRequest(client, input) {
|
|
|
242620
242970
|
};
|
|
242621
242971
|
const localFiles = [];
|
|
242622
242972
|
for (const spec of parseInputFileSpecs(input.inputFile ?? [])) {
|
|
242623
|
-
const info = await
|
|
242973
|
+
const info = await fs17.stat(spec.filePath);
|
|
242624
242974
|
if (!info.isFile()) {
|
|
242625
242975
|
throw new Error(`--input-file path is not a file: ${spec.filePath}`);
|
|
242626
242976
|
}
|
|
@@ -242679,7 +243029,7 @@ async function buildPreparedRunRequest(client, input) {
|
|
|
242679
243029
|
if (input.metadata)
|
|
242680
243030
|
form.append("metadata", JSON.stringify(input.metadata));
|
|
242681
243031
|
for (const file of remaining) {
|
|
242682
|
-
const content = file.content ?? (file.filePath ? await
|
|
243032
|
+
const content = file.content ?? (file.filePath ? await fs17.readFile(file.filePath) : Buffer.alloc(0));
|
|
242683
243033
|
appendFilePart(form, file.fieldName, content, file.filename, file.mimeType);
|
|
242684
243034
|
}
|
|
242685
243035
|
return { form, hasMultipartFiles: remaining.length > 0 };
|
|
@@ -242850,7 +243200,7 @@ async function runTarget(target, opts) {
|
|
|
242850
243200
|
failOnMismatch: opts.failOnMismatch
|
|
242851
243201
|
});
|
|
242852
243202
|
}
|
|
242853
|
-
const client =
|
|
243203
|
+
const client = buildClient2(opts);
|
|
242854
243204
|
let payload;
|
|
242855
243205
|
const runPath = runTargetApiPath(target);
|
|
242856
243206
|
const pathTarget = runStartMultipartTarget(target);
|
|
@@ -244155,12 +244505,12 @@ function looksLikeFreeform(prop) {
|
|
|
244155
244505
|
return prop.pattern !== undefined || prop.format !== undefined;
|
|
244156
244506
|
}
|
|
244157
244507
|
// src/commands/workflow/index.ts
|
|
244158
|
-
import { existsSync as existsSync23, promises as
|
|
244508
|
+
import { existsSync as existsSync23, promises as fs21 } from "node:fs";
|
|
244159
244509
|
import path19 from "node:path";
|
|
244160
244510
|
|
|
244161
244511
|
// src/lib/local-templates.ts
|
|
244162
244512
|
init_src();
|
|
244163
|
-
import { existsSync as existsSync18, promises as
|
|
244513
|
+
import { existsSync as existsSync18, promises as fs18, realpathSync as realpathSync3, statSync as statSync5 } from "node:fs";
|
|
244164
244514
|
import { basename, dirname as dirname6, isAbsolute, relative as relative4, resolve as resolve8, sep } from "node:path";
|
|
244165
244515
|
|
|
244166
244516
|
// src/lib/office-template.ts
|
|
@@ -244464,7 +244814,7 @@ async function loadLocalTemplatesForPush(workflowFile, parsedSteps, opts = {}) {
|
|
|
244464
244814
|
continue;
|
|
244465
244815
|
}
|
|
244466
244816
|
const absolutePath = resolveWorkflowTemplatePath(workflowFile, ref.templatePath, opts);
|
|
244467
|
-
const bytes = await
|
|
244817
|
+
const bytes = await fs18.readFile(absolutePath);
|
|
244468
244818
|
inspectOfficeTemplateBytes(bytes, basename(absolutePath));
|
|
244469
244819
|
const row = {
|
|
244470
244820
|
path: ref.templatePath,
|
|
@@ -244729,7 +245079,7 @@ async function clearEvalOutputs(dir, exampleNames = [], options = {}) {
|
|
|
244729
245079
|
|
|
244730
245080
|
// src/commands/workflow/evaluator-type.ts
|
|
244731
245081
|
init_src();
|
|
244732
|
-
import { promises as
|
|
245082
|
+
import { promises as fs19 } from "node:fs";
|
|
244733
245083
|
var EVALUATOR_REGISTRY = {
|
|
244734
245084
|
"exact-diff": {
|
|
244735
245085
|
type: "exact-diff",
|
|
@@ -244793,7 +245143,7 @@ function registerEvaluatorTypeCommands(parent) {
|
|
|
244793
245143
|
};
|
|
244794
245144
|
const text = JSON.stringify(result, null, 2);
|
|
244795
245145
|
if (opts.out) {
|
|
244796
|
-
await
|
|
245146
|
+
await fs19.writeFile(opts.out, text);
|
|
244797
245147
|
process.stderr.write(`${ui.ok("✓")} Wrote ${ui.bold(opts.out)}
|
|
244798
245148
|
`);
|
|
244799
245149
|
} else {
|
|
@@ -244802,6 +245152,267 @@ function registerEvaluatorTypeCommands(parent) {
|
|
|
244802
245152
|
});
|
|
244803
245153
|
}
|
|
244804
245154
|
|
|
245155
|
+
// src/lib/workflow-folders.ts
|
|
245156
|
+
function assertWorkflowFolder(folder, ref) {
|
|
245157
|
+
if (folder.type !== "workflow") {
|
|
245158
|
+
throw new Error(`Folder is not a workflow folder: ${ref}`);
|
|
245159
|
+
}
|
|
245160
|
+
return folder;
|
|
245161
|
+
}
|
|
245162
|
+
function findSiblingFolder(folders, parentId, segment) {
|
|
245163
|
+
const decoded = safeDecode2(segment);
|
|
245164
|
+
return folders.find((f) => f.parentId === parentId && (f.name === segment || f.name === decoded || encodeURIComponent(f.name) === segment));
|
|
245165
|
+
}
|
|
245166
|
+
var FOLDER_ID_PREFIX = "fldr_";
|
|
245167
|
+
function looksLikeFolderId(value) {
|
|
245168
|
+
return value.startsWith(FOLDER_ID_PREFIX);
|
|
245169
|
+
}
|
|
245170
|
+
function normalizeFolderPathInput(path) {
|
|
245171
|
+
const trimmed = path.trim();
|
|
245172
|
+
if (trimmed === "/" || trimmed === "")
|
|
245173
|
+
return "/";
|
|
245174
|
+
return trimmed.replace(/^\/+|\/+$/g, "");
|
|
245175
|
+
}
|
|
245176
|
+
function folderPathSegments(path) {
|
|
245177
|
+
const normalized = normalizeFolderPathInput(path);
|
|
245178
|
+
if (normalized === "/")
|
|
245179
|
+
return [];
|
|
245180
|
+
return normalized.split("/").filter(Boolean);
|
|
245181
|
+
}
|
|
245182
|
+
function safeDecode2(segment) {
|
|
245183
|
+
try {
|
|
245184
|
+
return decodeURIComponent(segment);
|
|
245185
|
+
} catch {
|
|
245186
|
+
return segment;
|
|
245187
|
+
}
|
|
245188
|
+
}
|
|
245189
|
+
function resolveFolderPathToId(folders, path) {
|
|
245190
|
+
const segments = folderPathSegments(path);
|
|
245191
|
+
if (segments.length === 0)
|
|
245192
|
+
return null;
|
|
245193
|
+
let parentId = null;
|
|
245194
|
+
for (const segment of segments) {
|
|
245195
|
+
const decoded = safeDecode2(segment);
|
|
245196
|
+
const folder = folders.find((f) => f.parentId === parentId && (f.name === segment || f.name === decoded || encodeURIComponent(f.name) === segment));
|
|
245197
|
+
if (!folder)
|
|
245198
|
+
return null;
|
|
245199
|
+
parentId = folder.id;
|
|
245200
|
+
}
|
|
245201
|
+
return parentId;
|
|
245202
|
+
}
|
|
245203
|
+
function folderIdToPath(folders, folderId) {
|
|
245204
|
+
if (!folderId)
|
|
245205
|
+
return "/";
|
|
245206
|
+
const byId = new Map(folders.map((f) => [f.id, f]));
|
|
245207
|
+
const segments = [];
|
|
245208
|
+
let current = folderId;
|
|
245209
|
+
while (current) {
|
|
245210
|
+
const folder = byId.get(current);
|
|
245211
|
+
if (!folder)
|
|
245212
|
+
break;
|
|
245213
|
+
segments.unshift(folder.name);
|
|
245214
|
+
current = folder.parentId;
|
|
245215
|
+
}
|
|
245216
|
+
return segments.length > 0 ? segments.join("/") : "/";
|
|
245217
|
+
}
|
|
245218
|
+
function buildFolderTree(folders) {
|
|
245219
|
+
const nodes = new Map;
|
|
245220
|
+
for (const folder of folders) {
|
|
245221
|
+
nodes.set(folder.id, { folder, children: [] });
|
|
245222
|
+
}
|
|
245223
|
+
const roots = [];
|
|
245224
|
+
for (const folder of folders) {
|
|
245225
|
+
const node = nodes.get(folder.id);
|
|
245226
|
+
if (folder.parentId && nodes.has(folder.parentId)) {
|
|
245227
|
+
nodes.get(folder.parentId).children.push(node);
|
|
245228
|
+
} else {
|
|
245229
|
+
roots.push(node);
|
|
245230
|
+
}
|
|
245231
|
+
}
|
|
245232
|
+
const sortNodes = (list) => {
|
|
245233
|
+
list.sort((a, b) => a.folder.name.localeCompare(b.folder.name));
|
|
245234
|
+
for (const node of list)
|
|
245235
|
+
sortNodes(node.children);
|
|
245236
|
+
};
|
|
245237
|
+
sortNodes(roots);
|
|
245238
|
+
return roots;
|
|
245239
|
+
}
|
|
245240
|
+
function renderFolderTreeLines(nodes, indent = "") {
|
|
245241
|
+
const lines = [];
|
|
245242
|
+
for (let i = 0;i < nodes.length; i++) {
|
|
245243
|
+
const node = nodes[i];
|
|
245244
|
+
const branch = i === nodes.length - 1 ? "└── " : "├── ";
|
|
245245
|
+
const childIndent = indent + (i === nodes.length - 1 ? " " : "│ ");
|
|
245246
|
+
const counts = [];
|
|
245247
|
+
if (node.folder.workflowCount != null && node.folder.workflowCount > 0) {
|
|
245248
|
+
counts.push(`${node.folder.workflowCount} workflow${node.folder.workflowCount === 1 ? "" : "s"}`);
|
|
245249
|
+
}
|
|
245250
|
+
if (node.folder.childCount != null && node.folder.childCount > 0) {
|
|
245251
|
+
counts.push(`${node.folder.childCount} subfolder${node.folder.childCount === 1 ? "" : "s"}`);
|
|
245252
|
+
}
|
|
245253
|
+
const suffix = counts.length > 0 ? ` ${counts.join(", ")}` : "";
|
|
245254
|
+
lines.push(`${indent}${branch}${node.folder.name} (${node.folder.id})${suffix}`);
|
|
245255
|
+
lines.push(...renderFolderTreeLines(node.children, childIndent));
|
|
245256
|
+
}
|
|
245257
|
+
return lines;
|
|
245258
|
+
}
|
|
245259
|
+
async function fetchWorkflowFolders(client, opts = {}) {
|
|
245260
|
+
const params = { type: "workflow" };
|
|
245261
|
+
if (opts.tree)
|
|
245262
|
+
params.tree = "true";
|
|
245263
|
+
const raw = await client.get("/v1/folders", params);
|
|
245264
|
+
if (Array.isArray(raw))
|
|
245265
|
+
return raw;
|
|
245266
|
+
if (raw && typeof raw === "object" && Array.isArray(raw.data)) {
|
|
245267
|
+
return raw.data;
|
|
245268
|
+
}
|
|
245269
|
+
return [];
|
|
245270
|
+
}
|
|
245271
|
+
async function resolveWorkflowFolderRef(client, pathOrId) {
|
|
245272
|
+
const trimmed = pathOrId.trim();
|
|
245273
|
+
if (looksLikeFolderId(trimmed)) {
|
|
245274
|
+
const folder = assertWorkflowFolder(await client.get(`/v1/folders/${encodeURIComponent(trimmed)}`), trimmed);
|
|
245275
|
+
return folder;
|
|
245276
|
+
}
|
|
245277
|
+
const folders = await fetchWorkflowFolders(client, { tree: true });
|
|
245278
|
+
const folderId = resolveFolderPathToId(folders, trimmed);
|
|
245279
|
+
if (!folderId) {
|
|
245280
|
+
throw new Error(`Folder not found: ${trimmed}`);
|
|
245281
|
+
}
|
|
245282
|
+
const match = folders.find((f) => f.id === folderId);
|
|
245283
|
+
if (!match)
|
|
245284
|
+
throw new Error(`Folder not found: ${trimmed}`);
|
|
245285
|
+
return match;
|
|
245286
|
+
}
|
|
245287
|
+
async function ensureFolderPath(client, path) {
|
|
245288
|
+
const segments = folderPathSegments(path);
|
|
245289
|
+
if (segments.length === 0)
|
|
245290
|
+
return null;
|
|
245291
|
+
let folders = await fetchWorkflowFolders(client, { tree: true });
|
|
245292
|
+
let parentId = null;
|
|
245293
|
+
for (const segment of segments) {
|
|
245294
|
+
const decoded = safeDecode2(segment);
|
|
245295
|
+
let folder = findSiblingFolder(folders, parentId, segment);
|
|
245296
|
+
if (!folder) {
|
|
245297
|
+
try {
|
|
245298
|
+
folder = await client.post("/v1/folders", {
|
|
245299
|
+
name: decoded,
|
|
245300
|
+
parentId,
|
|
245301
|
+
type: "workflow"
|
|
245302
|
+
});
|
|
245303
|
+
folders = [...folders, folder];
|
|
245304
|
+
} catch (err) {
|
|
245305
|
+
if (!(err instanceof ApiError) || err.status !== 409)
|
|
245306
|
+
throw err;
|
|
245307
|
+
folders = await fetchWorkflowFolders(client, { tree: true });
|
|
245308
|
+
folder = findSiblingFolder(folders, parentId, segment);
|
|
245309
|
+
if (!folder)
|
|
245310
|
+
throw err;
|
|
245311
|
+
}
|
|
245312
|
+
}
|
|
245313
|
+
parentId = folder.id;
|
|
245314
|
+
}
|
|
245315
|
+
return parentId;
|
|
245316
|
+
}
|
|
245317
|
+
|
|
245318
|
+
// src/commands/workflow/folders.ts
|
|
245319
|
+
function registerWorkflowFolderCommands(parent) {
|
|
245320
|
+
const folders = parent.command("folders").description("Manage workflow folders (organize workflows in Studio).").action(() => {
|
|
245321
|
+
process.stderr.write("`eigenpal workflow folders` requires a subcommand. Run `eigenpal workflow folders --help`.\n");
|
|
245322
|
+
process.exit(2);
|
|
245323
|
+
});
|
|
245324
|
+
addJsonFlag(withBaseUrl(folders.command("list"))).description("List workflow folders.").option("--tree", "Render folders as an indented tree").action(action(listWorkflowFolders));
|
|
245325
|
+
addJsonFlag(withBaseUrl(folders.command("create <path>"))).description("Create a folder path, creating any missing parent segments.").action(action(createWorkflowFolder));
|
|
245326
|
+
addJsonFlag(withBaseUrl(folders.command("rename <path-or-id>"))).description("Rename a workflow folder.").requiredOption("--name <name>", "New folder name").action(action(renameWorkflowFolder));
|
|
245327
|
+
addJsonFlag(withBaseUrl(folders.command("delete <path-or-id>"))).description("Delete a workflow folder.").option("--yes", "Skip typed-id confirmation (required in CI / agent terminals without a TTY)").addHelpText("after", `
|
|
245328
|
+
Deleting a folder removes its subfolders. Workflows inside are moved to the
|
|
245329
|
+
root ("All workflows"), not deleted. This matches Studio folder deletion.
|
|
245330
|
+
`).action(action(deleteWorkflowFolder));
|
|
245331
|
+
}
|
|
245332
|
+
async function listWorkflowFolders(opts) {
|
|
245333
|
+
const client = buildClient(opts);
|
|
245334
|
+
const rows = await fetchWorkflowFolders(client, { tree: true });
|
|
245335
|
+
if (opts.json) {
|
|
245336
|
+
printJson({ data: rows, total: rows.length });
|
|
245337
|
+
return;
|
|
245338
|
+
}
|
|
245339
|
+
if (opts.tree) {
|
|
245340
|
+
const tree = buildFolderTree(rows);
|
|
245341
|
+
const lines = renderFolderTreeLines(tree);
|
|
245342
|
+
if (lines.length === 0) {
|
|
245343
|
+
dim("No workflow folders yet.");
|
|
245344
|
+
return;
|
|
245345
|
+
}
|
|
245346
|
+
console.log(lines.join(`
|
|
245347
|
+
`));
|
|
245348
|
+
dim(`${rows.length} folder${rows.length === 1 ? "" : "s"} · use --json for the raw payload`);
|
|
245349
|
+
return;
|
|
245350
|
+
}
|
|
245351
|
+
console.log(table(rows, [
|
|
245352
|
+
{ key: "id", header: "ID" },
|
|
245353
|
+
{
|
|
245354
|
+
key: "name",
|
|
245355
|
+
header: "NAME",
|
|
245356
|
+
format: (_v, row) => folderIdToPath(rows, row.id)
|
|
245357
|
+
},
|
|
245358
|
+
{ key: "workflowCount", header: "WORKFLOWS", format: (v) => String(v ?? 0) },
|
|
245359
|
+
{ key: "childCount", header: "SUBFOLDERS", format: (v) => String(v ?? 0) }
|
|
245360
|
+
]));
|
|
245361
|
+
dim(`${rows.length} folder${rows.length === 1 ? "" : "s"} · use --tree for hierarchy`);
|
|
245362
|
+
}
|
|
245363
|
+
async function createWorkflowFolder(path, opts) {
|
|
245364
|
+
const client = buildClient(opts);
|
|
245365
|
+
const normalized = normalizeFolderPathInput(path);
|
|
245366
|
+
if (normalized === "/") {
|
|
245367
|
+
throw new Error("Cannot create the root folder. Omit the path or choose a name.");
|
|
245368
|
+
}
|
|
245369
|
+
const segments = folderPathSegments(path);
|
|
245370
|
+
if (segments.length === 0) {
|
|
245371
|
+
throw new Error("Folder path is required (for example billing/invoices).");
|
|
245372
|
+
}
|
|
245373
|
+
const folderId = await ensureFolderPath(client, path);
|
|
245374
|
+
const folders = await fetchWorkflowFolders(client, { tree: true });
|
|
245375
|
+
const folder = folders.find((f) => f.id === folderId);
|
|
245376
|
+
if (opts.json) {
|
|
245377
|
+
printJson(folder ?? { id: folderId, path: normalized });
|
|
245378
|
+
return;
|
|
245379
|
+
}
|
|
245380
|
+
success(`Created folder ${ui.bold(normalized)} ${ui.dim(`(${folderId})`)}`);
|
|
245381
|
+
}
|
|
245382
|
+
async function renameWorkflowFolder(pathOrId, opts) {
|
|
245383
|
+
const client = buildClient(opts);
|
|
245384
|
+
const folder = await resolveWorkflowFolderRef(client, pathOrId);
|
|
245385
|
+
const result = await client.patch(`/v1/folders/${encodeURIComponent(folder.id)}`, {
|
|
245386
|
+
name: opts.name.trim()
|
|
245387
|
+
});
|
|
245388
|
+
if (opts.json) {
|
|
245389
|
+
printJson(result);
|
|
245390
|
+
return;
|
|
245391
|
+
}
|
|
245392
|
+
success(`Renamed folder ${ui.bold(folder.name)} → ${ui.bold(result.name ?? opts.name)}`);
|
|
245393
|
+
}
|
|
245394
|
+
async function deleteWorkflowFolder(pathOrId, opts) {
|
|
245395
|
+
requireYesInNonInteractive(opts.yes, "delete workflow folder");
|
|
245396
|
+
const client = buildClient(opts);
|
|
245397
|
+
const folder = await resolveWorkflowFolderRef(client, pathOrId);
|
|
245398
|
+
const folders = await fetchWorkflowFolders(client, { tree: true });
|
|
245399
|
+
const pathLabel = folderIdToPath(folders, folder.id);
|
|
245400
|
+
warn("Deleting this folder removes its subfolders. Workflows inside move to the root; they are not deleted.");
|
|
245401
|
+
if (!opts.yes && isInteractiveStderr()) {
|
|
245402
|
+
await requireTypedConfirmation({
|
|
245403
|
+
id: folder.id,
|
|
245404
|
+
actionName: `delete folder "${pathLabel}"`,
|
|
245405
|
+
cancelledMessage: "Folder delete aborted"
|
|
245406
|
+
});
|
|
245407
|
+
}
|
|
245408
|
+
await client.delete(`/v1/folders/${encodeURIComponent(folder.id)}`);
|
|
245409
|
+
if (opts.json) {
|
|
245410
|
+
printJson({ deleted: true, id: folder.id, path: pathLabel });
|
|
245411
|
+
return;
|
|
245412
|
+
}
|
|
245413
|
+
success(`Deleted folder ${ui.bold(pathLabel)}`);
|
|
245414
|
+
}
|
|
245415
|
+
|
|
244805
245416
|
// src/commands/workflow/step-exec.ts
|
|
244806
245417
|
init_src();
|
|
244807
245418
|
var UNSUPPORTED_TYPE_EXIT = 2;
|
|
@@ -244830,20 +245441,20 @@ function registerStepExecCommands(workflow) {
|
|
|
244830
245441
|
|
|
244831
245442
|
// src/commands/workflow/templates.ts
|
|
244832
245443
|
init_src();
|
|
244833
|
-
import { existsSync as existsSync20, promises as
|
|
245444
|
+
import { existsSync as existsSync20, promises as fs20 } from "node:fs";
|
|
244834
245445
|
import { basename as basename3, resolve as resolve9 } from "node:path";
|
|
244835
|
-
function
|
|
245446
|
+
function buildClient5(opts) {
|
|
244836
245447
|
const config = resolveConfig(opts);
|
|
244837
245448
|
requireApiKey(config);
|
|
244838
245449
|
return new ApiClient(config);
|
|
244839
245450
|
}
|
|
244840
|
-
function
|
|
245451
|
+
function printJson5(value) {
|
|
244841
245452
|
console.log(JSON.stringify(value, null, 2));
|
|
244842
245453
|
}
|
|
244843
245454
|
async function readJsonFixtureFile(fixturePath) {
|
|
244844
245455
|
let raw;
|
|
244845
245456
|
try {
|
|
244846
|
-
raw = await
|
|
245457
|
+
raw = await fs20.readFile(resolve9(fixturePath), "utf8");
|
|
244847
245458
|
} catch (err) {
|
|
244848
245459
|
const code = err && typeof err === "object" && "code" in err ? String(err.code) : "";
|
|
244849
245460
|
if (code === "ENOENT") {
|
|
@@ -244895,8 +245506,8 @@ function registerTemplateCommands(parent) {
|
|
|
244895
245506
|
const uploadCmd = templates.command("upload <file>").description("Upload a DOCX or XLSX file as a new tmpl_… resource with an immutable tmpr_… revision.").option("--name <name>", "Display name (defaults to the filename without extension)").option("--description <text>", "Optional description");
|
|
244896
245507
|
addJsonFlag(withBaseUrl(uploadCmd)).action(action(async (file, opts) => {
|
|
244897
245508
|
const filePath = resolve9(file);
|
|
244898
|
-
const bytes = await
|
|
244899
|
-
const client =
|
|
245509
|
+
const bytes = await fs20.readFile(filePath);
|
|
245510
|
+
const client = buildClient5(opts);
|
|
244900
245511
|
const template = await uploadWorkspaceTemplate(client, {
|
|
244901
245512
|
bytes,
|
|
244902
245513
|
filename: basename3(filePath),
|
|
@@ -244904,7 +245515,7 @@ function registerTemplateCommands(parent) {
|
|
|
244904
245515
|
description: opts.description
|
|
244905
245516
|
});
|
|
244906
245517
|
if (opts.json) {
|
|
244907
|
-
|
|
245518
|
+
printJson5(template);
|
|
244908
245519
|
return;
|
|
244909
245520
|
}
|
|
244910
245521
|
success(`Uploaded ${ui.bold(template.id)} revision ${ui.bold(template.currentRevision?.id ?? "-")} (${template.format})`);
|
|
@@ -244912,10 +245523,10 @@ function registerTemplateCommands(parent) {
|
|
|
244912
245523
|
}));
|
|
244913
245524
|
const listCmd = templates.command("list").description("List workspace templates.");
|
|
244914
245525
|
addJsonFlag(withBaseUrl(withPagination(listCmd))).action(action(async (opts) => {
|
|
244915
|
-
const client =
|
|
245526
|
+
const client = buildClient5(opts);
|
|
244916
245527
|
const result = await listPublicTemplates(client, { limit: opts.limit, offset: opts.offset });
|
|
244917
245528
|
if (opts.json) {
|
|
244918
|
-
|
|
245529
|
+
printJson5(result);
|
|
244919
245530
|
return;
|
|
244920
245531
|
}
|
|
244921
245532
|
console.log(table(result.items.map((row) => ({
|
|
@@ -244940,10 +245551,10 @@ function registerTemplateCommands(parent) {
|
|
|
244940
245551
|
}));
|
|
244941
245552
|
const getCmd = templates.command("get <template-id>").alias("inspect").description("Inspect a tmpl_… resource: current tmpr_…, format, checksum, tokens, grammar.");
|
|
244942
245553
|
addJsonFlag(withBaseUrl(getCmd)).action(action(async (templateId, opts) => {
|
|
244943
|
-
const client =
|
|
245554
|
+
const client = buildClient5(opts);
|
|
244944
245555
|
const template = await getPublicTemplate(client, templateId);
|
|
244945
245556
|
if (opts.json) {
|
|
244946
|
-
|
|
245557
|
+
printJson5(template);
|
|
244947
245558
|
return;
|
|
244948
245559
|
}
|
|
244949
245560
|
printTemplateHuman(template);
|
|
@@ -244952,21 +245563,21 @@ function registerTemplateCommands(parent) {
|
|
|
244952
245563
|
withBaseUrl(downloadCmd).action(action(async (templateId, opts) => {
|
|
244953
245564
|
if (!opts.out)
|
|
244954
245565
|
throw new Error("Missing --out <path>.");
|
|
244955
|
-
const client =
|
|
245566
|
+
const client = buildClient5(opts);
|
|
244956
245567
|
const downloaded = await downloadTemplateBytes(client, templateId, opts.revisionId);
|
|
244957
|
-
await
|
|
245568
|
+
await fs20.writeFile(opts.out, downloaded.bytes);
|
|
244958
245569
|
success(`Wrote ${ui.bold(opts.out)} ${ui.dim(`(${downloaded.bytes.byteLength} bytes)`)}`);
|
|
244959
245570
|
}));
|
|
244960
245571
|
const replaceCmd = templates.command("replace <template-id> <file>").description("Append an immutable revision and advance the tmpl_… pointer.");
|
|
244961
245572
|
addJsonFlag(withBaseUrl(replaceCmd)).action(action(async (templateId, file, opts) => {
|
|
244962
245573
|
const filePath = resolve9(file);
|
|
244963
|
-
const bytes = await
|
|
244964
|
-
const client =
|
|
245574
|
+
const bytes = await fs20.readFile(filePath);
|
|
245575
|
+
const client = buildClient5(opts);
|
|
244965
245576
|
const current = await getPublicTemplate(client, templateId);
|
|
244966
245577
|
const nextInspection = inspectOfficeTemplateBytes(bytes, basename3(filePath));
|
|
244967
245578
|
if (current.currentRevision?.sha256 === nextInspection.sha256 || current.sha256 === nextInspection.sha256) {
|
|
244968
245579
|
if (opts.json) {
|
|
244969
|
-
|
|
245580
|
+
printJson5({ ...current, reused: true });
|
|
244970
245581
|
return;
|
|
244971
245582
|
}
|
|
244972
245583
|
success(`Checksum matches current revision ${ui.bold(current.currentRevision?.id ?? "-")} — skipped upload`);
|
|
@@ -244978,7 +245589,7 @@ function registerTemplateCommands(parent) {
|
|
|
244978
245589
|
filename: basename3(filePath)
|
|
244979
245590
|
});
|
|
244980
245591
|
if (opts.json) {
|
|
244981
|
-
|
|
245592
|
+
printJson5(template);
|
|
244982
245593
|
return;
|
|
244983
245594
|
}
|
|
244984
245595
|
success(`Replaced ${ui.bold(template.id)} → revision ${ui.bold(template.currentRevision?.id ?? "-")}`);
|
|
@@ -244989,10 +245600,10 @@ function registerTemplateCommands(parent) {
|
|
|
244989
245600
|
if (!opts.yes && !process.stdout.isTTY) {
|
|
244990
245601
|
throw new Error("templates delete is destructive and requires --yes when run non-interactively");
|
|
244991
245602
|
}
|
|
244992
|
-
const client =
|
|
245603
|
+
const client = buildClient5(opts);
|
|
244993
245604
|
const result = await deleteWorkspaceTemplate(client, templateId);
|
|
244994
245605
|
if (opts.json) {
|
|
244995
|
-
|
|
245606
|
+
printJson5(result);
|
|
244996
245607
|
return;
|
|
244997
245608
|
}
|
|
244998
245609
|
success(`Deleted ${ui.bold(templateId)}`);
|
|
@@ -245005,7 +245616,7 @@ function registerTemplateCommands(parent) {
|
|
|
245005
245616
|
let filename;
|
|
245006
245617
|
const isTmpl = TemplateIdSchema.safeParse(templateArg).success;
|
|
245007
245618
|
if (isTmpl) {
|
|
245008
|
-
const client =
|
|
245619
|
+
const client = buildClient5(opts);
|
|
245009
245620
|
const downloaded = await downloadTemplateBytes(client, templateArg, opts.revisionId);
|
|
245010
245621
|
bytes = downloaded.bytes;
|
|
245011
245622
|
filename = downloaded.filename;
|
|
@@ -245014,12 +245625,12 @@ function registerTemplateCommands(parent) {
|
|
|
245014
245625
|
if (!existsSync20(filePath)) {
|
|
245015
245626
|
throw new Error(`Template file not found: ${filePath}. Pass a local .docx/.xlsx path or a tmpl_… id.`);
|
|
245016
245627
|
}
|
|
245017
|
-
bytes = await
|
|
245628
|
+
bytes = await fs20.readFile(filePath);
|
|
245018
245629
|
filename = basename3(filePath);
|
|
245019
245630
|
}
|
|
245020
245631
|
const rendered = renderLocalOfficeTemplate(bytes, filename, data);
|
|
245021
245632
|
const { unresolved, unusedDataKeys } = compareTemplateDataKeys(rendered.inspection.tokens, Object.keys(data));
|
|
245022
|
-
await
|
|
245633
|
+
await fs20.writeFile(opts.out, rendered.output);
|
|
245023
245634
|
const payload = {
|
|
245024
245635
|
format: rendered.inspection.format,
|
|
245025
245636
|
sha256: rendered.inspection.sha256,
|
|
@@ -245033,7 +245644,7 @@ function registerTemplateCommands(parent) {
|
|
|
245033
245644
|
bytes: rendered.output.byteLength
|
|
245034
245645
|
};
|
|
245035
245646
|
if (opts.json) {
|
|
245036
|
-
|
|
245647
|
+
printJson5(payload);
|
|
245037
245648
|
return;
|
|
245038
245649
|
}
|
|
245039
245650
|
success(`Wrote ${ui.bold(opts.out)} (${rendered.inspection.format}, ${rendered.output.byteLength} bytes)`);
|
|
@@ -245784,20 +246395,20 @@ function relPath(root, target) {
|
|
|
245784
246395
|
}
|
|
245785
246396
|
|
|
245786
246397
|
// src/commands/workflow/index.ts
|
|
245787
|
-
function
|
|
246398
|
+
function buildClient6(opts) {
|
|
245788
246399
|
const config = resolveConfig(opts);
|
|
245789
246400
|
requireApiKey(config);
|
|
245790
246401
|
return new ApiClient(config);
|
|
245791
246402
|
}
|
|
245792
246403
|
async function buildClientForWorkflow(workflowIdOrSlug, opts) {
|
|
245793
|
-
const client =
|
|
246404
|
+
const client = buildClient6(opts);
|
|
245794
246405
|
const workflowId = await resolveWorkflowId(client, workflowIdOrSlug);
|
|
245795
246406
|
return { client, workflowId };
|
|
245796
246407
|
}
|
|
245797
246408
|
function descriptionFor(tool) {
|
|
245798
246409
|
return WORKFLOW_TOOL_METADATA[tool].description;
|
|
245799
246410
|
}
|
|
245800
|
-
function
|
|
246411
|
+
function printJson6(value) {
|
|
245801
246412
|
console.log(JSON.stringify(value, null, 2));
|
|
245802
246413
|
}
|
|
245803
246414
|
function extractWorkflowVersion(yaml) {
|
|
@@ -245806,7 +246417,7 @@ function extractWorkflowVersion(yaml) {
|
|
|
245806
246417
|
}
|
|
245807
246418
|
async function writeOrPrint(out, content) {
|
|
245808
246419
|
if (out) {
|
|
245809
|
-
await
|
|
246420
|
+
await fs21.writeFile(out, content);
|
|
245810
246421
|
process.stderr.write(`${ui.ok("✓")} Wrote ${ui.bold(out)}
|
|
245811
246422
|
`);
|
|
245812
246423
|
return;
|
|
@@ -245816,7 +246427,7 @@ async function writeOrPrint(out, content) {
|
|
|
245816
246427
|
async function readDirAsZip2(dir) {
|
|
245817
246428
|
const tree = {};
|
|
245818
246429
|
async function walk(current, relPrefix) {
|
|
245819
|
-
const entries = await
|
|
246430
|
+
const entries = await fs21.readdir(current, { withFileTypes: true });
|
|
245820
246431
|
for (const e of entries) {
|
|
245821
246432
|
if (e.name.startsWith(".") || e.name === "node_modules")
|
|
245822
246433
|
continue;
|
|
@@ -245825,7 +246436,7 @@ async function readDirAsZip2(dir) {
|
|
|
245825
246436
|
if (e.isDirectory())
|
|
245826
246437
|
await walk(full, rel);
|
|
245827
246438
|
else if (e.isFile())
|
|
245828
|
-
tree[rel] = new Uint8Array(await
|
|
246439
|
+
tree[rel] = new Uint8Array(await fs21.readFile(full));
|
|
245829
246440
|
}
|
|
245830
246441
|
}
|
|
245831
246442
|
await walk(dir, "");
|
|
@@ -245845,7 +246456,7 @@ async function downloadStreamToFile2(client, path, outFile) {
|
|
|
245845
246456
|
const res = await client.getStream(path);
|
|
245846
246457
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
245847
246458
|
if (outFile) {
|
|
245848
|
-
await
|
|
246459
|
+
await fs21.writeFile(outFile, buf);
|
|
245849
246460
|
process.stderr.write(`${ui.ok("✓")} Wrote ${ui.bold(outFile)} ${ui.dim(`(${buf.byteLength} bytes)`)}
|
|
245850
246461
|
`);
|
|
245851
246462
|
return;
|
|
@@ -245884,6 +246495,7 @@ YAML's \`name:\` field). Both:
|
|
|
245884
246495
|
$ eigenpal workflow pull my-extraction
|
|
245885
246496
|
`);
|
|
245886
246497
|
registerWorkflowCoreCommands(workflow);
|
|
246498
|
+
registerWorkflowFolderCommands(workflow);
|
|
245887
246499
|
registerEvaluatorsCommands(workflow);
|
|
245888
246500
|
registerDatasetCommands2(workflow);
|
|
245889
246501
|
registerTemplateCommands(workflow);
|
|
@@ -245898,7 +246510,7 @@ YAML's \`name:\` field). Both:
|
|
|
245898
246510
|
function registerWorkflowCoreCommands(parent) {
|
|
245899
246511
|
const listCmd = parent.command("list").description(descriptionFor("workflow_list")).option("--search <q>", "Filter by name");
|
|
245900
246512
|
addJsonFlag(withBaseUrl(withPagination(listCmd))).action(action(async (opts) => {
|
|
245901
|
-
const client =
|
|
246513
|
+
const client = buildClient6(opts);
|
|
245902
246514
|
const params = {
|
|
245903
246515
|
limit: String(opts.limit),
|
|
245904
246516
|
offset: String(opts.offset)
|
|
@@ -246000,8 +246612,8 @@ new uploads are deleted. The file on disk is not rewritten.
|
|
|
246000
246612
|
throw new Error("Missing --file <yaml>.");
|
|
246001
246613
|
}
|
|
246002
246614
|
}
|
|
246003
|
-
const yamlOnDisk = await
|
|
246004
|
-
const client =
|
|
246615
|
+
const yamlOnDisk = await fs21.readFile(filePath, "utf8");
|
|
246616
|
+
const client = buildClient6(opts);
|
|
246005
246617
|
const definition = parseWorkflowOrThrow(yamlOnDisk);
|
|
246006
246618
|
const loadedTemplates = await loadLocalTemplatesForPush(filePath, definition.steps, {
|
|
246007
246619
|
allowExternal: Boolean(opts.allowExternalTemplates)
|
|
@@ -246059,7 +246671,7 @@ new uploads are deleted. The file on disk is not rewritten.
|
|
|
246059
246671
|
});
|
|
246060
246672
|
await finalizeCreatedWorkspaceTemplates(client, created);
|
|
246061
246673
|
if (opts.json) {
|
|
246062
|
-
|
|
246674
|
+
printJson6(withLocalTemplates(result, resolvedTemplates));
|
|
246063
246675
|
return;
|
|
246064
246676
|
}
|
|
246065
246677
|
success(`Pushed ${ui.bold(workflowId)} (v${result.version ?? nextVersion})`);
|
|
@@ -246073,7 +246685,7 @@ new uploads are deleted. The file on disk is not rewritten.
|
|
|
246073
246685
|
});
|
|
246074
246686
|
await finalizeCreatedWorkspaceTemplates(client, created);
|
|
246075
246687
|
if (opts.json) {
|
|
246076
|
-
|
|
246688
|
+
printJson6(withLocalTemplates(result, resolvedTemplates));
|
|
246077
246689
|
return;
|
|
246078
246690
|
}
|
|
246079
246691
|
const id = result.workflow?.id ?? result.id ?? "?";
|
|
@@ -246085,19 +246697,56 @@ new uploads are deleted. The file on disk is not rewritten.
|
|
|
246085
246697
|
await rethrowAfterTemplateCleanup(client, created, err);
|
|
246086
246698
|
}
|
|
246087
246699
|
}));
|
|
246088
|
-
const moveCmd = parent.command("move <workflow-id>").description("Move a workflow to a folder path, creating folders as needed").requiredOption("--folder <path>", "Target folder path (`/` for root)")
|
|
246700
|
+
const moveCmd = parent.command("move <workflow-id>").description("Move a workflow to a folder path, creating folders as needed").requiredOption("--folder <path>", "Target folder path (`/` for root)").addHelpText("after", `
|
|
246701
|
+
Uses the public \`/v1/automations/{id}\` move API. \`/\` moves the workflow to
|
|
246702
|
+
the root. Agents cannot be moved with this command.
|
|
246703
|
+
`);
|
|
246089
246704
|
addJsonFlag(withBaseUrl(moveCmd)).action(action(async (workflow, opts) => {
|
|
246090
246705
|
const { client, workflowId } = await buildClientForWorkflow(workflow, opts);
|
|
246091
|
-
const
|
|
246706
|
+
const automation = await fetchAutomation(client, workflowId);
|
|
246707
|
+
if (automation.type != null && automation.type !== "workflow") {
|
|
246708
|
+
throw new Error(`${workflowId} is an agent, not a workflow. Agents do not support folder placement.`);
|
|
246709
|
+
}
|
|
246710
|
+
const result = await client.patch(`/v1/automations/${encodeURIComponent(workflowId)}`, {
|
|
246092
246711
|
folderPath: opts.folder
|
|
246093
246712
|
});
|
|
246094
246713
|
if (opts.json) {
|
|
246095
|
-
|
|
246714
|
+
printJson6(result);
|
|
246096
246715
|
return;
|
|
246097
246716
|
}
|
|
246098
246717
|
const target = opts.folder.trim() === "/" ? "root" : opts.folder;
|
|
246099
246718
|
success(`Moved ${ui.bold(workflowId)} to ${ui.bold(target)}`);
|
|
246100
246719
|
}));
|
|
246720
|
+
const deleteCmd = parent.command("delete <workflow-id>").description("Delete a workflow definition while preserving past runs.").option("--yes", "Skip typed-id confirmation (required in CI / agent terminals without a TTY)").addHelpText("after", `
|
|
246721
|
+
Permanently deletes the workflow definition and version history. Existing run
|
|
246722
|
+
history is preserved and marked as belonging to a deleted workflow.
|
|
246723
|
+
|
|
246724
|
+
Pass \`--yes\` in scripts, CI, and agent terminals (non-TTY). In a TTY, type the
|
|
246725
|
+
resolved workflow id to confirm.
|
|
246726
|
+
`);
|
|
246727
|
+
addJsonFlag(withBaseUrl(deleteCmd)).action(action(async (workflow, opts) => {
|
|
246728
|
+
requireYesInNonInteractive(opts.yes, "delete workflow");
|
|
246729
|
+
const { client, workflowId } = await buildClientForWorkflow(workflow, opts);
|
|
246730
|
+
const automation = await fetchAutomation(client, workflowId);
|
|
246731
|
+
if (automation.type != null && automation.type !== "workflow") {
|
|
246732
|
+
throw new Error(`${workflowId} is an agent, not a workflow. Use \`eigenpal agents delete\` instead.`);
|
|
246733
|
+
}
|
|
246734
|
+
warn("This permanently deletes the workflow definition and version history. Existing run history is preserved.");
|
|
246735
|
+
if (!opts.yes && isInteractiveStderr()) {
|
|
246736
|
+
await requireTypedConfirmation({
|
|
246737
|
+
id: workflowId,
|
|
246738
|
+
actionName: "delete workflow",
|
|
246739
|
+
cancelledMessage: "Workflow delete aborted"
|
|
246740
|
+
});
|
|
246741
|
+
}
|
|
246742
|
+
const result = await client.delete(`/v1/automations/${encodeURIComponent(workflowId)}`);
|
|
246743
|
+
const parsed = parseAutomationDeleteResult(result);
|
|
246744
|
+
if (opts.json) {
|
|
246745
|
+
printJson6({ ...parsed, id: workflowId });
|
|
246746
|
+
return;
|
|
246747
|
+
}
|
|
246748
|
+
success(`Deleted workflow ${ui.bold(workflowId)}`);
|
|
246749
|
+
}));
|
|
246101
246750
|
}
|
|
246102
246751
|
function withLocalTemplates(result, resolved) {
|
|
246103
246752
|
if (resolved.length === 0)
|
|
@@ -246259,13 +246908,13 @@ function registerEvaluatorsCommands(parent) {
|
|
|
246259
246908
|
}));
|
|
246260
246909
|
const pushCmd = evaluators.command("push <workflow-id>").description(descriptionFor("workflow_set_evaluators")).requiredOption("--file <yaml>", "Path to evaluators YAML file");
|
|
246261
246910
|
addJsonFlag(withBaseUrl(pushCmd)).action(action(async (workflow, opts) => {
|
|
246262
|
-
const yaml = await
|
|
246911
|
+
const yaml = await fs21.readFile(opts.file, "utf8");
|
|
246263
246912
|
const { client, workflowId } = await buildClientForWorkflow(workflow, opts);
|
|
246264
246913
|
const result = await client.put(`/v1/automations/${workflowId}/evaluators`, {
|
|
246265
246914
|
yaml
|
|
246266
246915
|
});
|
|
246267
246916
|
if (opts.json) {
|
|
246268
|
-
|
|
246917
|
+
printJson6(result);
|
|
246269
246918
|
return;
|
|
246270
246919
|
}
|
|
246271
246920
|
let count = null;
|
|
@@ -246343,8 +246992,8 @@ skip in CI). Folder layout reference: \`packages/cli/src/skill/reference/dataset
|
|
|
246343
246992
|
cancelledMessage: "Dataset replace aborted"
|
|
246344
246993
|
});
|
|
246345
246994
|
}
|
|
246346
|
-
const stat = await
|
|
246347
|
-
const data = stat.isDirectory() ? await readDirAsZip2(opts.file) : new Uint8Array(await
|
|
246995
|
+
const stat = await fs21.stat(opts.file);
|
|
246996
|
+
const data = stat.isDirectory() ? await readDirAsZip2(opts.file) : new Uint8Array(await fs21.readFile(opts.file));
|
|
246348
246997
|
const filename = stat.isDirectory() ? `${path19.basename(opts.file)}.zip` : opts.file;
|
|
246349
246998
|
const formData = new FormData;
|
|
246350
246999
|
formData.append("file", new Blob([data]), filename);
|
|
@@ -246373,7 +247022,7 @@ skip in CI). Folder layout reference: \`packages/cli/src/skill/reference/dataset
|
|
|
246373
247022
|
}));
|
|
246374
247023
|
if (issues.length === 0) {
|
|
246375
247024
|
error2("Import aborted with no structured issues — server-side bug.");
|
|
246376
|
-
|
|
247025
|
+
printJson6(terminal);
|
|
246377
247026
|
} else {
|
|
246378
247027
|
printIssues("dataset", opts.file, issues);
|
|
246379
247028
|
if (errPayload.limitMb != null && errPayload.actualMb != null) {
|
|
@@ -246394,7 +247043,7 @@ skip in CI). Folder layout reference: \`packages/cli/src/skill/reference/dataset
|
|
|
246394
247043
|
if (terminal.phase === "done") {
|
|
246395
247044
|
const done = terminal;
|
|
246396
247045
|
if (opts.json) {
|
|
246397
|
-
|
|
247046
|
+
printJson6(done);
|
|
246398
247047
|
return;
|
|
246399
247048
|
}
|
|
246400
247049
|
const created = done.created ?? 0;
|
|
@@ -246412,7 +247061,7 @@ skip in CI). Folder layout reference: \`packages/cli/src/skill/reference/dataset
|
|
|
246412
247061
|
}
|
|
246413
247062
|
} else {
|
|
246414
247063
|
error2(`Import response had unexpected terminal phase: ${terminal.phase}`);
|
|
246415
|
-
|
|
247064
|
+
printJson6(terminal);
|
|
246416
247065
|
process.exit(1);
|
|
246417
247066
|
}
|
|
246418
247067
|
}));
|
|
@@ -246437,7 +247086,7 @@ async function readJsonInput(literal, filePath, flagName) {
|
|
|
246437
247086
|
process.stdin.on("data", (chunk) => buf += chunk);
|
|
246438
247087
|
process.stdin.once("end", () => resolve(buf));
|
|
246439
247088
|
process.stdin.once("error", reject);
|
|
246440
|
-
}) : await
|
|
247089
|
+
}) : await fs21.readFile(filePath, "utf8");
|
|
246441
247090
|
try {
|
|
246442
247091
|
return JSON.parse(raw);
|
|
246443
247092
|
} catch (err) {
|
|
@@ -246472,7 +247121,7 @@ exclusive. To attach files without a dataset folder, pass ingress refs in JSON:
|
|
|
246472
247121
|
const { client, workflowId } = await buildClientForWorkflow(workflow, opts);
|
|
246473
247122
|
const result = await client.post(`/v1/automations/${workflowId}/examples`, body);
|
|
246474
247123
|
if (opts.json) {
|
|
246475
|
-
|
|
247124
|
+
printJson6(result);
|
|
246476
247125
|
return;
|
|
246477
247126
|
}
|
|
246478
247127
|
success(`Created example ${ui.bold(opts.name)} (${result.id}) in ${ui.bold(workflowId)}`);
|
|
@@ -246498,7 +247147,7 @@ exclusive. To attach files without a dataset folder, pass ingress refs in JSON:
|
|
|
246498
247147
|
const { client, workflowId } = await buildClientForWorkflow(workflow, opts);
|
|
246499
247148
|
const result = await client.patch(`/v1/automations/${workflowId}/examples/${encodeURIComponent(exampleId)}`, body);
|
|
246500
247149
|
if (opts.json) {
|
|
246501
|
-
|
|
247150
|
+
printJson6(result);
|
|
246502
247151
|
return;
|
|
246503
247152
|
}
|
|
246504
247153
|
const fields = Object.keys(body).join(", ");
|
|
@@ -246512,7 +247161,7 @@ exclusive. To attach files without a dataset folder, pass ingress refs in JSON:
|
|
|
246512
247161
|
const { client, workflowId } = await buildClientForWorkflow(workflow, opts);
|
|
246513
247162
|
const deleted = await client.delete(`/v1/automations/${workflowId}/examples/${encodeURIComponent(exampleId)}`);
|
|
246514
247163
|
if (opts.json) {
|
|
246515
|
-
|
|
247164
|
+
printJson6(deleted);
|
|
246516
247165
|
return;
|
|
246517
247166
|
}
|
|
246518
247167
|
success(`Deleted example ${ui.bold(deleted.name ?? exampleId)} ${ui.dim(`(${exampleId})`)} from ${ui.bold(workflowId)}`);
|
|
@@ -246522,7 +247171,7 @@ exclusive. To attach files without a dataset folder, pass ingress refs in JSON:
|
|
|
246522
247171
|
const { client, workflowId } = await buildClientForWorkflow(workflow, opts);
|
|
246523
247172
|
const row = await client.get(`/v1/automations/${workflowId}/examples/${encodeURIComponent(exampleId)}`);
|
|
246524
247173
|
if (opts.json) {
|
|
246525
|
-
|
|
247174
|
+
printJson6(row);
|
|
246526
247175
|
return;
|
|
246527
247176
|
}
|
|
246528
247177
|
renderExampleHuman(row);
|
|
@@ -246649,7 +247298,7 @@ returns immediately with \`{ batchId, total }\`; poll
|
|
|
246649
247298
|
const total = start.runCount ?? start.total ?? 0;
|
|
246650
247299
|
if (!opts.wait) {
|
|
246651
247300
|
if (opts.json) {
|
|
246652
|
-
|
|
247301
|
+
printJson6({ ...start, batchId: experimentId, total });
|
|
246653
247302
|
return;
|
|
246654
247303
|
}
|
|
246655
247304
|
success(`Started experiment ${ui.bold(experimentId)} ${ui.dim(`(${total} run${total === 1 ? "" : "s"} queued)`)}`);
|
|
@@ -246663,7 +247312,7 @@ returns immediately with \`{ batchId, total }\`; poll
|
|
|
246663
247312
|
const status = await client.get(`/v1/automations/${workflowId}/experiments/${experimentId}`);
|
|
246664
247313
|
if (status.status === "completed") {
|
|
246665
247314
|
if (opts.json) {
|
|
246666
|
-
|
|
247315
|
+
printJson6({
|
|
246667
247316
|
...status,
|
|
246668
247317
|
batchId: experimentId,
|
|
246669
247318
|
total: status.runCount ?? status.total
|
|
@@ -246683,7 +247332,7 @@ returns immediately with \`{ batchId, total }\`; poll
|
|
|
246683
247332
|
}
|
|
246684
247333
|
if (Date.now() >= deadline) {
|
|
246685
247334
|
if (opts.json) {
|
|
246686
|
-
|
|
247335
|
+
printJson6({
|
|
246687
247336
|
...status,
|
|
246688
247337
|
batchId: experimentId,
|
|
246689
247338
|
total: status.runCount ?? status.total
|
|
@@ -246723,12 +247372,12 @@ returns immediately with \`{ batchId, total }\`; poll
|
|
|
246723
247372
|
const summary = summarizeExperimentExecutions(execs);
|
|
246724
247373
|
if (execs.length === 0) {
|
|
246725
247374
|
if (opts.json)
|
|
246726
|
-
|
|
247375
|
+
printJson6({ ...result, summary: rollupForJson(summary) });
|
|
246727
247376
|
error2(`Experiment ${batchId} still has no executions after retrying — check the batch id.`);
|
|
246728
247377
|
process.exit(1);
|
|
246729
247378
|
}
|
|
246730
247379
|
if (opts.json) {
|
|
246731
|
-
|
|
247380
|
+
printJson6({ ...result, summary: rollupForJson(summary) });
|
|
246732
247381
|
return;
|
|
246733
247382
|
}
|
|
246734
247383
|
if (opts.short) {
|
|
@@ -246760,7 +247409,7 @@ returns immediately with \`{ batchId, total }\`; poll
|
|
|
246760
247409
|
maxWait: opts.maxWait,
|
|
246761
247410
|
onTerminal: (result, summary) => {
|
|
246762
247411
|
if (wantPayload) {
|
|
246763
|
-
|
|
247412
|
+
printJson6({ ...result, summary: rollupForJson(summary) });
|
|
246764
247413
|
} else {
|
|
246765
247414
|
process.stderr.write(`${ui.dim(`use --include payload (or --json) for the full per-execution snapshot`)}
|
|
246766
247415
|
`);
|
|
@@ -246768,7 +247417,7 @@ returns immediately with \`{ batchId, total }\`; poll
|
|
|
246768
247417
|
},
|
|
246769
247418
|
onDeadline: (result, summary) => {
|
|
246770
247419
|
if (wantPayload)
|
|
246771
|
-
|
|
247420
|
+
printJson6({ ...result, summary: rollupForJson(summary) });
|
|
246772
247421
|
}
|
|
246773
247422
|
});
|
|
246774
247423
|
}));
|
|
@@ -246792,7 +247441,7 @@ Behavior:
|
|
|
246792
247441
|
const { client, workflowId } = await buildClientForWorkflow(workflow, opts);
|
|
246793
247442
|
const result = await client.post(`/v1/automations/${workflowId}/experiments/${batchId}/cancel`);
|
|
246794
247443
|
if (opts.json) {
|
|
246795
|
-
|
|
247444
|
+
printJson6(result);
|
|
246796
247445
|
return;
|
|
246797
247446
|
}
|
|
246798
247447
|
const c = result.counts;
|
|
@@ -246866,7 +247515,7 @@ batches must belong to the same workflow within the caller's tenant.
|
|
|
246866
247515
|
if (!Number.isFinite(threshold) || threshold < 0) {
|
|
246867
247516
|
throw new Error("--regression-threshold must be a non-negative number");
|
|
246868
247517
|
}
|
|
246869
|
-
const client =
|
|
247518
|
+
const client = buildClient6(opts);
|
|
246870
247519
|
if (opts.outputs) {
|
|
246871
247520
|
const [outputsA, outputsB] = await Promise.all([
|
|
246872
247521
|
fetchExperimentOutputs(client, batchIdA),
|
|
@@ -246882,7 +247531,7 @@ batches must belong to the same workflow within the caller's tenant.
|
|
|
246882
247531
|
rowsB: outputsB.rows
|
|
246883
247532
|
});
|
|
246884
247533
|
if (opts.json)
|
|
246885
|
-
|
|
247534
|
+
printJson6(outputDiff);
|
|
246886
247535
|
else
|
|
246887
247536
|
renderExperimentOutputDiffHuman(outputDiff);
|
|
246888
247537
|
return;
|
|
@@ -246900,7 +247549,7 @@ batches must belong to the same workflow within the caller's tenant.
|
|
|
246900
247549
|
regressionThreshold: threshold
|
|
246901
247550
|
});
|
|
246902
247551
|
if (opts.json) {
|
|
246903
|
-
|
|
247552
|
+
printJson6(diff);
|
|
246904
247553
|
return;
|
|
246905
247554
|
}
|
|
246906
247555
|
renderBatchDiffHuman(diff);
|
|
@@ -247158,7 +247807,7 @@ sent to the server is replaced with \`templateId\` + \`templateRevisionId\`.
|
|
|
247158
247807
|
let yamlOnDisk;
|
|
247159
247808
|
let loadedTemplates = [];
|
|
247160
247809
|
if (opts.file) {
|
|
247161
|
-
yamlOnDisk = await
|
|
247810
|
+
yamlOnDisk = await fs21.readFile(opts.file, "utf8");
|
|
247162
247811
|
const definition = parseWorkflowOrThrow(yamlOnDisk);
|
|
247163
247812
|
loadedTemplates = await loadLocalTemplatesForPush(opts.file, definition.steps, {
|
|
247164
247813
|
allowExternal: Boolean(opts.allowExternalTemplates)
|
|
@@ -247185,7 +247834,7 @@ sent to the server is replaced with \`templateId\` + \`templateRevisionId\`.
|
|
|
247185
247834
|
const result = await client.post(automationVersionsPath(workflowId), body).catch((err) => rethrowAfterTemplateCleanup(client, created, err));
|
|
247186
247835
|
await finalizeCreatedWorkspaceTemplates(client, created);
|
|
247187
247836
|
if (opts.json) {
|
|
247188
|
-
|
|
247837
|
+
printJson6(withLocalTemplates(result, resolvedTemplates));
|
|
247189
247838
|
return;
|
|
247190
247839
|
}
|
|
247191
247840
|
const id = typeof result.id === "string" ? result.id : "?";
|
|
@@ -247208,7 +247857,7 @@ restore HEAD) return 404 — create a tagged copy first.
|
|
|
247208
247857
|
const { client, workflowId } = await buildClientForWorkflow(workflow, opts);
|
|
247209
247858
|
const result = await client.post(automationVersionsPath(workflowId, `/${encodeURIComponent(versionId)}/promote`));
|
|
247210
247859
|
if (opts.json) {
|
|
247211
|
-
|
|
247860
|
+
printJson6(result);
|
|
247212
247861
|
return;
|
|
247213
247862
|
}
|
|
247214
247863
|
const label = formatWorkflowVersionLabel(result.version);
|
|
@@ -247231,7 +247880,7 @@ promoted until you create a tagged copy.
|
|
|
247231
247880
|
const body = opts.message ? { message: opts.message } : {};
|
|
247232
247881
|
const result = await client.post(automationVersionsPath(workflowId, `/${encodeURIComponent(versionId)}/restore`), body);
|
|
247233
247882
|
if (opts.json) {
|
|
247234
|
-
|
|
247883
|
+
printJson6(result);
|
|
247235
247884
|
return;
|
|
247236
247885
|
}
|
|
247237
247886
|
const id = typeof result.id === "string" ? result.id : "?";
|
|
@@ -247494,8 +248143,8 @@ var HELP_GROUPS = [
|
|
|
247494
248143
|
},
|
|
247495
248144
|
{
|
|
247496
248145
|
title: "Run",
|
|
247497
|
-
description: "Start runs,
|
|
247498
|
-
commands: ["run", "rerun", "runs"]
|
|
248146
|
+
description: "Start runs, watch them, download artifacts, and work live human-review queues for paused runs.",
|
|
248147
|
+
commands: ["run", "rerun", "runs", "reviews"]
|
|
247499
248148
|
},
|
|
247500
248149
|
{
|
|
247501
248150
|
title: "Tooling",
|
|
@@ -247711,6 +248360,7 @@ registerModelsCommands(program2);
|
|
|
247711
248360
|
registerEmailServersCommands(program2);
|
|
247712
248361
|
registerRunCommands(program2);
|
|
247713
248362
|
registerRunsCommands(program2);
|
|
248363
|
+
registerReviewsCommands(program2);
|
|
247714
248364
|
registerGitCommands(program2);
|
|
247715
248365
|
registerDocsCommands(program2);
|
|
247716
248366
|
program2.command("completion <shell>").description("Print a shell completion script to stdout (supported shells: bash, zsh, fish). Pipe into the appropriate completion file for your shell — see the script header for install instructions.").action(async (shell) => {
|