@eigenpal/cli 0.4.17 → 0.5.1
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 +1 -0
- package/dist/cli.js +799 -43
- package/dist/skill/SKILL.md +264 -444
- package/dist/skill/reference/cli/agent.md +536 -98
- package/dist/skill/reference/cli/auth.md +5 -5
- package/dist/skill/reference/cli/skill.md +5 -5
- package/dist/skill/reference/cli/workflow.md +76 -76
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1019,7 +1019,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1019
1019
|
this._exitCallback = (err) => {
|
|
1020
1020
|
if (err.code !== "commander.executeSubCommandAsync") {
|
|
1021
1021
|
throw err;
|
|
1022
|
-
}
|
|
1022
|
+
}
|
|
1023
1023
|
};
|
|
1024
1024
|
}
|
|
1025
1025
|
return this;
|
|
@@ -20343,7 +20343,7 @@ function finalize(ctx, schema) {
|
|
|
20343
20343
|
result.$schema = "http://json-schema.org/draft-07/schema#";
|
|
20344
20344
|
} else if (ctx.target === "draft-04") {
|
|
20345
20345
|
result.$schema = "http://json-schema.org/draft-04/schema#";
|
|
20346
|
-
} else if (ctx.target === "openapi-3.0") {}
|
|
20346
|
+
} else if (ctx.target === "openapi-3.0") {}
|
|
20347
20347
|
if (ctx.external?.uri) {
|
|
20348
20348
|
const id = ctx.external.registry.get(schema)?.id;
|
|
20349
20349
|
if (!id)
|
|
@@ -20604,7 +20604,7 @@ var formatMap, stringProcessor = (schema, ctx, _json, _params) => {
|
|
|
20604
20604
|
if (val === undefined) {
|
|
20605
20605
|
if (ctx.unrepresentable === "throw") {
|
|
20606
20606
|
throw new Error("Literal `undefined` cannot be represented in JSON Schema");
|
|
20607
|
-
}
|
|
20607
|
+
}
|
|
20608
20608
|
} else if (typeof val === "bigint") {
|
|
20609
20609
|
if (ctx.unrepresentable === "throw") {
|
|
20610
20610
|
throw new Error("BigInt literals cannot be represented in JSON Schema");
|
|
@@ -27388,7 +27388,7 @@ var require_tracestate_impl = __commonJS((exports) => {
|
|
|
27388
27388
|
const value = listMember.slice(i + 1, part.length);
|
|
27389
27389
|
if ((0, tracestate_validators_1.validateKey)(key) && (0, tracestate_validators_1.validateValue)(value)) {
|
|
27390
27390
|
agg.set(key, value);
|
|
27391
|
-
}
|
|
27391
|
+
}
|
|
27392
27392
|
}
|
|
27393
27393
|
return agg;
|
|
27394
27394
|
}, new Map);
|
|
@@ -181229,7 +181229,7 @@ import { fileURLToPath as fileURLToPath6 } from "url";
|
|
|
181229
181229
|
// package.json
|
|
181230
181230
|
var package_default = {
|
|
181231
181231
|
name: "@eigenpal/cli",
|
|
181232
|
-
version: "0.
|
|
181232
|
+
version: "0.5.1",
|
|
181233
181233
|
description: "Eigenpal CLI — author and run document workflows from your terminal. Agent-ready.",
|
|
181234
181234
|
keywords: [
|
|
181235
181235
|
"eigenpal",
|
|
@@ -181304,7 +181304,9 @@ var package_default = {
|
|
|
181304
181304
|
|
|
181305
181305
|
// src/commands/agent.ts
|
|
181306
181306
|
var import_yaml = __toESM(require_dist(), 1);
|
|
181307
|
-
import {
|
|
181307
|
+
import { spawnSync } from "node:child_process";
|
|
181308
|
+
import { createHash } from "node:crypto";
|
|
181309
|
+
import { existsSync as existsSync2, promises as fs, readFileSync as readFileSync2 } from "node:fs";
|
|
181308
181310
|
import path from "node:path";
|
|
181309
181311
|
import { createInterface } from "node:readline/promises";
|
|
181310
181312
|
|
|
@@ -181387,6 +181389,15 @@ class ApiClient {
|
|
|
181387
181389
|
});
|
|
181388
181390
|
return this.handleResponse(res, url);
|
|
181389
181391
|
}
|
|
181392
|
+
async put(path, body) {
|
|
181393
|
+
const url = `${this.baseUrl}${path}`;
|
|
181394
|
+
const res = await fetch(url, {
|
|
181395
|
+
method: "PUT",
|
|
181396
|
+
headers: this.headers({ "Content-Type": "application/json" }),
|
|
181397
|
+
body: body !== undefined ? JSON.stringify(body) : undefined
|
|
181398
|
+
});
|
|
181399
|
+
return this.handleResponse(res, url);
|
|
181400
|
+
}
|
|
181390
181401
|
async patch(path, body) {
|
|
181391
181402
|
const url = `${this.baseUrl}${path}`;
|
|
181392
181403
|
const res = await fetch(url, {
|
|
@@ -181948,6 +181959,7 @@ Examples:
|
|
|
181948
181959
|
Version flags are intentionally unsupported for agents in this release.
|
|
181949
181960
|
`).action(action(pushAgent));
|
|
181950
181961
|
withBaseUrl(agent.command("pull <agent-id-or-slug>")).description("Download an agent project as agent.yaml, agent/, and dataset/.").option("--out <dir>", "Output directory").action(action(pullAgent));
|
|
181962
|
+
registerAgentFileCommands(agent);
|
|
181951
181963
|
addJsonFlag(agent.command("validate [dir]")).description("Validate a local agent project layout.").action(action(validateAgentCommand));
|
|
181952
181964
|
registerDatasetCommands(agent);
|
|
181953
181965
|
registerExecutionCommands(agent);
|
|
@@ -181957,6 +181969,16 @@ Version flags are intentionally unsupported for agents in this release.
|
|
|
181957
181969
|
registerComingSoon(agent, "evaluators", "Agent evaluators are reserved for future workflow-style evaluators.");
|
|
181958
181970
|
registerComingSoon(agent, "versions", "Agent versions are coming soon.");
|
|
181959
181971
|
}
|
|
181972
|
+
function registerAgentFileCommands(agent) {
|
|
181973
|
+
const file2 = agent.command("file").description("List, download, and upload individual live agent files.").action(() => {
|
|
181974
|
+
process.stderr.write("`eigenpal agent file` requires a subcommand. Run `eigenpal agent file --help`.\n");
|
|
181975
|
+
process.exit(2);
|
|
181976
|
+
});
|
|
181977
|
+
addJsonFlag(withBaseUrl(file2.command("list <agent-id-or-slug>"))).description("List live files for an agent.").option("--path <prefix>", "Only list files beneath this relative path").action(action(listAgentFiles));
|
|
181978
|
+
addJsonFlag(withBaseUrl(file2.command("get <agent-id-or-slug> <remote-path>"))).description("Download one live agent file.").option("--out <file>", "Output file path").action(action(getAgentFile));
|
|
181979
|
+
addJsonFlag(withBaseUrl(file2.command("put <agent-id-or-slug> <remote-path> <local-path>"))).description("Upload one local file into the live agent namespace.").option("--dry-run", "Validate local file and remote path without uploading").option("--preview", "Compare remote and local file without uploading").action(action(putAgentFile));
|
|
181980
|
+
addJsonFlag(withBaseUrl(file2.command("diff <agent-id-or-slug> <remote-path> <local-path>"))).description("Compare one live agent file against a local file.").action(action(diffAgentFile));
|
|
181981
|
+
}
|
|
181960
181982
|
function registerDatasetCommands(agent) {
|
|
181961
181983
|
const dataset = agent.command("dataset").description("Manage an agent dataset.").action(() => {
|
|
181962
181984
|
process.stderr.write("`eigenpal agent dataset` requires a subcommand. Run `eigenpal agent dataset --help`.\n");
|
|
@@ -181973,8 +181995,24 @@ function registerExecutionCommands(agent) {
|
|
|
181973
181995
|
process.exit(2);
|
|
181974
181996
|
});
|
|
181975
181997
|
addJsonFlag(withBaseUrl(execution.command("run <agent-id-or-slug>"))).description("Start one agent execution.").option("--input-json <json>", "JSON input object").option("--input-file <path>", "Input file to upload as multipart form-data").option("--wait", "Poll until the execution reaches a terminal status").action(action(runExecution));
|
|
181976
|
-
addJsonFlag(withBaseUrl(execution.command("get <execution-id>"))).description("Get one agent execution.").option("--include <parts>", "Comma-separated extra parts,
|
|
181977
|
-
addJsonFlag(
|
|
181998
|
+
addJsonFlag(withBaseUrl(execution.command("get <execution-id>"))).description("Get one agent execution.").option("--include <parts>", "Comma-separated extra parts: feedback,expected,files,trace,issues", "feedback").action(action(getExecution));
|
|
181999
|
+
addJsonFlag(withBaseUrl(execution.command("rerun <execution-id>"))).description("Create a new execution from a previous execution's stored input snapshot.").option("--wait", "Poll until the rerun reaches a terminal status").option("--interval <seconds>", "Polling interval in seconds", intArg, 2).option("--max-wait <seconds>", "Maximum wait before exiting 2", intArg, 1800).action(action(rerunExecution));
|
|
182000
|
+
const list = addJsonFlag(withPagination(withBaseUrl(execution.command("list <agent-id-or-slug>")), 50)).description("List agent executions.").option("--status <status>", "Filter by status").option("--batch-id <id>", "Filter by experiment batch id").option("--example-name <name>", "Filter by exact dataset example name").option("--example-name-contains <q>", "Filter by substring in example name").option("--created-after <time>", "Filter by created-at lower bound").option("--created-before <time>", "Filter by created-at upper bound").option("--completed-after <time>", "Filter by completed-at lower bound").option("--completed-before <time>", "Filter by completed-at upper bound").option("--feedback-status <open|resolved|ignored>", "Filter by feedback status").option("--feedback-rating <pass|fail|partial|none>", "Filter by feedback rating").option("--feedback-body-contains <q>", "Filter by feedback body substring").option("--feedback-created-after <time>", "Filter by feedback created-at lower bound").option("--feedback-created-before <time>", "Filter by feedback created-at upper bound").option("--feedback-updated-after <time>", "Filter by feedback updated-at lower bound").option("--feedback-updated-before <time>", "Filter by feedback updated-at upper bound").option("--feedback-resolved-after <time>", "Filter by feedback resolved-at lower bound").option("--feedback-resolved-before <time>", "Filter by feedback resolved-at upper bound").option("--has-feedback", "Only executions with feedback").option("--no-feedback", "Only executions without feedback").option("--has-expected", "Only executions with expected JSON or files").option("--has-expected-json", "Only executions with expected.json").option("--has-expected-files", "Only executions with expected files").option("--promoted-to-example", "Only executions promoted to dataset examples").option("--promoted-example-name <name>", "Filter by promoted dataset example name").option("--since-last-resolved", "Only executions created after the latest resolved feedback").option("--include <parts>", "Comma-separated extra parts: feedback,expected,files").option("--compact", "Return/print compact triage rows without full output payloads").option("--sort <field>", "Sort by createdAt, completedAt, status, or exampleName").option("--order <asc|desc>", "Sort direction").option("--scan-limit <n>", "Feedback scan window for feedback filters", intArg).action(action(listExecutions));
|
|
182001
|
+
list.addHelpText("after", `
|
|
182002
|
+
Examples:
|
|
182003
|
+
$ eigenpal agent execution list incorporator --feedback-rating fail --since-last-resolved --include feedback,expected
|
|
182004
|
+
$ eigenpal agent execution list activities --has-expected-files --created-after 2026-05-01
|
|
182005
|
+
`);
|
|
182006
|
+
withBaseUrl(execution.command("pull <execution-id>")).description("Download execution feedback, expected artifacts, files, and metadata.").option("--out <dir>", "Output directory").option("--include <parts>", "Comma-separated parts: feedback,expected,files,output,input,metadata,issues,trace,all", "feedback,expected").option("--json", "Output a JSON summary of written artifacts").action(action(pullExecution));
|
|
182007
|
+
addJsonFlag(withBaseUrl(execution.command("compare <reference-execution-id> <execution-id>"))).description("Compare one execution against another execution. PDF/DOCX text comparison uses pdftotext/python3 and reports byte fallbacks.").option("--baseline", "Compare actual outputs from both executions instead of expected artifacts").option("--out <dir>", "Write comparison artifacts to this directory").option("--normalize-dates", "Normalize YYYYMMDD and YYYY-MM-DD tokens in filenames/text").option("--fail-on-diff", "Exit 1 when comparison status is fail").action(action(compareExecution));
|
|
182008
|
+
const artifacts = execution.command("artifacts").description("Inspect execution artifact inventory.").action(() => {
|
|
182009
|
+
process.stderr.write("`eigenpal agent execution artifacts` requires a subcommand. Run `eigenpal agent execution artifacts --help`.\n");
|
|
182010
|
+
process.exit(2);
|
|
182011
|
+
});
|
|
182012
|
+
addJsonFlag(withBaseUrl(artifacts.command("list <execution-id>"))).description("List available execution artifacts without downloading them.").action(action(listExecutionArtifacts));
|
|
182013
|
+
withBaseUrl(execution.command("trace <execution-id>")).description("Print raw trace.jsonl for an execution, or write it with --out.").option("--out <file>", "Output file path").action(action(traceExecution));
|
|
182014
|
+
registerExecutionFeedbackCommands(execution);
|
|
182015
|
+
registerExecutionExpectedCommands(execution);
|
|
181978
182016
|
addJsonFlag(withBaseUrl(execution.command("watch <execution-id>"))).description("Watch an execution until it reaches a terminal status.").option("--interval <seconds>", "Polling interval in seconds", intArg, 2).option("--max-wait <seconds>", "Maximum wait before exiting 2", intArg, 1800).action(action(watchExecutionCommand));
|
|
181979
182017
|
addJsonFlag(withBaseUrl(execution.command("cancel <execution-id>"))).description("Cancel an agent execution.").option("--yes", "Required in non-interactive environments").action(action(cancelExecution));
|
|
181980
182018
|
}
|
|
@@ -181990,6 +182028,27 @@ function registerExperimentCommands(agent) {
|
|
|
181990
182028
|
addJsonFlag(withBaseUrl(experiment.command("compare <batch-id-a> <batch-id-b>"))).description("Compare two experiment batches.").option("--sort <mode>", "Accepted for compatibility; sorting happens client-side later").option("--regression-threshold <n>", "Accepted for compatibility", intArg).action(action(compareExperiments));
|
|
181991
182029
|
addJsonFlag(withBaseUrl(experiment.command("cancel <agent-id-or-slug> <batch-id>"))).description("Cancel every active execution in an experiment.").option("--yes", "Required in non-interactive environments").action(action(cancelExperiment));
|
|
181992
182030
|
}
|
|
182031
|
+
function registerExecutionFeedbackCommands(execution) {
|
|
182032
|
+
const feedback = execution.command("feedback").description("Update or clear feedback attached to an agent execution.").action(() => {
|
|
182033
|
+
process.stderr.write("`eigenpal agent execution feedback` requires a subcommand. Run `eigenpal agent execution feedback --help`.\n");
|
|
182034
|
+
process.exit(2);
|
|
182035
|
+
});
|
|
182036
|
+
addJsonFlag(withBaseUrl(feedback.command("update <execution-id>"))).description("Edit feedback state, rating, message, or expected JSON for an execution.").option("--status <open|resolved|ignored>", "Set feedback status").option("--rating <pass|fail|partial|none>", "Set feedback rating").option("--message <text>", "Set feedback message body").option("--message-file <path>", "Read feedback message body from a file").option("--expected-json <json>", "Set structured expected JSON").option("--expected-json-file <path>", "Read structured expected JSON from a file").option("--clear-message", "Clear the feedback message body").option("--clear-rating", "Clear feedback rating").option("--clear-expected-json", "Delete structured expected JSON").action(action(updateExecutionFeedback));
|
|
182037
|
+
addJsonFlag(withBaseUrl(feedback.command("resolve <execution-id>"))).description("Mark execution feedback as resolved.").option("--message <text>", "Set feedback message body").option("--message-file <path>", "Read feedback message body from a file").action(action((executionId, opts) => updateExecutionFeedback(executionId, { ...opts, status: "resolved" })));
|
|
182038
|
+
addJsonFlag(withBaseUrl(feedback.command("clear <execution-id>"))).description("Delete feedback, expected.json, and expected files for an execution.").option("--yes", "Required in non-interactive environments").action(action(clearExecutionFeedback));
|
|
182039
|
+
}
|
|
182040
|
+
function registerExecutionExpectedCommands(execution) {
|
|
182041
|
+
const expected = execution.command("expected").description("Manage expected artifacts attached to an agent execution.").action(() => {
|
|
182042
|
+
process.stderr.write("`eigenpal agent execution expected` requires a subcommand. Run `eigenpal agent execution expected --help`.\n");
|
|
182043
|
+
process.exit(2);
|
|
182044
|
+
});
|
|
182045
|
+
addJsonFlag(withBaseUrl(expected.command("list <execution-id>"))).description("List expected JSON and files attached to an execution.").action(action(listExecutionExpected));
|
|
182046
|
+
withBaseUrl(expected.command("pull <execution-id>")).description("Download expected JSON and files attached to an execution.").option("--out <dir>", "Output directory").action(action(pullExecutionExpected));
|
|
182047
|
+
addJsonFlag(withBaseUrl(expected.command("upload <execution-id> <file>"))).description("Upload a local file as an expected artifact.").option("--name <name>", "Expected artifact name").action(action(uploadExecutionExpected));
|
|
182048
|
+
addJsonFlag(withBaseUrl(expected.command("copy-output <execution-id> <output-file>"))).description("Copy a generated output file into expected artifacts.").option("--name <name>", "Expected artifact name").action(action(copyOutputToExpected));
|
|
182049
|
+
addJsonFlag(withBaseUrl(expected.command("rename <execution-id> <old-name> <new-name>"))).description("Rename an expected artifact.").action(action(renameExecutionExpected));
|
|
182050
|
+
addJsonFlag(withBaseUrl(expected.command("delete <execution-id> <name>"))).description("Delete an expected artifact.").option("--yes", "Required in non-interactive environments").action(action(deleteExecutionExpected));
|
|
182051
|
+
}
|
|
181993
182052
|
function registerSessionCommands(agent) {
|
|
181994
182053
|
const session = agent.command("session").description("Manage agent builder sessions.").action(() => {
|
|
181995
182054
|
process.stderr.write("`eigenpal agent session` requires a subcommand. Run `eigenpal agent session --help`.\n");
|
|
@@ -182108,6 +182167,55 @@ async function pullAgent(agentId, opts) {
|
|
|
182108
182167
|
await pullDataset(agentId, { ...opts, out: path.join(out, DATASET_DIR) });
|
|
182109
182168
|
success2(`Pulled agent to ${ui.bold(out)}`);
|
|
182110
182169
|
}
|
|
182170
|
+
async function listAgentFiles(agentId, opts) {
|
|
182171
|
+
const client = buildClient(opts);
|
|
182172
|
+
const payload = await client.get(`/api/v1/agents/${encodeURIComponent(agentId)}/files`, {
|
|
182173
|
+
...opts.path ? { prefix: opts.path } : {}
|
|
182174
|
+
});
|
|
182175
|
+
if (opts.json)
|
|
182176
|
+
return printJson(payload);
|
|
182177
|
+
console.log(table((payload.files ?? []).map((name) => ({ name })), [{ key: "name", header: "PATH" }]));
|
|
182178
|
+
}
|
|
182179
|
+
async function getAgentFile(agentId, remotePath, opts) {
|
|
182180
|
+
const client = buildClient(opts);
|
|
182181
|
+
const payload = await client.get(`/api/v1/agents/${encodeURIComponent(agentId)}/files`, {
|
|
182182
|
+
path: remotePath
|
|
182183
|
+
});
|
|
182184
|
+
if (opts.json)
|
|
182185
|
+
return printJson(payload);
|
|
182186
|
+
const out = path.resolve(opts.out ?? payload.path);
|
|
182187
|
+
await writeBase64File(out, payload.contentBase64);
|
|
182188
|
+
success2(`Downloaded ${payload.path} to ${ui.bold(out)}`);
|
|
182189
|
+
}
|
|
182190
|
+
async function putAgentFile(agentId, remotePath, localPath, opts) {
|
|
182191
|
+
const absolute = path.resolve(localPath);
|
|
182192
|
+
const data = await fs.readFile(absolute);
|
|
182193
|
+
if (opts.dryRun) {
|
|
182194
|
+
const payload2 = { ok: true, dryRun: true, path: remotePath, bytes: data.length };
|
|
182195
|
+
if (opts.json)
|
|
182196
|
+
return printJson(payload2);
|
|
182197
|
+
success2(`Validated ${remotePath} from ${ui.bold(absolute)} (${data.length} bytes)`);
|
|
182198
|
+
return;
|
|
182199
|
+
}
|
|
182200
|
+
if (opts.preview) {
|
|
182201
|
+
const report = await buildAgentFileDiff(agentId, remotePath, absolute, opts);
|
|
182202
|
+
if (opts.json)
|
|
182203
|
+
return printJson(report);
|
|
182204
|
+
renderAgentFileDiff(report);
|
|
182205
|
+
return;
|
|
182206
|
+
}
|
|
182207
|
+
const client = buildClient(opts);
|
|
182208
|
+
const payload = await client.put(`/api/v1/agents/${encodeURIComponent(agentId)}/files?path=${encodeURIComponent(remotePath)}`, { contentBase64: data.toString("base64") });
|
|
182209
|
+
if (opts.json)
|
|
182210
|
+
return printJson(payload);
|
|
182211
|
+
success2(`Uploaded ${remotePath} from ${ui.bold(absolute)}`);
|
|
182212
|
+
}
|
|
182213
|
+
async function diffAgentFile(agentId, remotePath, localPath, opts) {
|
|
182214
|
+
const report = await buildAgentFileDiff(agentId, remotePath, path.resolve(localPath), opts);
|
|
182215
|
+
if (opts.json)
|
|
182216
|
+
return printJson(report);
|
|
182217
|
+
renderAgentFileDiff(report);
|
|
182218
|
+
}
|
|
182111
182219
|
async function validateAgentCommand(dir = ".", opts) {
|
|
182112
182220
|
const result = await validateAgentProject(path.resolve(dir));
|
|
182113
182221
|
if (opts.json)
|
|
@@ -182184,18 +182292,302 @@ async function getExecution(executionId, opts) {
|
|
|
182184
182292
|
});
|
|
182185
182293
|
renderExecutionPayload(payload, opts);
|
|
182186
182294
|
}
|
|
182187
|
-
async function
|
|
182295
|
+
async function rerunExecution(executionId, opts) {
|
|
182188
182296
|
const client = buildClient(opts);
|
|
182189
|
-
|
|
182297
|
+
let payload = await client.post(`/api/v1/agents/executions/${encodeURIComponent(executionId)}/rerun`, {});
|
|
182298
|
+
const rerunId = String(payload.executionId ?? "");
|
|
182299
|
+
if (opts.wait && rerunId) {
|
|
182300
|
+
payload = await pollExecution(client, rerunId, opts.interval, opts.maxWait);
|
|
182301
|
+
return renderExecutionPayload(payload, opts);
|
|
182302
|
+
}
|
|
182190
182303
|
if (opts.json)
|
|
182191
182304
|
return printJson(payload);
|
|
182192
|
-
|
|
182305
|
+
success2(`Started rerun ${ui.bold(rerunId)} from ${executionId}`);
|
|
182306
|
+
}
|
|
182307
|
+
async function pullExecution(executionId, opts) {
|
|
182308
|
+
const client = buildClient(opts);
|
|
182309
|
+
const include = new Set(opts.include.split(",").map((part) => part.trim()).filter(Boolean));
|
|
182310
|
+
if (include.has("all")) {
|
|
182311
|
+
include.add("feedback");
|
|
182312
|
+
include.add("expected");
|
|
182313
|
+
include.add("files");
|
|
182314
|
+
include.add("input");
|
|
182315
|
+
include.add("output");
|
|
182316
|
+
include.add("metadata");
|
|
182317
|
+
include.add("issues");
|
|
182318
|
+
include.add("trace");
|
|
182319
|
+
}
|
|
182320
|
+
const payload = await client.get(`/api/v1/agents/executions/${encodeURIComponent(executionId)}`, { include: [...include].join(",") });
|
|
182321
|
+
const execution = payload.execution;
|
|
182322
|
+
if (!execution)
|
|
182323
|
+
throw new Error(`Execution ${executionId} not found`);
|
|
182324
|
+
const out = path.resolve(opts.out ?? path.join(".eigenpal", "artifacts", "executions", executionId));
|
|
182325
|
+
await fs.mkdir(out, { recursive: true });
|
|
182326
|
+
const written = [];
|
|
182327
|
+
const skipped = [];
|
|
182328
|
+
const writeJsonArtifact = async (name, value) => {
|
|
182329
|
+
await fs.writeFile(path.join(out, name), JSON.stringify(value, null, 2));
|
|
182330
|
+
written.push(name);
|
|
182331
|
+
};
|
|
182332
|
+
await writeJsonArtifact("execution.json", execution);
|
|
182333
|
+
const feedback = execution.feedback;
|
|
182334
|
+
if (include.has("feedback") && feedback) {
|
|
182335
|
+
await fs.writeFile(path.join(out, "feedback.md"), serializeCliFeedback(feedback));
|
|
182336
|
+
written.push("feedback.md");
|
|
182337
|
+
} else if (include.has("feedback")) {
|
|
182338
|
+
skipped.push("feedback");
|
|
182339
|
+
}
|
|
182340
|
+
if (include.has("expected")) {
|
|
182341
|
+
written.push(...await writeExpectedArtifacts(client, executionId, out, execution));
|
|
182342
|
+
}
|
|
182343
|
+
if (include.has("files") || include.has("output")) {
|
|
182344
|
+
written.push(...await writeListedFiles(client, executionId, out, "output", execution.resultFiles));
|
|
182345
|
+
}
|
|
182346
|
+
if (include.has("files") || include.has("input")) {
|
|
182347
|
+
written.push(...await writeListedFiles(client, executionId, out, "input", execution.inputFiles));
|
|
182348
|
+
if (execution.inputJson) {
|
|
182349
|
+
await writeJsonArtifact("input.json", execution.inputJson);
|
|
182350
|
+
} else {
|
|
182351
|
+
skipped.push("input.json");
|
|
182352
|
+
}
|
|
182353
|
+
}
|
|
182354
|
+
if (include.has("files") || include.has("metadata")) {
|
|
182355
|
+
if (execution.metadata) {
|
|
182356
|
+
await writeJsonArtifact("metadata.json", execution.metadata);
|
|
182357
|
+
} else {
|
|
182358
|
+
skipped.push("metadata.json");
|
|
182359
|
+
}
|
|
182360
|
+
}
|
|
182361
|
+
if (include.has("files") || include.has("issues")) {
|
|
182362
|
+
const file2 = await writeDiagnosticFile(client, executionId, out, "issues", "issues.md", execution.issueFiles);
|
|
182363
|
+
if (file2)
|
|
182364
|
+
written.push(file2);
|
|
182365
|
+
else
|
|
182366
|
+
skipped.push("issues.md");
|
|
182367
|
+
}
|
|
182368
|
+
if (include.has("files") || include.has("trace")) {
|
|
182369
|
+
const file2 = await writeDiagnosticFile(client, executionId, out, "trace", "trace.jsonl", execution.traceFiles);
|
|
182370
|
+
if (file2)
|
|
182371
|
+
written.push(file2);
|
|
182372
|
+
else
|
|
182373
|
+
skipped.push("trace.jsonl");
|
|
182374
|
+
}
|
|
182375
|
+
const summary = {
|
|
182376
|
+
executionId,
|
|
182377
|
+
out,
|
|
182378
|
+
written,
|
|
182379
|
+
skipped,
|
|
182380
|
+
counts: {
|
|
182381
|
+
written: written.length,
|
|
182382
|
+
skipped: skipped.length
|
|
182383
|
+
}
|
|
182384
|
+
};
|
|
182385
|
+
if (opts.json)
|
|
182386
|
+
return printJson(summary);
|
|
182387
|
+
success2(`Pulled execution ${executionId} to ${out}`);
|
|
182388
|
+
dim(`Wrote ${written.length} artifact${written.length === 1 ? "" : "s"}${skipped.length ? `; skipped missing ${skipped.join(", ")}` : ""}`);
|
|
182389
|
+
}
|
|
182390
|
+
async function listExecutionArtifacts(executionId, opts) {
|
|
182391
|
+
const client = buildClient(opts);
|
|
182392
|
+
const payload = await client.get(`/api/v1/agents/executions/${encodeURIComponent(executionId)}`, { include: "expected,files,input,output,issues,trace,metadata" });
|
|
182393
|
+
const execution = payload.execution;
|
|
182394
|
+
if (!execution)
|
|
182395
|
+
throw new Error(`Execution ${executionId} not found`);
|
|
182396
|
+
const artifacts = executionArtifactInventory(execution);
|
|
182397
|
+
if (opts.json)
|
|
182398
|
+
return printJson({ executionId, artifacts });
|
|
182399
|
+
console.log(table(artifacts, [
|
|
182400
|
+
{ key: "kind", header: "KIND" },
|
|
182401
|
+
{ key: "name", header: "NAME" },
|
|
182402
|
+
{ key: "present", header: "PRESENT" }
|
|
182403
|
+
]));
|
|
182404
|
+
}
|
|
182405
|
+
async function traceExecution(executionId, opts) {
|
|
182406
|
+
const client = buildClient(opts);
|
|
182407
|
+
const text = await downloadTraceText(client, executionId);
|
|
182408
|
+
if (!opts.out) {
|
|
182409
|
+
process.stdout.write(text);
|
|
182410
|
+
return;
|
|
182411
|
+
}
|
|
182412
|
+
const out = path.resolve(opts.out);
|
|
182413
|
+
await fs.mkdir(path.dirname(out), { recursive: true });
|
|
182414
|
+
await fs.writeFile(out, text);
|
|
182415
|
+
success2(`Downloaded trace for ${executionId} to ${ui.bold(out)}`);
|
|
182416
|
+
}
|
|
182417
|
+
async function compareExecution(referenceId, executionId, opts) {
|
|
182418
|
+
const client = buildClient(opts);
|
|
182419
|
+
const targetPayload = await client.get(`/api/v1/agents/executions/${encodeURIComponent(executionId)}`, { include: "files,output" });
|
|
182420
|
+
const target = targetPayload.execution;
|
|
182421
|
+
if (!target)
|
|
182422
|
+
throw new Error(`Execution ${executionId} not found`);
|
|
182423
|
+
const mode = opts.baseline ? "baseline" : "expected";
|
|
182424
|
+
const reference = (await client.get(`/api/v1/agents/executions/${encodeURIComponent(referenceId)}`, {
|
|
182425
|
+
include: mode === "baseline" ? "files,output" : "expected"
|
|
182426
|
+
})).execution;
|
|
182427
|
+
if (!reference)
|
|
182428
|
+
throw new Error(`Reference execution ${referenceId} not found`);
|
|
182429
|
+
const out = path.resolve(opts.out ?? path.join(".eigenpal", "artifacts", "comparisons", `${referenceId}..${executionId}`));
|
|
182430
|
+
await fs.mkdir(out, { recursive: true });
|
|
182431
|
+
const warnings = [];
|
|
182432
|
+
if (mode === "expected" && reference.expected == null && fileNames(reference.expectedFiles).length === 0) {
|
|
182433
|
+
warnings.push(`Reference execution ${referenceId} has no expected JSON or expected files; comparison has no baseline artifacts. Use --baseline to compare actual outputs.`);
|
|
182434
|
+
}
|
|
182435
|
+
const jsonDiffs = diffJson(mode === "baseline" ? reference.output : reference.expected, target.output);
|
|
182436
|
+
const expectedFiles = mode === "baseline" ? fileNames(reference.resultFiles).filter((name) => name !== "issues.md" && name !== "trace.jsonl") : fileNames(reference.expectedFiles);
|
|
182437
|
+
const outputFiles = fileNames(target.resultFiles).filter((name) => name !== "issues.md" && name !== "trace.jsonl");
|
|
182438
|
+
const inventory = compareFileInventory(expectedFiles, outputFiles, Boolean(opts.normalizeDates));
|
|
182439
|
+
const textDifferences = await compareMatchedFileText(client, { executionId: referenceId, kind: mode === "baseline" ? "output" : "expected" }, { executionId, kind: "output" }, out, inventory.matched, Boolean(opts.normalizeDates));
|
|
182440
|
+
const report = {
|
|
182441
|
+
status: jsonDiffs.length === 0 && inventory.missing.length === 0 && inventory.extra.length === 0 && textDifferences.every((diff) => diff.status === "match" || diff.status === "binary-match") ? "pass" : "fail",
|
|
182442
|
+
executionId,
|
|
182443
|
+
comparedWith: referenceId,
|
|
182444
|
+
mode,
|
|
182445
|
+
warnings,
|
|
182446
|
+
jsonDifferences: jsonDiffs,
|
|
182447
|
+
matchedFiles: inventory.matched,
|
|
182448
|
+
missingFiles: inventory.missing,
|
|
182449
|
+
extraFiles: inventory.extra,
|
|
182450
|
+
textDifferences
|
|
182451
|
+
};
|
|
182452
|
+
await fs.writeFile(path.join(out, "comparison.json"), JSON.stringify(report, null, 2));
|
|
182453
|
+
if (opts.json) {
|
|
182454
|
+
printJson(report);
|
|
182455
|
+
} else {
|
|
182456
|
+
renderComparisonReport(report);
|
|
182457
|
+
}
|
|
182458
|
+
dim(`Comparison artifacts written to ${ui.bold(out)}`);
|
|
182459
|
+
if (opts.failOnDiff && report.status === "fail")
|
|
182460
|
+
process.exit(1);
|
|
182461
|
+
}
|
|
182462
|
+
async function listExecutions(agentId, opts) {
|
|
182463
|
+
const client = buildClient(opts);
|
|
182464
|
+
const params = buildExecutionListParams(opts);
|
|
182465
|
+
const payload = await client.get(`/api/v1/agents/${encodeURIComponent(agentId)}/executions`, params);
|
|
182466
|
+
const rows = opts.compact ? payload.executions.map(compactExecutionRow) : payload.executions;
|
|
182467
|
+
if (opts.json)
|
|
182468
|
+
return printJson({ ...payload, executions: rows });
|
|
182469
|
+
if (payload.scanLimited) {
|
|
182470
|
+
warn("Feedback/expected filters scanned only the first matching window. Increase --scan-limit or narrow DB filters for a fuller result.");
|
|
182471
|
+
}
|
|
182472
|
+
if (payload.noResolvedAnchor) {
|
|
182473
|
+
warn("No resolved feedback anchor was found in the scan window; --since-last-resolved returned no rows.");
|
|
182474
|
+
}
|
|
182475
|
+
console.log(table(rows, [
|
|
182193
182476
|
{ key: "id", header: "ID" },
|
|
182194
182477
|
{ key: "status", header: "STATUS" },
|
|
182195
182478
|
{ key: "exampleId", header: "EXAMPLE" },
|
|
182479
|
+
{
|
|
182480
|
+
key: "feedback",
|
|
182481
|
+
header: "FEEDBACK",
|
|
182482
|
+
format: (value) => value && typeof value === "object" ? `${String(value.rating ?? "")}/${String(value.status ?? "")}` : ""
|
|
182483
|
+
},
|
|
182196
182484
|
{ key: "createdAt", header: "CREATED", format: formatTimestamp }
|
|
182197
182485
|
]));
|
|
182198
182486
|
}
|
|
182487
|
+
function buildExecutionListParams(opts) {
|
|
182488
|
+
return compactParams({
|
|
182489
|
+
...opts,
|
|
182490
|
+
feedback: undefined,
|
|
182491
|
+
noFeedback: opts.noFeedback ?? (opts.feedback === false ? true : undefined)
|
|
182492
|
+
});
|
|
182493
|
+
}
|
|
182494
|
+
async function updateExecutionFeedback(executionId, opts) {
|
|
182495
|
+
const client = buildClient(opts);
|
|
182496
|
+
const body = {};
|
|
182497
|
+
if (opts.status)
|
|
182498
|
+
body.status = opts.status;
|
|
182499
|
+
if (opts.rating)
|
|
182500
|
+
body.rating = opts.rating === "none" ? null : opts.rating;
|
|
182501
|
+
if (opts.clearRating)
|
|
182502
|
+
body.rating = null;
|
|
182503
|
+
if (opts.messageFile)
|
|
182504
|
+
body.body = await fs.readFile(opts.messageFile, "utf-8");
|
|
182505
|
+
if (opts.message !== undefined)
|
|
182506
|
+
body.body = opts.message;
|
|
182507
|
+
if (opts.clearMessage)
|
|
182508
|
+
body.body = "";
|
|
182509
|
+
if (opts.expectedJsonFile)
|
|
182510
|
+
body.expected = JSON.parse(await fs.readFile(opts.expectedJsonFile, "utf-8"));
|
|
182511
|
+
if (opts.expectedJson !== undefined)
|
|
182512
|
+
body.expected = JSON.parse(opts.expectedJson);
|
|
182513
|
+
if (opts.clearExpectedJson)
|
|
182514
|
+
body.expected = null;
|
|
182515
|
+
const payload = await client.patch(`/api/v1/agents/executions/${encodeURIComponent(executionId)}/feedback`, body);
|
|
182516
|
+
renderGeneric(payload, opts, `Updated feedback for ${executionId}`);
|
|
182517
|
+
}
|
|
182518
|
+
function compactExecutionRow(execution) {
|
|
182519
|
+
const feedback = execution.feedback && typeof execution.feedback === "object" ? execution.feedback : null;
|
|
182520
|
+
return {
|
|
182521
|
+
id: execution.id,
|
|
182522
|
+
status: execution.status,
|
|
182523
|
+
exampleId: execution.exampleId,
|
|
182524
|
+
feedback: feedback ? {
|
|
182525
|
+
rating: feedback.rating ?? null,
|
|
182526
|
+
status: feedback.status ?? null,
|
|
182527
|
+
updatedAt: feedback.updatedAt ?? null
|
|
182528
|
+
} : null,
|
|
182529
|
+
hasExpectedJson: execution.expected != null,
|
|
182530
|
+
expectedFileCount: Array.isArray(execution.expectedFiles) ? execution.expectedFiles.length : undefined,
|
|
182531
|
+
createdAt: execution.createdAt,
|
|
182532
|
+
completedAt: execution.completedAt
|
|
182533
|
+
};
|
|
182534
|
+
}
|
|
182535
|
+
async function clearExecutionFeedback(executionId, opts) {
|
|
182536
|
+
if (!(opts.yes || await confirmTyped(executionId, "clear feedback artifacts"))) {
|
|
182537
|
+
throw new Error("Clear cancelled");
|
|
182538
|
+
}
|
|
182539
|
+
const client = buildClient(opts);
|
|
182540
|
+
const payload = await client.delete(`/api/v1/agents/executions/${encodeURIComponent(executionId)}/feedback`);
|
|
182541
|
+
renderGeneric(payload, opts, `Cleared feedback for ${executionId}`);
|
|
182542
|
+
}
|
|
182543
|
+
async function listExecutionExpected(executionId, opts) {
|
|
182544
|
+
const client = buildClient(opts);
|
|
182545
|
+
const payload = await client.get(`/api/v1/agents/executions/${encodeURIComponent(executionId)}/expected`);
|
|
182546
|
+
if (opts.json)
|
|
182547
|
+
return printJson(payload);
|
|
182548
|
+
console.log(table(payload.files ?? [], [{ key: "name", header: "NAME" }]));
|
|
182549
|
+
if (payload.expected != null)
|
|
182550
|
+
dim("expected.json present");
|
|
182551
|
+
}
|
|
182552
|
+
async function pullExecutionExpected(executionId, opts) {
|
|
182553
|
+
const client = buildClient(opts);
|
|
182554
|
+
const payload = await client.get(`/api/v1/agents/executions/${encodeURIComponent(executionId)}/expected`);
|
|
182555
|
+
const out = path.resolve(opts.out ?? path.join(executionId, "expected"));
|
|
182556
|
+
await fs.mkdir(out, { recursive: true });
|
|
182557
|
+
if (payload.expected != null) {
|
|
182558
|
+
await fs.writeFile(path.join(out, "expected.json"), JSON.stringify(payload.expected, null, 2));
|
|
182559
|
+
}
|
|
182560
|
+
await downloadExpectedFiles(client, executionId, out, payload.files);
|
|
182561
|
+
success2(`Pulled expected artifacts for ${executionId} to ${out}`);
|
|
182562
|
+
}
|
|
182563
|
+
async function uploadExecutionExpected(executionId, file2, opts) {
|
|
182564
|
+
const client = buildClient(opts);
|
|
182565
|
+
const form = new FormData;
|
|
182566
|
+
const data = await fs.readFile(file2);
|
|
182567
|
+
form.append("file", new Blob([data]), path.basename(file2));
|
|
182568
|
+
if (opts.name)
|
|
182569
|
+
form.append("name", opts.name);
|
|
182570
|
+
const payload = await client.postFormData(`/api/v1/agents/executions/${encodeURIComponent(executionId)}/expected`, form);
|
|
182571
|
+
renderGeneric(payload, opts, `Uploaded expected file for ${executionId}`);
|
|
182572
|
+
}
|
|
182573
|
+
async function copyOutputToExpected(executionId, outputFile, opts) {
|
|
182574
|
+
const client = buildClient(opts);
|
|
182575
|
+
const payload = await client.post(`/api/v1/agents/executions/${encodeURIComponent(executionId)}/expected`, { outputFileName: outputFile, ...opts.name ? { expectedName: opts.name } : {} });
|
|
182576
|
+
renderGeneric(payload, opts, `Copied output file to expected for ${executionId}`);
|
|
182577
|
+
}
|
|
182578
|
+
async function renameExecutionExpected(executionId, oldName, newName, opts) {
|
|
182579
|
+
const client = buildClient(opts);
|
|
182580
|
+
const payload = await client.patch(`/api/v1/agents/executions/${encodeURIComponent(executionId)}/expected/${encodeURIComponent(oldName)}`, { name: newName });
|
|
182581
|
+
renderGeneric(payload, opts, `Renamed expected file for ${executionId}`);
|
|
182582
|
+
}
|
|
182583
|
+
async function deleteExecutionExpected(executionId, name, opts) {
|
|
182584
|
+
if (!(opts.yes || await confirmTyped(name, "delete expected file"))) {
|
|
182585
|
+
throw new Error("Delete cancelled");
|
|
182586
|
+
}
|
|
182587
|
+
const client = buildClient(opts);
|
|
182588
|
+
await client.delete(`/api/v1/agents/executions/${encodeURIComponent(executionId)}/expected/${encodeURIComponent(name)}`);
|
|
182589
|
+
renderGeneric({ ok: true }, opts, `Deleted expected file ${name}`);
|
|
182590
|
+
}
|
|
182199
182591
|
async function watchExecutionCommand(executionId, opts) {
|
|
182200
182592
|
const client = buildClient(opts);
|
|
182201
182593
|
const payload = await pollExecution(client, executionId, opts.interval, opts.maxWait);
|
|
@@ -182410,6 +182802,336 @@ async function buildAgentExecutionRunFormData(inputFile, inputJson) {
|
|
|
182410
182802
|
form.append("_json", inputJson);
|
|
182411
182803
|
return form;
|
|
182412
182804
|
}
|
|
182805
|
+
function serializeCliFeedback(feedback) {
|
|
182806
|
+
const keys = [
|
|
182807
|
+
"rating",
|
|
182808
|
+
"status",
|
|
182809
|
+
"createdAt",
|
|
182810
|
+
"createdBy",
|
|
182811
|
+
"createdByEmail",
|
|
182812
|
+
"updatedAt",
|
|
182813
|
+
"resolvedAt",
|
|
182814
|
+
"resolvedBy",
|
|
182815
|
+
"resolvedByEmail",
|
|
182816
|
+
"resolvedBySessionId",
|
|
182817
|
+
"promotedExampleName"
|
|
182818
|
+
];
|
|
182819
|
+
const frontmatter = keys.map((key) => `${key}: ${feedback[key] ?? ""}`).join(`
|
|
182820
|
+
`);
|
|
182821
|
+
return `---
|
|
182822
|
+
${frontmatter}
|
|
182823
|
+
---
|
|
182824
|
+
|
|
182825
|
+
${String(feedback.body ?? "").trim()}
|
|
182826
|
+
`;
|
|
182827
|
+
}
|
|
182828
|
+
async function writeExpectedArtifacts(client, executionId, out, execution) {
|
|
182829
|
+
const written = [];
|
|
182830
|
+
const expectedDir = path.join(out, "expected");
|
|
182831
|
+
await fs.mkdir(expectedDir, { recursive: true });
|
|
182832
|
+
if (execution.expected != null) {
|
|
182833
|
+
await fs.writeFile(path.join(out, "expected.json"), JSON.stringify(execution.expected, null, 2));
|
|
182834
|
+
written.push("expected.json");
|
|
182835
|
+
}
|
|
182836
|
+
written.push(...(await downloadExpectedFiles(client, executionId, expectedDir, execution.expectedFiles)).map((name) => `expected/${name}`));
|
|
182837
|
+
return written;
|
|
182838
|
+
}
|
|
182839
|
+
async function downloadExpectedFiles(client, executionId, out, files) {
|
|
182840
|
+
const rows = Array.isArray(files) ? files : [];
|
|
182841
|
+
const written = await Promise.all(rows.map(async (file2) => {
|
|
182842
|
+
const name = String(file2.name ?? "");
|
|
182843
|
+
if (!name || name.includes("/") || name.includes(".."))
|
|
182844
|
+
return null;
|
|
182845
|
+
const response = await client.getStream(`/api/v1/agents/executions/${encodeURIComponent(executionId)}/expected/${encodeURIComponent(name)}`);
|
|
182846
|
+
await fs.mkdir(out, { recursive: true });
|
|
182847
|
+
await fs.writeFile(path.join(out, name), Buffer.from(await response.arrayBuffer()));
|
|
182848
|
+
return name;
|
|
182849
|
+
}));
|
|
182850
|
+
return written.filter((name) => Boolean(name));
|
|
182851
|
+
}
|
|
182852
|
+
async function writeListedFiles(client, executionId, out, kind, files) {
|
|
182853
|
+
const rows = Array.isArray(files) ? files : [];
|
|
182854
|
+
const targetDir = path.join(out, kind);
|
|
182855
|
+
await fs.mkdir(targetDir, { recursive: true });
|
|
182856
|
+
const written = await Promise.all(rows.map(async (file2) => {
|
|
182857
|
+
const name = String(file2.name ?? "");
|
|
182858
|
+
if (!name || name.includes("/") || name.includes(".."))
|
|
182859
|
+
return null;
|
|
182860
|
+
const response = await client.getStream(`/api/v1/agents/executions/${encodeURIComponent(executionId)}/files/${kind}/${encodeURIComponent(name)}`);
|
|
182861
|
+
await fs.writeFile(path.join(targetDir, name), Buffer.from(await response.arrayBuffer()));
|
|
182862
|
+
return `${kind}/${name}`;
|
|
182863
|
+
}));
|
|
182864
|
+
return written.filter((name) => Boolean(name));
|
|
182865
|
+
}
|
|
182866
|
+
async function writeDiagnosticFile(client, executionId, out, kind, filename, files) {
|
|
182867
|
+
const rows = Array.isArray(files) ? files : [];
|
|
182868
|
+
const exists = rows.some((file2) => String(file2.name ?? "") === filename);
|
|
182869
|
+
if (!exists)
|
|
182870
|
+
return null;
|
|
182871
|
+
const response = await client.getStream(`/api/v1/agents/executions/${encodeURIComponent(executionId)}/files/${kind}/${filename}`);
|
|
182872
|
+
await fs.writeFile(path.join(out, filename), Buffer.from(await response.arrayBuffer()));
|
|
182873
|
+
return filename;
|
|
182874
|
+
}
|
|
182875
|
+
async function downloadTraceText(client, executionId) {
|
|
182876
|
+
const response = await client.getStream(`/api/v1/agents/executions/${encodeURIComponent(executionId)}/files/trace/trace.jsonl`);
|
|
182877
|
+
return Buffer.from(await response.arrayBuffer()).toString("utf-8");
|
|
182878
|
+
}
|
|
182879
|
+
function diffJson(expected, actual, basePath = "$") {
|
|
182880
|
+
if (expected === undefined || expected === null)
|
|
182881
|
+
return [];
|
|
182882
|
+
if (Object.is(expected, actual))
|
|
182883
|
+
return [];
|
|
182884
|
+
if (expected && actual && typeof expected === "object" && typeof actual === "object" && !Array.isArray(expected) && !Array.isArray(actual)) {
|
|
182885
|
+
const keys = new Set([...Object.keys(expected), ...Object.keys(actual)]);
|
|
182886
|
+
return [...keys].flatMap((key) => {
|
|
182887
|
+
const next = `${basePath}.${key}`;
|
|
182888
|
+
if (!(key in actual))
|
|
182889
|
+
return [{ path: next, type: "missing" }];
|
|
182890
|
+
if (!(key in expected))
|
|
182891
|
+
return [{ path: next, type: "extra" }];
|
|
182892
|
+
return diffJson(expected[key], actual[key], next);
|
|
182893
|
+
});
|
|
182894
|
+
}
|
|
182895
|
+
if (Array.isArray(expected) && Array.isArray(actual)) {
|
|
182896
|
+
const diffs = [];
|
|
182897
|
+
const max = Math.max(expected.length, actual.length);
|
|
182898
|
+
for (let index = 0;index < max; index += 1) {
|
|
182899
|
+
const next = `${basePath}[${index}]`;
|
|
182900
|
+
if (index >= actual.length)
|
|
182901
|
+
diffs.push({ path: next, type: "missing" });
|
|
182902
|
+
else if (index >= expected.length)
|
|
182903
|
+
diffs.push({ path: next, type: "extra" });
|
|
182904
|
+
else
|
|
182905
|
+
diffs.push(...diffJson(expected[index], actual[index], next));
|
|
182906
|
+
}
|
|
182907
|
+
return diffs;
|
|
182908
|
+
}
|
|
182909
|
+
return [
|
|
182910
|
+
{
|
|
182911
|
+
path: basePath,
|
|
182912
|
+
type: "changed",
|
|
182913
|
+
expected: JSON.stringify(expected),
|
|
182914
|
+
actual: JSON.stringify(actual)
|
|
182915
|
+
}
|
|
182916
|
+
];
|
|
182917
|
+
}
|
|
182918
|
+
function fileNames(files) {
|
|
182919
|
+
return (Array.isArray(files) ? files : []).map((file2) => String(file2.name ?? "")).filter(Boolean).sort();
|
|
182920
|
+
}
|
|
182921
|
+
function executionArtifactInventory(execution) {
|
|
182922
|
+
const rows = [
|
|
182923
|
+
{ kind: "metadata", name: "execution.json", present: "yes" }
|
|
182924
|
+
];
|
|
182925
|
+
if (execution.inputJson != null)
|
|
182926
|
+
rows.push({ kind: "input", name: "input.json", present: "yes" });
|
|
182927
|
+
if (execution.metadata != null)
|
|
182928
|
+
rows.push({ kind: "metadata", name: "metadata.json", present: "yes" });
|
|
182929
|
+
if (execution.expected != null)
|
|
182930
|
+
rows.push({ kind: "expected", name: "expected.json", present: "yes" });
|
|
182931
|
+
for (const name of fileNames(execution.inputFiles))
|
|
182932
|
+
rows.push({ kind: "input", name, present: "yes" });
|
|
182933
|
+
for (const name of fileNames(execution.resultFiles).filter((name2) => name2 !== "issues.md" && name2 !== "trace.jsonl")) {
|
|
182934
|
+
rows.push({ kind: "output", name, present: "yes" });
|
|
182935
|
+
}
|
|
182936
|
+
for (const name of fileNames(execution.expectedFiles)) {
|
|
182937
|
+
rows.push({ kind: "expected", name, present: "yes" });
|
|
182938
|
+
}
|
|
182939
|
+
for (const name of fileNames(execution.issueFiles))
|
|
182940
|
+
rows.push({ kind: "issues", name, present: "yes" });
|
|
182941
|
+
for (const name of fileNames(execution.traceFiles))
|
|
182942
|
+
rows.push({ kind: "trace", name, present: "yes" });
|
|
182943
|
+
return rows.sort((a, b) => `${a.kind}/${a.name}`.localeCompare(`${b.kind}/${b.name}`));
|
|
182944
|
+
}
|
|
182945
|
+
async function buildAgentFileDiff(agentId, remotePath, localPath, opts) {
|
|
182946
|
+
const client = buildClient(opts);
|
|
182947
|
+
const local = await fs.readFile(localPath);
|
|
182948
|
+
let remote = null;
|
|
182949
|
+
let serverPath = remotePath;
|
|
182950
|
+
try {
|
|
182951
|
+
const payload = await client.get(`/api/v1/agents/${encodeURIComponent(agentId)}/files`, {
|
|
182952
|
+
path: remotePath
|
|
182953
|
+
});
|
|
182954
|
+
serverPath = String(payload.path ?? remotePath);
|
|
182955
|
+
remote = Buffer.from(String(payload.contentBase64 ?? ""), "base64");
|
|
182956
|
+
} catch (err) {
|
|
182957
|
+
if (!(err instanceof ApiError) || err.status !== 404)
|
|
182958
|
+
throw err;
|
|
182959
|
+
}
|
|
182960
|
+
const localHash = createHash("sha256").update(local).digest("hex");
|
|
182961
|
+
const remoteHash = remote ? createHash("sha256").update(remote).digest("hex") : null;
|
|
182962
|
+
const status = !remote ? "remote-missing" : localHash === remoteHash ? "match" : "different";
|
|
182963
|
+
return {
|
|
182964
|
+
agentId,
|
|
182965
|
+
path: serverPath,
|
|
182966
|
+
localPath,
|
|
182967
|
+
status,
|
|
182968
|
+
localBytes: local.length,
|
|
182969
|
+
remoteBytes: remote?.length ?? null,
|
|
182970
|
+
localSha256: localHash,
|
|
182971
|
+
remoteSha256: remoteHash,
|
|
182972
|
+
textPreview: remote && isLikelyText(local) && isLikelyText(remote) ? buildTextDiffPreview(remote.toString("utf-8"), local.toString("utf-8")) : null
|
|
182973
|
+
};
|
|
182974
|
+
}
|
|
182975
|
+
function renderAgentFileDiff(report) {
|
|
182976
|
+
const label = `File ${report.status}`;
|
|
182977
|
+
if (report.status === "match")
|
|
182978
|
+
success2(label);
|
|
182979
|
+
else
|
|
182980
|
+
error51(label);
|
|
182981
|
+
console.log(table([
|
|
182982
|
+
{ item: "Remote path", value: report.path },
|
|
182983
|
+
{ item: "Local bytes", value: String(report.localBytes) },
|
|
182984
|
+
{ item: "Remote bytes", value: String(report.remoteBytes ?? "missing") },
|
|
182985
|
+
{ item: "Local sha256", value: report.localSha256.slice(0, 12) },
|
|
182986
|
+
{ item: "Remote sha256", value: report.remoteSha256?.slice(0, 12) ?? "missing" }
|
|
182987
|
+
], [
|
|
182988
|
+
{ key: "item", header: "ITEM" },
|
|
182989
|
+
{ key: "value", header: "VALUE" }
|
|
182990
|
+
]));
|
|
182991
|
+
if (report.textPreview?.length) {
|
|
182992
|
+
console.log(report.textPreview.join(`
|
|
182993
|
+
`));
|
|
182994
|
+
}
|
|
182995
|
+
}
|
|
182996
|
+
function isLikelyText(buffer) {
|
|
182997
|
+
return !buffer.includes(0);
|
|
182998
|
+
}
|
|
182999
|
+
function buildTextDiffPreview(remoteText, localText) {
|
|
183000
|
+
if (remoteText === localText)
|
|
183001
|
+
return [];
|
|
183002
|
+
const remoteLines = remoteText.split(/\r?\n/);
|
|
183003
|
+
const localLines = localText.split(/\r?\n/);
|
|
183004
|
+
const max = Math.max(remoteLines.length, localLines.length);
|
|
183005
|
+
const preview = [];
|
|
183006
|
+
for (let index = 0;index < max && preview.length < 12; index += 1) {
|
|
183007
|
+
if (remoteLines[index] === localLines[index])
|
|
183008
|
+
continue;
|
|
183009
|
+
preview.push(`-${remoteLines[index] ?? ""}`);
|
|
183010
|
+
preview.push(`+${localLines[index] ?? ""}`);
|
|
183011
|
+
}
|
|
183012
|
+
return preview;
|
|
183013
|
+
}
|
|
183014
|
+
function normalizeGeneratedTokens(value) {
|
|
183015
|
+
return value.replace(/\d{4}-\d{2}-\d{2}/g, "<date>").replace(/\d{8}/g, "<date>");
|
|
183016
|
+
}
|
|
183017
|
+
function compareFileInventory(expected, output, normalizeDates) {
|
|
183018
|
+
const normalize = (value) => normalizeDates ? normalizeGeneratedTokens(value) : value;
|
|
183019
|
+
const outputByNormalized = new Map(output.map((name) => [normalize(name), name]));
|
|
183020
|
+
const expectedByNormalized = new Map(expected.map((name) => [normalize(name), name]));
|
|
183021
|
+
const matched = expected.map((expectedName) => {
|
|
183022
|
+
const outputName = outputByNormalized.get(normalize(expectedName));
|
|
183023
|
+
return outputName ? { expected: expectedName, output: outputName } : null;
|
|
183024
|
+
}).filter((match) => Boolean(match));
|
|
183025
|
+
return {
|
|
183026
|
+
matched,
|
|
183027
|
+
missing: expected.filter((name) => !outputByNormalized.has(normalize(name))),
|
|
183028
|
+
extra: output.filter((name) => !expectedByNormalized.has(normalize(name)))
|
|
183029
|
+
};
|
|
183030
|
+
}
|
|
183031
|
+
async function compareMatchedFileText(client, left, right, out, matched, normalizeDates) {
|
|
183032
|
+
const expectedDir = path.join(out, "expected");
|
|
183033
|
+
const outputDir = path.join(out, "output");
|
|
183034
|
+
await fs.mkdir(expectedDir, { recursive: true });
|
|
183035
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
183036
|
+
const diffs = [];
|
|
183037
|
+
for (const pair of matched) {
|
|
183038
|
+
const expectedPath = path.join(expectedDir, pair.expected);
|
|
183039
|
+
const outputPath = path.join(outputDir, pair.output);
|
|
183040
|
+
await downloadStreamToFile(client, executionFileUrl(left, pair.expected), expectedPath);
|
|
183041
|
+
await downloadStreamToFile(client, executionFileUrl(right, pair.output), outputPath);
|
|
183042
|
+
const expectedText = extractComparableText(expectedPath);
|
|
183043
|
+
const outputText = extractComparableText(outputPath);
|
|
183044
|
+
if (expectedText.text == null || outputText.text == null) {
|
|
183045
|
+
const [expectedBuffer, outputBuffer] = await Promise.all([
|
|
183046
|
+
fs.readFile(expectedPath),
|
|
183047
|
+
fs.readFile(outputPath)
|
|
183048
|
+
]);
|
|
183049
|
+
const expectedHash = createHash("sha256").update(expectedBuffer).digest("hex");
|
|
183050
|
+
const outputHash = createHash("sha256").update(outputBuffer).digest("hex");
|
|
183051
|
+
diffs.push({
|
|
183052
|
+
...pair,
|
|
183053
|
+
status: expectedBuffer.length === outputBuffer.length && expectedHash === outputHash ? "binary-match" : "binary-different",
|
|
183054
|
+
expectedBytes: expectedBuffer.length,
|
|
183055
|
+
outputBytes: outputBuffer.length,
|
|
183056
|
+
expectedSha256: expectedHash,
|
|
183057
|
+
outputSha256: outputHash,
|
|
183058
|
+
textExtraction: {
|
|
183059
|
+
expected: expectedText.reason ?? null,
|
|
183060
|
+
output: outputText.reason ?? null
|
|
183061
|
+
}
|
|
183062
|
+
});
|
|
183063
|
+
continue;
|
|
183064
|
+
}
|
|
183065
|
+
const normalize = (value) => normalizeDates ? normalizeGeneratedTokens(value).trim() : value.trim();
|
|
183066
|
+
diffs.push({
|
|
183067
|
+
...pair,
|
|
183068
|
+
status: normalize(expectedText.text) === normalize(outputText.text) ? "match" : "text-different"
|
|
183069
|
+
});
|
|
183070
|
+
}
|
|
183071
|
+
return diffs;
|
|
183072
|
+
}
|
|
183073
|
+
function executionFileUrl(side, name) {
|
|
183074
|
+
const executionId = encodeURIComponent(side.executionId);
|
|
183075
|
+
const filename = encodeURIComponent(name);
|
|
183076
|
+
return side.kind === "expected" ? `/api/v1/agents/executions/${executionId}/expected/${filename}` : `/api/v1/agents/executions/${executionId}/files/output/${filename}`;
|
|
183077
|
+
}
|
|
183078
|
+
async function downloadStreamToFile(client, url2, target) {
|
|
183079
|
+
await fs.mkdir(path.dirname(target), { recursive: true });
|
|
183080
|
+
const response = await client.getStream(url2);
|
|
183081
|
+
await fs.writeFile(target, Buffer.from(await response.arrayBuffer()));
|
|
183082
|
+
}
|
|
183083
|
+
function extractComparableText(file2) {
|
|
183084
|
+
const ext = path.extname(file2).toLowerCase();
|
|
183085
|
+
if ([".txt", ".md", ".json", ".csv", ".xml"].includes(ext)) {
|
|
183086
|
+
return { text: readFileSync2(file2, "utf8") };
|
|
183087
|
+
}
|
|
183088
|
+
if (ext === ".pdf") {
|
|
183089
|
+
const result = spawnSync("pdftotext", [file2, "-"], { encoding: "utf8" });
|
|
183090
|
+
return result.status === 0 ? { text: result.stdout } : { text: null, reason: textExtractionFallbackReason("pdftotext", result) };
|
|
183091
|
+
}
|
|
183092
|
+
if (ext === ".docx") {
|
|
183093
|
+
const script = "import re,sys,zipfile; z=zipfile.ZipFile(sys.argv[1]); x=z.read('word/document.xml').decode('utf-8','ignore'); print(re.sub('<[^>]+>',' ',x))";
|
|
183094
|
+
const result = spawnSync("python3", ["-c", script, file2], { encoding: "utf8" });
|
|
183095
|
+
return result.status === 0 ? { text: result.stdout } : { text: null, reason: textExtractionFallbackReason("python3", result) };
|
|
183096
|
+
}
|
|
183097
|
+
return { text: null, reason: `No text extractor for ${ext || "extensionless"} files` };
|
|
183098
|
+
}
|
|
183099
|
+
function textExtractionFallbackReason(tool, result) {
|
|
183100
|
+
if (result.error)
|
|
183101
|
+
return `${tool} unavailable; compared bytes instead`;
|
|
183102
|
+
return `${tool} could not extract text; compared bytes instead`;
|
|
183103
|
+
}
|
|
183104
|
+
function renderComparisonReport(report) {
|
|
183105
|
+
const header = `Comparison ${report.status}`;
|
|
183106
|
+
if (report.status === "pass") {
|
|
183107
|
+
success2(header);
|
|
183108
|
+
} else {
|
|
183109
|
+
error51(header);
|
|
183110
|
+
}
|
|
183111
|
+
for (const warning of report.warnings ?? []) {
|
|
183112
|
+
dim(`warning: ${warning}`);
|
|
183113
|
+
}
|
|
183114
|
+
console.log(table([
|
|
183115
|
+
{ item: "JSON differences", count: report.jsonDifferences.length },
|
|
183116
|
+
{ item: "Matched files", count: report.matchedFiles.length },
|
|
183117
|
+
{ item: "Missing files", count: report.missingFiles.length },
|
|
183118
|
+
{ item: "Extra files", count: report.extraFiles.length },
|
|
183119
|
+
{
|
|
183120
|
+
item: "Text differences",
|
|
183121
|
+
count: report.textDifferences.filter((diff) => diff.status === "text-different").length
|
|
183122
|
+
}
|
|
183123
|
+
], [
|
|
183124
|
+
{ key: "item", header: "ITEM" },
|
|
183125
|
+
{ key: "count", header: "COUNT" }
|
|
183126
|
+
]));
|
|
183127
|
+
for (const diff of report.textDifferences) {
|
|
183128
|
+
const textExtraction = diff.textExtraction;
|
|
183129
|
+
const reasons = [textExtraction?.expected, textExtraction?.output].filter((value) => typeof value === "string" && value.length > 0).filter((value, index, values) => values.indexOf(value) === index);
|
|
183130
|
+
for (const reason of reasons) {
|
|
183131
|
+
dim(`warning: ${String(diff.expected)} vs ${String(diff.output)}: ${reason}`);
|
|
183132
|
+
}
|
|
183133
|
+
}
|
|
183134
|
+
}
|
|
182413
183135
|
async function readAgentYaml(root) {
|
|
182414
183136
|
const file2 = path.join(root, AGENT_YAML);
|
|
182415
183137
|
const raw = await fs.readFile(file2, "utf-8");
|
|
@@ -182490,7 +183212,7 @@ function renderGeneric(payload, opts, message) {
|
|
|
182490
183212
|
function compactParams(opts) {
|
|
182491
183213
|
const params = {};
|
|
182492
183214
|
for (const [key, value] of Object.entries(opts)) {
|
|
182493
|
-
if (value === undefined || value === null || key === "json" || key === "baseUrl" || key === "yes")
|
|
183215
|
+
if (value === undefined || value === null || key === "json" || key === "baseUrl" || key === "yes" || key === "compact")
|
|
182494
183216
|
continue;
|
|
182495
183217
|
params[key] = String(value);
|
|
182496
183218
|
}
|
|
@@ -183007,7 +183729,7 @@ import {
|
|
|
183007
183729
|
existsSync as existsSync3,
|
|
183008
183730
|
mkdirSync as mkdirSync2,
|
|
183009
183731
|
readdirSync,
|
|
183010
|
-
readFileSync as
|
|
183732
|
+
readFileSync as readFileSync3,
|
|
183011
183733
|
statSync,
|
|
183012
183734
|
writeFileSync as writeFileSync2
|
|
183013
183735
|
} from "node:fs";
|
|
@@ -183105,7 +183827,7 @@ function copyTemplate(src, dst, projectName) {
|
|
|
183105
183827
|
}
|
|
183106
183828
|
mkdirSync2(dirname2(targetPath), { recursive: true });
|
|
183107
183829
|
if (isTextFile(sourcePath)) {
|
|
183108
|
-
const text =
|
|
183830
|
+
const text = readFileSync3(sourcePath, "utf-8").replaceAll(PLACEHOLDER, projectName);
|
|
183109
183831
|
writeFileSync2(targetPath, text);
|
|
183110
183832
|
} else {
|
|
183111
183833
|
copyFileSync(sourcePath, targetPath);
|
|
@@ -183137,12 +183859,12 @@ function isTextFile(path2) {
|
|
|
183137
183859
|
|
|
183138
183860
|
// src/commands/skill.ts
|
|
183139
183861
|
init_dist4();
|
|
183140
|
-
import { createHash } from "node:crypto";
|
|
183862
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
183141
183863
|
import {
|
|
183142
183864
|
existsSync as existsSync4,
|
|
183143
183865
|
lstatSync,
|
|
183144
183866
|
mkdirSync as mkdirSync3,
|
|
183145
|
-
readFileSync as
|
|
183867
|
+
readFileSync as readFileSync4,
|
|
183146
183868
|
readdirSync as readdirSync2,
|
|
183147
183869
|
rmSync,
|
|
183148
183870
|
rmdirSync,
|
|
@@ -183236,7 +183958,7 @@ function resolveSkillTarget(opts) {
|
|
|
183236
183958
|
return opts.target ?? defaultClaudeTarget();
|
|
183237
183959
|
}
|
|
183238
183960
|
function sha256(buffer) {
|
|
183239
|
-
return
|
|
183961
|
+
return createHash2("sha256").update(buffer).digest("hex");
|
|
183240
183962
|
}
|
|
183241
183963
|
var CLI_VERSION_PLACEHOLDER = "__CLI_VERSION__";
|
|
183242
183964
|
function templateSourceFile(relativePath, bytes, cliVersion) {
|
|
@@ -183260,7 +183982,7 @@ async function installSkill(opts) {
|
|
|
183260
183982
|
for (const relativePath of sourceFiles) {
|
|
183261
183983
|
const sourcePath = join3(source, relativePath);
|
|
183262
183984
|
const targetPath = join3(target, relativePath);
|
|
183263
|
-
const sourceBytes = templateSourceFile(relativePath,
|
|
183985
|
+
const sourceBytes = templateSourceFile(relativePath, readFileSync4(sourcePath), cliVersion);
|
|
183264
183986
|
const sourceHash = sha256(sourceBytes);
|
|
183265
183987
|
if (!existsSync4(targetPath)) {
|
|
183266
183988
|
mkdirSync3(dirname3(targetPath), { recursive: true });
|
|
@@ -183268,7 +183990,7 @@ async function installSkill(opts) {
|
|
|
183268
183990
|
written += 1;
|
|
183269
183991
|
continue;
|
|
183270
183992
|
}
|
|
183271
|
-
const targetBytes =
|
|
183993
|
+
const targetBytes = readFileSync4(targetPath);
|
|
183272
183994
|
const targetHash = sha256(targetBytes);
|
|
183273
183995
|
if (targetHash === sourceHash) {
|
|
183274
183996
|
skipped += 1;
|
|
@@ -183299,7 +184021,7 @@ async function installSkill(opts) {
|
|
|
183299
184021
|
const targetPath = join3(target, relativePath);
|
|
183300
184022
|
if (!existsSync4(targetPath))
|
|
183301
184023
|
continue;
|
|
183302
|
-
manifestEntries.push({ path: relativePath, sha256: sha256(
|
|
184024
|
+
manifestEntries.push({ path: relativePath, sha256: sha256(readFileSync4(targetPath)) });
|
|
183303
184025
|
}
|
|
183304
184026
|
const manifest = {
|
|
183305
184027
|
cliVersion,
|
|
@@ -183340,7 +184062,7 @@ async function uninstallSkill(opts) {
|
|
|
183340
184062
|
}
|
|
183341
184063
|
if (!existsSync4(path2))
|
|
183342
184064
|
continue;
|
|
183343
|
-
const currentHash = sha256(
|
|
184065
|
+
const currentHash = sha256(readFileSync4(path2));
|
|
183344
184066
|
if (currentHash !== entry.sha256 && !opts.yes) {
|
|
183345
184067
|
kept += 1;
|
|
183346
184068
|
continue;
|
|
@@ -183570,7 +184292,7 @@ function readManifest(target) {
|
|
|
183570
184292
|
if (!existsSync4(path2))
|
|
183571
184293
|
return null;
|
|
183572
184294
|
try {
|
|
183573
|
-
return JSON.parse(
|
|
184295
|
+
return JSON.parse(readFileSync4(path2, "utf-8"));
|
|
183574
184296
|
} catch {
|
|
183575
184297
|
return null;
|
|
183576
184298
|
}
|
|
@@ -183584,7 +184306,7 @@ function readCliVersion() {
|
|
|
183584
184306
|
];
|
|
183585
184307
|
for (const candidate of candidates) {
|
|
183586
184308
|
if (existsSync4(candidate)) {
|
|
183587
|
-
const pkg = JSON.parse(
|
|
184309
|
+
const pkg = JSON.parse(readFileSync4(candidate, "utf-8"));
|
|
183588
184310
|
if (pkg.version)
|
|
183589
184311
|
return pkg.version;
|
|
183590
184312
|
}
|
|
@@ -184386,8 +185108,8 @@ import path15 from "node:path";
|
|
|
184386
185108
|
import { createInterface as createInterface3 } from "node:readline/promises";
|
|
184387
185109
|
|
|
184388
185110
|
// src/lib/format-eigenpal.ts
|
|
184389
|
-
import { spawnSync } from "child_process";
|
|
184390
|
-
import { existsSync as existsSync5, readFileSync as
|
|
185111
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
185112
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
184391
185113
|
import { join as join4, resolve as resolve3 } from "path";
|
|
184392
185114
|
var PRETTRC_NAMES = [
|
|
184393
185115
|
".prettierrc",
|
|
@@ -184408,7 +185130,7 @@ function hasPrettierConfig(cwd) {
|
|
|
184408
185130
|
const pkgPath = join4(cwd, "package.json");
|
|
184409
185131
|
if (!existsSync5(pkgPath))
|
|
184410
185132
|
return false;
|
|
184411
|
-
const raw =
|
|
185133
|
+
const raw = readFileSync5(pkgPath, "utf-8");
|
|
184412
185134
|
const pkg = JSON.parse(raw);
|
|
184413
185135
|
return pkg != null && typeof pkg === "object" && "prettier" in pkg;
|
|
184414
185136
|
} catch {
|
|
@@ -184423,7 +185145,7 @@ function formatEigenpalDirIfAvailable(dir) {
|
|
|
184423
185145
|
if (!hasPrettierConfig(cwd))
|
|
184424
185146
|
return;
|
|
184425
185147
|
const runner = typeof Bun !== "undefined" ? "bunx" : "npx";
|
|
184426
|
-
|
|
185148
|
+
spawnSync2(runner, ["prettier", "--write", absDir], {
|
|
184427
185149
|
cwd,
|
|
184428
185150
|
stdio: "ignore",
|
|
184429
185151
|
shell: false
|
|
@@ -184509,7 +185231,7 @@ import { existsSync as existsSync7, readdirSync as readdirSync4, rmSync as rmSyn
|
|
|
184509
185231
|
import { basename, join as join7 } from "path";
|
|
184510
185232
|
|
|
184511
185233
|
// src/lib/payload.ts
|
|
184512
|
-
import { existsSync as existsSync6, readdirSync as readdirSync3, readFileSync as
|
|
185234
|
+
import { existsSync as existsSync6, readdirSync as readdirSync3, readFileSync as readFileSync6, statSync as statSync2 } from "fs";
|
|
184513
185235
|
import { join as join6 } from "path";
|
|
184514
185236
|
|
|
184515
185237
|
// src/lib/fs-helpers.ts
|
|
@@ -184566,7 +185288,7 @@ function getExampleNames(dir, exampleNamesFilter) {
|
|
|
184566
185288
|
function readInput(exampleDir) {
|
|
184567
185289
|
const argsPath = join6(exampleDir, "input", "arguments.json");
|
|
184568
185290
|
const inputDir = join6(exampleDir, "input");
|
|
184569
|
-
const scalars = JSON.parse(
|
|
185291
|
+
const scalars = JSON.parse(readFileSync6(argsPath, "utf-8"));
|
|
184570
185292
|
const files = [];
|
|
184571
185293
|
for (const entry of readdirSync3(inputDir)) {
|
|
184572
185294
|
const full = join6(inputDir, entry);
|
|
@@ -184577,7 +185299,7 @@ function readInput(exampleDir) {
|
|
|
184577
185299
|
files.push({
|
|
184578
185300
|
argument: entry,
|
|
184579
185301
|
filename,
|
|
184580
|
-
content:
|
|
185302
|
+
content: readFileSync6(join6(full, filename)),
|
|
184581
185303
|
mimeType: guessMimeType(filename)
|
|
184582
185304
|
});
|
|
184583
185305
|
}
|
|
@@ -184588,7 +185310,7 @@ function readOverrides(exampleDir) {
|
|
|
184588
185310
|
const metaPath = join6(exampleDir, "meta.json");
|
|
184589
185311
|
if (!existsSync6(metaPath))
|
|
184590
185312
|
return null;
|
|
184591
|
-
const raw = JSON.parse(
|
|
185313
|
+
const raw = JSON.parse(readFileSync6(metaPath, "utf-8"));
|
|
184592
185314
|
const ov = raw.overrides;
|
|
184593
185315
|
if (ov && typeof ov === "object" && "steps" in ov && typeof ov.steps === "object") {
|
|
184594
185316
|
return ov;
|
|
@@ -184845,18 +185567,18 @@ async function watchExecution(opts) {
|
|
|
184845
185567
|
import { join as join11 } from "path";
|
|
184846
185568
|
|
|
184847
185569
|
// src/lib/execution-artifacts.ts
|
|
184848
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync4, readdirSync as readdirSync5, readFileSync as
|
|
185570
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync4, readdirSync as readdirSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
|
|
184849
185571
|
import { join as join10 } from "path";
|
|
184850
185572
|
|
|
184851
185573
|
// src/lib/format.ts
|
|
184852
|
-
import { readFileSync as
|
|
185574
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
184853
185575
|
import { extname as extname3, resolve as resolve5 } from "path";
|
|
184854
185576
|
var PRETTIER_EXTENSIONS = new Set([".json", ".yaml", ".yml"]);
|
|
184855
185577
|
async function formatFileIfAvailable(filepath) {
|
|
184856
185578
|
if (!PRETTIER_EXTENSIONS.has(extname3(filepath)))
|
|
184857
185579
|
return;
|
|
184858
185580
|
try {
|
|
184859
|
-
const content =
|
|
185581
|
+
const content = readFileSync7(filepath, "utf-8");
|
|
184860
185582
|
const prettier = await Promise.resolve().then(() => (init_prettier(), exports_prettier));
|
|
184861
185583
|
const formatted = await prettier.format(content, {
|
|
184862
185584
|
filepath: resolve5(filepath)
|
|
@@ -185623,7 +186345,7 @@ function parseWorkflow(yaml) {
|
|
|
185623
186345
|
}
|
|
185624
186346
|
// src/commands/validate.ts
|
|
185625
186347
|
var import_yaml5 = __toESM(require_dist(), 1);
|
|
185626
|
-
import { existsSync as existsSync9, readdirSync as readdirSync6, readFileSync as
|
|
186348
|
+
import { existsSync as existsSync9, readdirSync as readdirSync6, readFileSync as readFileSync9, statSync as statSync5 } from "fs";
|
|
185627
186349
|
import { join as join12, resolve as resolve6 } from "path";
|
|
185628
186350
|
var NAME_RE = /^[a-z0-9][a-z0-9-_]*$/;
|
|
185629
186351
|
function isDirSafe(path15, issues, field) {
|
|
@@ -185641,7 +186363,7 @@ function validateWorkflowYaml(path15) {
|
|
|
185641
186363
|
if (!existsSync9(path15)) {
|
|
185642
186364
|
return [{ field: path15, message: "File not found." }];
|
|
185643
186365
|
}
|
|
185644
|
-
const text =
|
|
186366
|
+
const text = readFileSync9(path15, "utf-8");
|
|
185645
186367
|
try {
|
|
185646
186368
|
parseWorkflow(text);
|
|
185647
186369
|
return [];
|
|
@@ -185663,7 +186385,7 @@ function validateEvaluatorsYaml(path15) {
|
|
|
185663
186385
|
if (!existsSync9(path15)) {
|
|
185664
186386
|
return [{ field: path15, message: "File not found." }];
|
|
185665
186387
|
}
|
|
185666
|
-
const text =
|
|
186388
|
+
const text = readFileSync9(path15, "utf-8");
|
|
185667
186389
|
let parsed;
|
|
185668
186390
|
try {
|
|
185669
186391
|
parsed = import_yaml5.parse(text);
|
|
@@ -185715,7 +186437,7 @@ function validateDatasetFolder(root2) {
|
|
|
185715
186437
|
}
|
|
185716
186438
|
let args;
|
|
185717
186439
|
try {
|
|
185718
|
-
const parsed = JSON.parse(
|
|
186440
|
+
const parsed = JSON.parse(readFileSync9(argsPath, "utf-8"));
|
|
185719
186441
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
185720
186442
|
issues.push({
|
|
185721
186443
|
field: `examples/${exampleName}/input/arguments.json`,
|
|
@@ -185773,7 +186495,7 @@ function validateDatasetFolder(root2) {
|
|
|
185773
186495
|
if (existsSync9(expectedPath)) {
|
|
185774
186496
|
let parsed;
|
|
185775
186497
|
try {
|
|
185776
|
-
parsed = JSON.parse(
|
|
186498
|
+
parsed = JSON.parse(readFileSync9(expectedPath, "utf-8"));
|
|
185777
186499
|
} catch {
|
|
185778
186500
|
issues.push({
|
|
185779
186501
|
field: `examples/${exampleName}/expected/output.json`,
|
|
@@ -186316,7 +187038,7 @@ async function readDirAsZip(dir) {
|
|
|
186316
187038
|
}
|
|
186317
187039
|
return zipSync(tree);
|
|
186318
187040
|
}
|
|
186319
|
-
async function
|
|
187041
|
+
async function downloadStreamToFile2(client, path16, outFile) {
|
|
186320
187042
|
const res = await client.getStream(path16);
|
|
186321
187043
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
186322
187044
|
if (outFile) {
|
|
@@ -186620,7 +187342,7 @@ function registerDatasetCommands2(parent) {
|
|
|
186620
187342
|
const pullCmd = dataset.command("pull <workflow-id>").description(descriptionFor("workflow_get_dataset")).option("--out <zip>", "Write the dataset ZIP to this path. When omitted, the binary streams to stdout.");
|
|
186621
187343
|
withBaseUrl(pullCmd).action(action(async (workflow2, opts) => {
|
|
186622
187344
|
const { client, workflowId } = await buildClientForWorkflow(workflow2, opts);
|
|
186623
|
-
await
|
|
187345
|
+
await downloadStreamToFile2(client, `/api/v1/workflows/${workflowId}/dataset/export`, opts.out);
|
|
186624
187346
|
}));
|
|
186625
187347
|
const pushCmd = dataset.command("push <workflow-id>").description(descriptionFor("workflow_set_dataset")).requiredOption("--file <path>", "Path to a dataset ZIP file or a dataset/ folder (folder is zipped in memory before upload)").option("--mode <append|replace>", "Import mode (default: append)", "append").option("--yes", "Skip the destructive confirmation prompt for --mode replace (use in CI)", false).addHelpText("after", `
|
|
186626
187348
|
Examples:
|
|
@@ -187069,7 +187791,7 @@ Behavior:
|
|
|
187069
187791
|
const params = new URLSearchParams({ format: opts.format });
|
|
187070
187792
|
if (batchId)
|
|
187071
187793
|
params.set("batchId", batchId);
|
|
187072
|
-
await
|
|
187794
|
+
await downloadStreamToFile2(client, `/api/v1/workflows/${workflowId}/eval-results/export?${params.toString()}`, opts.out);
|
|
187073
187795
|
}));
|
|
187074
187796
|
const compareCmd = experiment.command("compare <batchIdA> <batchIdB>").description("Diff eval scores between two experiment batches.").option("--sort <abs-delta-desc|delta-asc|delta-desc|name>", "Row sort order (default: biggest movers first)", "abs-delta-desc").option("--regression-threshold <n>", "Δ below this is flagged as a regression (default 0.05)", Number.parseFloat, 0.05).addHelpText("after", `
|
|
187075
187797
|
Examples:
|
|
@@ -187157,7 +187879,7 @@ Behavior:
|
|
|
187157
187879
|
return;
|
|
187158
187880
|
const params = new URLSearchParams({ format: opts.format, batchId });
|
|
187159
187881
|
try {
|
|
187160
|
-
await
|
|
187882
|
+
await downloadStreamToFile2(client, `/api/v1/workflows/${workflowId}/eval-results/export?${params.toString()}`, dest);
|
|
187161
187883
|
} catch (err2) {
|
|
187162
187884
|
error51(`Watch finished but pulling results failed: ${err2 instanceof Error ? err2.message : String(err2)}. Re-run \`experiment results <wf> <batch>\` to retry.`);
|
|
187163
187885
|
process.exit(1);
|
|
@@ -187358,6 +188080,39 @@ function registerStepTypeCommands(parent) {
|
|
|
187358
188080
|
});
|
|
187359
188081
|
}
|
|
187360
188082
|
|
|
188083
|
+
// src/lib/command-aliases.ts
|
|
188084
|
+
var CONVENTION_ALIASES = new Map([
|
|
188085
|
+
["artifacts", "artifact"],
|
|
188086
|
+
["execution", "exec"],
|
|
188087
|
+
["experiment", "exp"],
|
|
188088
|
+
["feedback", "fb"],
|
|
188089
|
+
["list", "ls"],
|
|
188090
|
+
["compare", "diff"]
|
|
188091
|
+
]);
|
|
188092
|
+
function applyCommandAliasConventions(root2) {
|
|
188093
|
+
for (const command of root2.commands) {
|
|
188094
|
+
applySiblingAliases(command.parent ?? root2);
|
|
188095
|
+
applyCommandAliasConventions(command);
|
|
188096
|
+
}
|
|
188097
|
+
}
|
|
188098
|
+
function applySiblingAliases(parent) {
|
|
188099
|
+
const reserved = new Set;
|
|
188100
|
+
for (const sibling of parent.commands) {
|
|
188101
|
+
reserved.add(sibling.name());
|
|
188102
|
+
for (const alias of sibling.aliases())
|
|
188103
|
+
reserved.add(alias);
|
|
188104
|
+
}
|
|
188105
|
+
for (const command of parent.commands) {
|
|
188106
|
+
const alias = CONVENTION_ALIASES.get(command.name());
|
|
188107
|
+
if (!alias || command.aliases().includes(alias))
|
|
188108
|
+
continue;
|
|
188109
|
+
if (reserved.has(alias))
|
|
188110
|
+
continue;
|
|
188111
|
+
command.aliases([...command.aliases(), alias]);
|
|
188112
|
+
reserved.add(alias);
|
|
188113
|
+
}
|
|
188114
|
+
}
|
|
188115
|
+
|
|
187361
188116
|
// src/lib/logo.ts
|
|
187362
188117
|
var LOGO_WIDTH = 22;
|
|
187363
188118
|
var LOGO_LINES = [
|
|
@@ -187803,6 +188558,7 @@ skillCmd.command("list").description("Show every tool that has an Eigenpal skill
|
|
|
187803
188558
|
process.exit(1);
|
|
187804
188559
|
}
|
|
187805
188560
|
});
|
|
188561
|
+
applyCommandAliasConventions(program2);
|
|
187806
188562
|
function isEntryPoint() {
|
|
187807
188563
|
const argv1 = process.argv[1];
|
|
187808
188564
|
if (!argv1)
|