@swmansion/argent 0.32.1-next.10 → 0.32.1-next.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-cmds.mjs +472 -433
- package/dist/client.d.ts +5 -0
- package/dist/client.js +27 -9
- package/dist/installer.mjs +342 -201
- package/dist/mcp-server.mjs +25 -8
- package/dist/tool-server.cjs +20259 -20225
- package/package.json +1 -1
package/dist/cli-cmds.mjs
CHANGED
|
@@ -8917,7 +8917,7 @@ var require_src = __commonJS({
|
|
|
8917
8917
|
|
|
8918
8918
|
// ../argent-cli/src/run.ts
|
|
8919
8919
|
import * as fs12 from "node:fs";
|
|
8920
|
-
import * as
|
|
8920
|
+
import * as path18 from "node:path";
|
|
8921
8921
|
|
|
8922
8922
|
// ../argent-tools-client/src/launcher.ts
|
|
8923
8923
|
import * as net from "node:net";
|
|
@@ -10452,6 +10452,8 @@ var FAILURE_CODES = {
|
|
|
10452
10452
|
CLI_RUN_ARGS_JSON_INVALID: "CLI_RUN_ARGS_JSON_INVALID",
|
|
10453
10453
|
CLI_RUN_INPUT_VALIDATION_FAILED: "CLI_RUN_INPUT_VALIDATION_FAILED",
|
|
10454
10454
|
CLI_RUN_TOOL_CALL_FAILED: "CLI_RUN_TOOL_CALL_FAILED",
|
|
10455
|
+
// The result carried the tool-server's `failure` field.
|
|
10456
|
+
CLI_RUN_TOOL_RESULT_FAILED: "CLI_RUN_TOOL_RESULT_FAILED",
|
|
10455
10457
|
CLI_RUN_SAVE_IMAGE_FAILED: "CLI_RUN_SAVE_IMAGE_FAILED",
|
|
10456
10458
|
TOOL_CAPABILITY_UNSUPPORTED_OPERATION: "TOOL_CAPABILITY_UNSUPPORTED_OPERATION",
|
|
10457
10459
|
TOOL_PLATFORM_NOT_IMPLEMENTED: "TOOL_PLATFORM_NOT_IMPLEMENTED",
|
|
@@ -10467,6 +10469,7 @@ var FAILURE_CODES = {
|
|
|
10467
10469
|
INSTALL_MODE_FLAG_CONFLICT: "INSTALL_MODE_FLAG_CONFLICT",
|
|
10468
10470
|
INSTALL_FROM_TAR_PACKAGE_FAILED: "INSTALL_FROM_TAR_PACKAGE_FAILED",
|
|
10469
10471
|
INSTALL_INIT_TRIGGERED_UPDATE_FAILED: "INSTALL_INIT_TRIGGERED_UPDATE_FAILED",
|
|
10472
|
+
INSTALL_SKILLS_FAILED: "INSTALL_SKILLS_FAILED",
|
|
10470
10473
|
INSTALL_SKILLS_REFRESH_FAILED: "INSTALL_SKILLS_REFRESH_FAILED",
|
|
10471
10474
|
INSTALL_UNCLASSIFIED_FAILED: "INSTALL_UNCLASSIFIED_FAILED",
|
|
10472
10475
|
UPDATE_INSTALLED_VERSION_DETECT_FAILED: "UPDATE_INSTALLED_VERSION_DETECT_FAILED",
|
|
@@ -31651,7 +31654,8 @@ async function consumeToolStream(name, body, onProgress, signal) {
|
|
|
31651
31654
|
final = {
|
|
31652
31655
|
data: msg.data,
|
|
31653
31656
|
note: msg.note,
|
|
31654
|
-
...msg.profiling === true ? { profiling: true } : {}
|
|
31657
|
+
...msg.profiling === true ? { profiling: true } : {},
|
|
31658
|
+
...typeof msg.failure === "string" ? { failure: msg.failure } : {}
|
|
31655
31659
|
};
|
|
31656
31660
|
} else if (msg.event === "error") {
|
|
31657
31661
|
throw new ToolInvocationError(msg.error ?? "tool invocation failed", {
|
|
@@ -31703,7 +31707,8 @@ async function consumeToolStream(name, body, onProgress, signal) {
|
|
|
31703
31707
|
return {
|
|
31704
31708
|
data: final.data,
|
|
31705
31709
|
note: final.note,
|
|
31706
|
-
...final.profiling ? { profiling: true } : {}
|
|
31710
|
+
...final.profiling ? { profiling: true } : {},
|
|
31711
|
+
...final.failure !== void 0 ? { failure: final.failure } : {}
|
|
31707
31712
|
};
|
|
31708
31713
|
}
|
|
31709
31714
|
function errorBodyMessage(body) {
|
|
@@ -31868,6 +31873,7 @@ function createToolsClient(options = {}) {
|
|
|
31868
31873
|
}
|
|
31869
31874
|
const shadowWarning = await e2eShadowWarningFor(name, args);
|
|
31870
31875
|
const baselineDirs = [];
|
|
31876
|
+
let unwrittenBaselines2 = [];
|
|
31871
31877
|
if (meta3?.fileInputs?.length) {
|
|
31872
31878
|
if (remote) assertRequiredPresent(meta3, finalArgs);
|
|
31873
31879
|
finalArgs = await prepareFileInputs(meta3.fileInputs, finalArgs ?? {}, {
|
|
@@ -31881,8 +31887,9 @@ function createToolsClient(options = {}) {
|
|
|
31881
31887
|
signal: opts?.signal
|
|
31882
31888
|
});
|
|
31883
31889
|
}
|
|
31884
|
-
const settle2 = async (
|
|
31885
|
-
const applied = await applyClientFileDirectives(
|
|
31890
|
+
const settle2 = async (data2) => {
|
|
31891
|
+
const applied = await applyClientFileDirectives(data2, { allowedDirs: baselineDirs });
|
|
31892
|
+
unwrittenBaselines2 = applied.failed.map((f) => f.path);
|
|
31886
31893
|
for (const { path: file2, error: error63 } of applied.failed) {
|
|
31887
31894
|
diagnose(`The baseline ${file2} was not written on this client: ${error63}`);
|
|
31888
31895
|
}
|
|
@@ -31899,6 +31906,7 @@ function createToolsClient(options = {}) {
|
|
|
31899
31906
|
}
|
|
31900
31907
|
return { ...result, warning: shadowWarning };
|
|
31901
31908
|
};
|
|
31909
|
+
const unwrittenFailure = () => unwrittenBaselines2.length > 0 ? `Baselines not written on this client: ${unwrittenBaselines2.join(", ")}` : void 0;
|
|
31902
31910
|
const stream = opts?.onProgress !== void 0 || carriesMembers(finalArgs);
|
|
31903
31911
|
const sentOnce = carriesUpload(finalArgs);
|
|
31904
31912
|
const forwarded = remote ? await forwardedSecrets(finalArgs) : void 0;
|
|
@@ -31962,11 +31970,14 @@ function createToolsClient(options = {}) {
|
|
|
31962
31970
|
}),
|
|
31963
31971
|
opts?.signal
|
|
31964
31972
|
);
|
|
31973
|
+
const data2 = await settle2(streamed.data);
|
|
31974
|
+
const failure3 = streamed.failure ?? unwrittenFailure();
|
|
31965
31975
|
return {
|
|
31966
|
-
data:
|
|
31976
|
+
data: data2,
|
|
31967
31977
|
note: streamed.note,
|
|
31968
31978
|
outputHint: meta3?.outputHint,
|
|
31969
|
-
...streamed.profiling ? { profiling: true } : {}
|
|
31979
|
+
...streamed.profiling ? { profiling: true } : {},
|
|
31980
|
+
...failure3 !== void 0 ? { failure: failure3 } : {}
|
|
31970
31981
|
};
|
|
31971
31982
|
}
|
|
31972
31983
|
let json2;
|
|
@@ -32002,11 +32013,14 @@ function createToolsClient(options = {}) {
|
|
|
32002
32013
|
});
|
|
32003
32014
|
}
|
|
32004
32015
|
opts?.signal?.throwIfAborted();
|
|
32016
|
+
const data = await settle2(json2.data);
|
|
32017
|
+
const failure2 = (typeof json2.failure === "string" ? json2.failure : void 0) ?? unwrittenFailure();
|
|
32005
32018
|
return {
|
|
32006
|
-
data
|
|
32019
|
+
data,
|
|
32007
32020
|
note: json2.note,
|
|
32008
32021
|
outputHint: meta3?.outputHint,
|
|
32009
|
-
...json2.profiling === true ? { profiling: true } : {}
|
|
32022
|
+
...json2.profiling === true ? { profiling: true } : {},
|
|
32023
|
+
...failure2 !== void 0 ? { failure: failure2 } : {}
|
|
32010
32024
|
};
|
|
32011
32025
|
}
|
|
32012
32026
|
return { fetchTools, fetchTool, callTool, baseUrl };
|
|
@@ -35221,6 +35235,9 @@ var ALLOWED = {
|
|
|
35221
35235
|
warned_count: COUNT
|
|
35222
35236
|
},
|
|
35223
35237
|
"installation:skill_install": {
|
|
35238
|
+
source: oneOf(["pinned", "bundled"]),
|
|
35239
|
+
used_fallback: bool,
|
|
35240
|
+
fallback_reason: oneOf(["ref_missing", "unclassified"]),
|
|
35224
35241
|
method: oneOf(["default", "interactive", "manual"]),
|
|
35225
35242
|
is_online: bool,
|
|
35226
35243
|
has_offline_cache: bool,
|
|
@@ -35821,7 +35838,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
|
|
|
35821
35838
|
var SESSION_ID2 = randomUUID5();
|
|
35822
35839
|
function readCliVersion() {
|
|
35823
35840
|
if (true) {
|
|
35824
|
-
return "0.32.1-next.
|
|
35841
|
+
return "0.32.1-next.12";
|
|
35825
35842
|
}
|
|
35826
35843
|
return "0.0.0";
|
|
35827
35844
|
}
|
|
@@ -36760,391 +36777,106 @@ function isValidationIssue(value) {
|
|
|
36760
36777
|
return typeof issue2.code === "string" && Array.isArray(issue2.path) && typeof issue2.message === "string";
|
|
36761
36778
|
}
|
|
36762
36779
|
|
|
36763
|
-
// ../argent-cli/src/
|
|
36764
|
-
|
|
36765
|
-
|
|
36766
|
-
|
|
36767
|
-
|
|
36780
|
+
// ../argent-cli/src/e2e.ts
|
|
36781
|
+
import * as fsp from "node:fs/promises";
|
|
36782
|
+
import { constants as fsConstants2 } from "node:fs";
|
|
36783
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
36784
|
+
import * as path17 from "node:path";
|
|
36785
|
+
|
|
36786
|
+
// ../argent-cli/src/command-args.ts
|
|
36787
|
+
var UsageError = class extends Error {
|
|
36788
|
+
constructor(message) {
|
|
36789
|
+
super(message);
|
|
36790
|
+
this.name = "UsageError";
|
|
36791
|
+
}
|
|
36792
|
+
};
|
|
36793
|
+
function listChoices(choices) {
|
|
36794
|
+
const quoted = choices.map((c2) => `"${c2}"`);
|
|
36795
|
+
if (quoted.length <= 1) return quoted.join("");
|
|
36796
|
+
return `${quoted.slice(0, -1).join(", ")} or ${quoted[quoted.length - 1]}`;
|
|
36797
|
+
}
|
|
36798
|
+
function resolveName(tok, specs) {
|
|
36799
|
+
if (tok.startsWith("--")) return tok.slice(2) in specs ? tok.slice(2) : null;
|
|
36800
|
+
const short = tok.slice(1);
|
|
36801
|
+
for (const [name, spec] of Object.entries(specs)) {
|
|
36802
|
+
if (spec.alias === short) return name;
|
|
36803
|
+
}
|
|
36804
|
+
return null;
|
|
36805
|
+
}
|
|
36806
|
+
function parseCommandArgs(argv, specs) {
|
|
36807
|
+
const positionals = [];
|
|
36808
|
+
const options = {};
|
|
36768
36809
|
for (let i2 = 0; i2 < argv.length; i2++) {
|
|
36769
36810
|
const tok = argv[i2];
|
|
36770
|
-
if (tok === "--
|
|
36771
|
-
|
|
36772
|
-
|
|
36811
|
+
if (tok === "--") {
|
|
36812
|
+
positionals.push(...argv.slice(i2 + 1));
|
|
36813
|
+
break;
|
|
36773
36814
|
}
|
|
36774
|
-
if (tok === "
|
|
36775
|
-
|
|
36776
|
-
if (!v) throw new FlagParseException("--out requires a path");
|
|
36777
|
-
outPath = v;
|
|
36778
|
-
i2 += 1;
|
|
36815
|
+
if (!tok.startsWith("-") || tok === "-") {
|
|
36816
|
+
positionals.push(tok);
|
|
36779
36817
|
continue;
|
|
36780
36818
|
}
|
|
36781
|
-
|
|
36782
|
-
|
|
36819
|
+
const eq = tok.startsWith("--") ? tok.indexOf("=") : -1;
|
|
36820
|
+
const flag = eq === -1 ? tok : tok.slice(0, eq);
|
|
36821
|
+
const inlineValue = eq === -1 ? void 0 : tok.slice(eq + 1);
|
|
36822
|
+
const name = resolveName(flag, specs);
|
|
36823
|
+
if (name === null) throw new UsageError(`Unknown flag: ${tok}`);
|
|
36824
|
+
const spec = specs[name];
|
|
36825
|
+
const display = `--${name}`;
|
|
36826
|
+
if (spec.kind === "boolean") {
|
|
36827
|
+
if (inlineValue !== void 0) throw new UsageError(`${display} does not take a value`);
|
|
36828
|
+
const next = argv[i2 + 1]?.trim().toLowerCase();
|
|
36829
|
+
if (next === "true" || next === "false") {
|
|
36830
|
+
throw new UsageError(
|
|
36831
|
+
`${display} does not take a value \u2014 it is a switch; omit it to leave the option off`
|
|
36832
|
+
);
|
|
36833
|
+
}
|
|
36834
|
+
options[name] = true;
|
|
36783
36835
|
continue;
|
|
36784
36836
|
}
|
|
36785
|
-
|
|
36786
|
-
|
|
36787
|
-
|
|
36788
|
-
|
|
36789
|
-
|
|
36790
|
-
|
|
36791
|
-
|
|
36792
|
-
|
|
36793
|
-
|
|
36794
|
-
|
|
36795
|
-
});
|
|
36796
|
-
|
|
36797
|
-
|
|
36798
|
-
});
|
|
36799
|
-
}
|
|
36800
|
-
function printToolHelp(meta3) {
|
|
36801
|
-
const description = meta3.description?.trim() ?? "";
|
|
36802
|
-
const schema = meta3.inputSchema;
|
|
36803
|
-
const hasOwnArgsField = schema?.properties?.args !== void 0;
|
|
36804
|
-
console.log(`argent run ${meta3.name} [flags]`);
|
|
36805
|
-
if (description) console.log(`
|
|
36806
|
-
${description}
|
|
36807
|
-
`);
|
|
36808
|
-
console.log("Flags:");
|
|
36809
|
-
console.log(formatSchemaUsage(schema));
|
|
36810
|
-
console.log("\nGlobal flags:");
|
|
36811
|
-
if (!hasOwnArgsField) {
|
|
36812
|
-
console.log(" --args <json> Pass the entire payload as JSON (overrides flags)");
|
|
36813
|
-
console.log(" --args - Read the entire payload as JSON from stdin");
|
|
36814
|
-
}
|
|
36815
|
-
console.log(" --<field>-json <json> Pass a single field as JSON (objects/nested arrays)");
|
|
36816
|
-
console.log(" --json Print the raw JSON result");
|
|
36817
|
-
console.log(" --out <path> For image results, save to <path> instead of fetching URL");
|
|
36818
|
-
console.log(" --help, -h Show this help");
|
|
36819
|
-
}
|
|
36820
|
-
async function fetchImageToFile(result, outPath) {
|
|
36821
|
-
const url2 = result.url;
|
|
36822
|
-
if (!url2) {
|
|
36823
|
-
throw new Error("Tool result did not include a `url`; cannot save image");
|
|
36824
|
-
}
|
|
36825
|
-
const res = await fetch(url2);
|
|
36826
|
-
if (!res.ok) throw new Error(`Failed to download image: ${res.status} ${res.statusText}`);
|
|
36827
|
-
const buf = Buffer.from(await res.arrayBuffer());
|
|
36828
|
-
fs12.mkdirSync(path17.dirname(path17.resolve(outPath)), { recursive: true });
|
|
36829
|
-
fs12.writeFileSync(outPath, buf);
|
|
36830
|
-
}
|
|
36831
|
-
function renderResult(result, outputHint, images, json2) {
|
|
36832
|
-
if (json2) return JSON.stringify(result, null, 2);
|
|
36833
|
-
if (outputHint === "image") {
|
|
36834
|
-
if (images.length > 0) return `Saved screenshot: ${images[0].localPath}`;
|
|
36835
|
-
if (result && typeof result === "object" && "path" in result && typeof result.path === "string") {
|
|
36836
|
-
return `Saved screenshot: ${result.path}`;
|
|
36837
|
+
let value = inlineValue;
|
|
36838
|
+
if (value === void 0) {
|
|
36839
|
+
const next = argv[i2 + 1];
|
|
36840
|
+
if (next !== void 0 && (!next.startsWith("-") || next === "-")) {
|
|
36841
|
+
value = next;
|
|
36842
|
+
i2 += 1;
|
|
36843
|
+
}
|
|
36844
|
+
} else if (value === "") {
|
|
36845
|
+
value = void 0;
|
|
36846
|
+
}
|
|
36847
|
+
if (value === void 0) throw new UsageError(`${display} requires a value`);
|
|
36848
|
+
if (spec.choices && !spec.choices.includes(value)) {
|
|
36849
|
+
throw new UsageError(`${display} must be ${listChoices(spec.choices)}, got "${value}"`);
|
|
36837
36850
|
}
|
|
36851
|
+
options[name] = value;
|
|
36838
36852
|
}
|
|
36839
|
-
|
|
36840
|
-
return JSON.stringify(result, null, 2);
|
|
36853
|
+
return { positionals, options };
|
|
36841
36854
|
}
|
|
36842
|
-
|
|
36843
|
-
|
|
36844
|
-
|
|
36855
|
+
|
|
36856
|
+
// ../argent-cli/src/e2e.ts
|
|
36857
|
+
var STATUS_GLYPH = {
|
|
36858
|
+
pass: "\u2713",
|
|
36859
|
+
fail: "\u2717",
|
|
36860
|
+
error: "\u2717",
|
|
36861
|
+
skip: "\xB7"
|
|
36862
|
+
};
|
|
36863
|
+
var MAX_RENDER_DEPTH = 20;
|
|
36864
|
+
function stepIndent(depth) {
|
|
36865
|
+
if (typeof depth !== "number" || !Number.isInteger(depth) || depth <= 0) return "";
|
|
36866
|
+
return " ".repeat(Math.min(depth, MAX_RENDER_DEPTH));
|
|
36845
36867
|
}
|
|
36846
|
-
|
|
36847
|
-
|
|
36848
|
-
|
|
36849
|
-
|
|
36850
|
-
|
|
36851
|
-
|
|
36852
|
-
...signal
|
|
36853
|
-
});
|
|
36854
|
-
await shutdown();
|
|
36868
|
+
function durationSuffix(ms) {
|
|
36869
|
+
if (typeof ms !== "number" || !Number.isFinite(ms) || ms < 0) return "";
|
|
36870
|
+
const tenths = Math.round(ms / 100);
|
|
36871
|
+
if (tenths < 600) return ` (${(tenths / 10).toFixed(1)}s)`;
|
|
36872
|
+
const seconds = Math.round(ms / 1e3);
|
|
36873
|
+
return ` (${Math.floor(seconds / 60)}m ${seconds % 60}s)`;
|
|
36855
36874
|
}
|
|
36856
|
-
|
|
36857
|
-
|
|
36858
|
-
|
|
36859
|
-
const { fetchTool, callTool, baseUrl } = createToolsClient({ paths: options.paths });
|
|
36860
|
-
const [toolName, ...rest] = argv;
|
|
36861
|
-
if (!toolName || toolName === "--help" || toolName === "-h") {
|
|
36862
|
-
console.log(`Usage: argent run <tool> [flags]
|
|
36875
|
+
function printHelp(toStderr = false) {
|
|
36876
|
+
const print = toStderr ? console.error : console.log;
|
|
36877
|
+
print(`Usage: argent e2e <subcommand> [options]
|
|
36863
36878
|
|
|
36864
|
-
|
|
36865
|
-
available tools, or \`argent tools describe <name>\` to see one tool's flags.
|
|
36866
|
-
|
|
36867
|
-
Examples:
|
|
36868
|
-
argent run list-devices
|
|
36869
|
-
argent run gesture-tap --udid <UDID> --x 0.5 --y 0.5
|
|
36870
|
-
argent run screenshot --udid <UDID> --out ./screen.png
|
|
36871
|
-
argent run run-sequence --udid <UDID> --steps-json '[{"tool":"button","args":{"button":"home"}}]'
|
|
36872
|
-
argent run gesture-tap --args '{"udid":"<UDID>","x":0.5,"y":0.5}'
|
|
36873
|
-
`);
|
|
36874
|
-
return;
|
|
36875
|
-
}
|
|
36876
|
-
let cliOptions;
|
|
36877
|
-
try {
|
|
36878
|
-
cliOptions = splitOptions(rest);
|
|
36879
|
-
} catch (err) {
|
|
36880
|
-
if (err instanceof FlagParseException) {
|
|
36881
|
-
console.error(`Error: ${err.message}
|
|
36882
|
-
`);
|
|
36883
|
-
console.error(`Run \`argent run ${toolName} --help\` to see this tool's flags.`);
|
|
36884
|
-
await trackRunFailure(toolName, startedAt, {
|
|
36885
|
-
error_code: FAILURE_CODES.CLI_RUN_FLAG_PARSE_FAILED,
|
|
36886
|
-
failure_stage: "cli_run_split_options",
|
|
36887
|
-
failure_area: "cli",
|
|
36888
|
-
error_kind: "validation"
|
|
36889
|
-
});
|
|
36890
|
-
process.exit(2);
|
|
36891
|
-
}
|
|
36892
|
-
throw err;
|
|
36893
|
-
}
|
|
36894
|
-
const { json: json2, outPath, argvForFlags } = cliOptions;
|
|
36895
|
-
const meta3 = await fetchTool(toolName);
|
|
36896
|
-
if (!meta3) {
|
|
36897
|
-
console.error(`Tool "${toolName}" not found. Run \`argent tools\` to list available tools.`);
|
|
36898
|
-
await trackRunFailure(toolName, startedAt, {
|
|
36899
|
-
error_code: FAILURE_CODES.CLI_RUN_TOOL_NOT_FOUND,
|
|
36900
|
-
failure_stage: "cli_run_fetch_tool",
|
|
36901
|
-
failure_area: "cli",
|
|
36902
|
-
error_kind: "not_found"
|
|
36903
|
-
});
|
|
36904
|
-
process.exit(1);
|
|
36905
|
-
}
|
|
36906
|
-
const schema = meta3.inputSchema;
|
|
36907
|
-
const failInvocation = async (summary, report, failure2) => {
|
|
36908
|
-
if (json2) {
|
|
36909
|
-
console.error(
|
|
36910
|
-
JSON.stringify(
|
|
36911
|
-
{
|
|
36912
|
-
error: summary,
|
|
36913
|
-
missing: report ? missingFlagNames(report, schema) : [],
|
|
36914
|
-
issues: report?.rawIssues ?? []
|
|
36915
|
-
},
|
|
36916
|
-
null,
|
|
36917
|
-
2
|
|
36918
|
-
)
|
|
36919
|
-
);
|
|
36920
|
-
} else {
|
|
36921
|
-
console.error(`Error: ${summary}
|
|
36922
|
-
`);
|
|
36923
|
-
printToolHelp(meta3);
|
|
36924
|
-
}
|
|
36925
|
-
await trackRunFailure(toolName, startedAt, {
|
|
36926
|
-
...failure2,
|
|
36927
|
-
failure_area: "cli",
|
|
36928
|
-
error_kind: "validation"
|
|
36929
|
-
});
|
|
36930
|
-
process.exit(2);
|
|
36931
|
-
};
|
|
36932
|
-
const failValidation = (report, stage) => failInvocation(formatValidationError(report, schema), report, {
|
|
36933
|
-
error_code: FAILURE_CODES.CLI_RUN_INPUT_VALIDATION_FAILED,
|
|
36934
|
-
failure_stage: stage
|
|
36935
|
-
});
|
|
36936
|
-
let parsed;
|
|
36937
|
-
try {
|
|
36938
|
-
parsed = parseFlags(argvForFlags, schema);
|
|
36939
|
-
} catch (err) {
|
|
36940
|
-
if (err instanceof FlagParseException) {
|
|
36941
|
-
await failInvocation(err.message, null, {
|
|
36942
|
-
error_code: FAILURE_CODES.CLI_RUN_FLAG_PARSE_FAILED,
|
|
36943
|
-
failure_stage: "cli_run_parse_flags"
|
|
36944
|
-
});
|
|
36945
|
-
}
|
|
36946
|
-
throw err;
|
|
36947
|
-
}
|
|
36948
|
-
if (parsed.helpRequested) {
|
|
36949
|
-
printToolHelp(meta3);
|
|
36950
|
-
return;
|
|
36951
|
-
}
|
|
36952
|
-
if (parsed.positional.length > 0) {
|
|
36953
|
-
console.error(
|
|
36954
|
-
`Note: ignoring unused argument(s): ${parsed.positional.join(", ")}. Pass values as --flag <value> or --flag=<value>.`
|
|
36955
|
-
);
|
|
36956
|
-
}
|
|
36957
|
-
let payload = {};
|
|
36958
|
-
if (parsed.rawArgs !== null) {
|
|
36959
|
-
let rawJson = parsed.rawArgs;
|
|
36960
|
-
if (rawJson === "-") {
|
|
36961
|
-
rawJson = await readStdin();
|
|
36962
|
-
}
|
|
36963
|
-
try {
|
|
36964
|
-
const parsedRaw = JSON.parse(rawJson);
|
|
36965
|
-
if (parsedRaw === null || typeof parsedRaw !== "object" || Array.isArray(parsedRaw)) {
|
|
36966
|
-
console.error("--args must be a JSON object");
|
|
36967
|
-
await trackRunFailure(toolName, startedAt, {
|
|
36968
|
-
error_code: FAILURE_CODES.CLI_RUN_ARGS_NOT_OBJECT,
|
|
36969
|
-
failure_stage: "cli_run_parse_raw_args",
|
|
36970
|
-
failure_area: "cli",
|
|
36971
|
-
error_kind: "validation"
|
|
36972
|
-
});
|
|
36973
|
-
process.exit(2);
|
|
36974
|
-
}
|
|
36975
|
-
payload = parsedRaw;
|
|
36976
|
-
} catch (err) {
|
|
36977
|
-
console.error(`--args is not valid JSON: ${err instanceof Error ? err.message : err}`);
|
|
36978
|
-
await trackRunFailure(toolName, startedAt, {
|
|
36979
|
-
error_code: FAILURE_CODES.CLI_RUN_ARGS_JSON_INVALID,
|
|
36980
|
-
failure_stage: "cli_run_parse_raw_args",
|
|
36981
|
-
failure_area: "cli",
|
|
36982
|
-
error_kind: "validation"
|
|
36983
|
-
});
|
|
36984
|
-
process.exit(2);
|
|
36985
|
-
}
|
|
36986
|
-
}
|
|
36987
|
-
for (const [k, v] of Object.entries(parsed.args)) {
|
|
36988
|
-
payload[k] = v;
|
|
36989
|
-
}
|
|
36990
|
-
const missing = findMissingRequired(payload, schema);
|
|
36991
|
-
if (missing.length > 0) {
|
|
36992
|
-
await failValidation({ missing, invalid: [], rawIssues: null }, "cli_run_required_flags");
|
|
36993
|
-
}
|
|
36994
|
-
let result;
|
|
36995
|
-
let note;
|
|
36996
|
-
let images = [];
|
|
36997
|
-
try {
|
|
36998
|
-
const resp = await callTool(toolName, payload);
|
|
36999
|
-
const { url: url2, token } = await baseUrl();
|
|
37000
|
-
const materialized = await materializeArtifacts(resp.data, {
|
|
37001
|
-
toolsUrl: url2,
|
|
37002
|
-
authToken: token,
|
|
37003
|
-
deviceId: getDeviceIdFromArgs(payload)
|
|
37004
|
-
});
|
|
37005
|
-
result = materialized.result;
|
|
37006
|
-
images = materialized.images;
|
|
37007
|
-
note = resp.note;
|
|
37008
|
-
} catch (err) {
|
|
37009
|
-
const report = describeServerValidationFailure(err, payload, schema);
|
|
37010
|
-
if (report) {
|
|
37011
|
-
await failValidation(report, "cli_run_server_validation");
|
|
37012
|
-
}
|
|
37013
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
37014
|
-
await trackRunFailure(toolName, startedAt, {
|
|
37015
|
-
error_code: FAILURE_CODES.CLI_RUN_TOOL_CALL_FAILED,
|
|
37016
|
-
failure_stage: "cli_run_call_tool",
|
|
37017
|
-
failure_area: "cli",
|
|
37018
|
-
error_kind: "unknown"
|
|
37019
|
-
});
|
|
37020
|
-
process.exit(1);
|
|
37021
|
-
}
|
|
37022
|
-
if (outPath && meta3.outputHint === "image") {
|
|
37023
|
-
try {
|
|
37024
|
-
if (images.length > 0) {
|
|
37025
|
-
fs12.mkdirSync(path17.dirname(path17.resolve(outPath)), { recursive: true });
|
|
37026
|
-
fs12.writeFileSync(outPath, images[0].data);
|
|
37027
|
-
} else if (result && typeof result === "object") {
|
|
37028
|
-
await fetchImageToFile(result, outPath);
|
|
37029
|
-
}
|
|
37030
|
-
} catch (err) {
|
|
37031
|
-
console.error(`Failed to save image: ${err instanceof Error ? err.message : err}`);
|
|
37032
|
-
await trackRunFailure(toolName, startedAt, {
|
|
37033
|
-
error_code: FAILURE_CODES.CLI_RUN_SAVE_IMAGE_FAILED,
|
|
37034
|
-
failure_stage: "cli_run_save_image",
|
|
37035
|
-
failure_area: "cli",
|
|
37036
|
-
error_kind: "unknown"
|
|
37037
|
-
});
|
|
37038
|
-
process.exit(1);
|
|
37039
|
-
}
|
|
37040
|
-
}
|
|
37041
|
-
if (note) console.error(note);
|
|
37042
|
-
console.log(renderResult(result, meta3.outputHint, images, json2));
|
|
37043
|
-
if (outPath && meta3.outputHint === "image" && !json2) {
|
|
37044
|
-
console.log(`Wrote: ${outPath}`);
|
|
37045
|
-
}
|
|
37046
|
-
}
|
|
37047
|
-
|
|
37048
|
-
// ../argent-cli/src/e2e.ts
|
|
37049
|
-
import * as fsp from "node:fs/promises";
|
|
37050
|
-
import { constants as fsConstants2 } from "node:fs";
|
|
37051
|
-
import { createHash as createHash5 } from "node:crypto";
|
|
37052
|
-
import * as path18 from "node:path";
|
|
37053
|
-
|
|
37054
|
-
// ../argent-cli/src/command-args.ts
|
|
37055
|
-
var UsageError = class extends Error {
|
|
37056
|
-
constructor(message) {
|
|
37057
|
-
super(message);
|
|
37058
|
-
this.name = "UsageError";
|
|
37059
|
-
}
|
|
37060
|
-
};
|
|
37061
|
-
function listChoices(choices) {
|
|
37062
|
-
const quoted = choices.map((c2) => `"${c2}"`);
|
|
37063
|
-
if (quoted.length <= 1) return quoted.join("");
|
|
37064
|
-
return `${quoted.slice(0, -1).join(", ")} or ${quoted[quoted.length - 1]}`;
|
|
37065
|
-
}
|
|
37066
|
-
function resolveName(tok, specs) {
|
|
37067
|
-
if (tok.startsWith("--")) return tok.slice(2) in specs ? tok.slice(2) : null;
|
|
37068
|
-
const short = tok.slice(1);
|
|
37069
|
-
for (const [name, spec] of Object.entries(specs)) {
|
|
37070
|
-
if (spec.alias === short) return name;
|
|
37071
|
-
}
|
|
37072
|
-
return null;
|
|
37073
|
-
}
|
|
37074
|
-
function parseCommandArgs(argv, specs) {
|
|
37075
|
-
const positionals = [];
|
|
37076
|
-
const options = {};
|
|
37077
|
-
for (let i2 = 0; i2 < argv.length; i2++) {
|
|
37078
|
-
const tok = argv[i2];
|
|
37079
|
-
if (tok === "--") {
|
|
37080
|
-
positionals.push(...argv.slice(i2 + 1));
|
|
37081
|
-
break;
|
|
37082
|
-
}
|
|
37083
|
-
if (!tok.startsWith("-") || tok === "-") {
|
|
37084
|
-
positionals.push(tok);
|
|
37085
|
-
continue;
|
|
37086
|
-
}
|
|
37087
|
-
const eq = tok.startsWith("--") ? tok.indexOf("=") : -1;
|
|
37088
|
-
const flag = eq === -1 ? tok : tok.slice(0, eq);
|
|
37089
|
-
const inlineValue = eq === -1 ? void 0 : tok.slice(eq + 1);
|
|
37090
|
-
const name = resolveName(flag, specs);
|
|
37091
|
-
if (name === null) throw new UsageError(`Unknown flag: ${tok}`);
|
|
37092
|
-
const spec = specs[name];
|
|
37093
|
-
const display = `--${name}`;
|
|
37094
|
-
if (spec.kind === "boolean") {
|
|
37095
|
-
if (inlineValue !== void 0) throw new UsageError(`${display} does not take a value`);
|
|
37096
|
-
const next = argv[i2 + 1]?.trim().toLowerCase();
|
|
37097
|
-
if (next === "true" || next === "false") {
|
|
37098
|
-
throw new UsageError(
|
|
37099
|
-
`${display} does not take a value \u2014 it is a switch; omit it to leave the option off`
|
|
37100
|
-
);
|
|
37101
|
-
}
|
|
37102
|
-
options[name] = true;
|
|
37103
|
-
continue;
|
|
37104
|
-
}
|
|
37105
|
-
let value = inlineValue;
|
|
37106
|
-
if (value === void 0) {
|
|
37107
|
-
const next = argv[i2 + 1];
|
|
37108
|
-
if (next !== void 0 && (!next.startsWith("-") || next === "-")) {
|
|
37109
|
-
value = next;
|
|
37110
|
-
i2 += 1;
|
|
37111
|
-
}
|
|
37112
|
-
} else if (value === "") {
|
|
37113
|
-
value = void 0;
|
|
37114
|
-
}
|
|
37115
|
-
if (value === void 0) throw new UsageError(`${display} requires a value`);
|
|
37116
|
-
if (spec.choices && !spec.choices.includes(value)) {
|
|
37117
|
-
throw new UsageError(`${display} must be ${listChoices(spec.choices)}, got "${value}"`);
|
|
37118
|
-
}
|
|
37119
|
-
options[name] = value;
|
|
37120
|
-
}
|
|
37121
|
-
return { positionals, options };
|
|
37122
|
-
}
|
|
37123
|
-
|
|
37124
|
-
// ../argent-cli/src/e2e.ts
|
|
37125
|
-
var STATUS_GLYPH = {
|
|
37126
|
-
pass: "\u2713",
|
|
37127
|
-
fail: "\u2717",
|
|
37128
|
-
error: "\u2717",
|
|
37129
|
-
skip: "\xB7"
|
|
37130
|
-
};
|
|
37131
|
-
var MAX_RENDER_DEPTH = 20;
|
|
37132
|
-
function stepIndent(depth) {
|
|
37133
|
-
if (typeof depth !== "number" || !Number.isInteger(depth) || depth <= 0) return "";
|
|
37134
|
-
return " ".repeat(Math.min(depth, MAX_RENDER_DEPTH));
|
|
37135
|
-
}
|
|
37136
|
-
function durationSuffix(ms) {
|
|
37137
|
-
if (typeof ms !== "number" || !Number.isFinite(ms) || ms < 0) return "";
|
|
37138
|
-
const tenths = Math.round(ms / 100);
|
|
37139
|
-
if (tenths < 600) return ` (${(tenths / 10).toFixed(1)}s)`;
|
|
37140
|
-
const seconds = Math.round(ms / 1e3);
|
|
37141
|
-
return ` (${Math.floor(seconds / 60)}m ${seconds % 60}s)`;
|
|
37142
|
-
}
|
|
37143
|
-
function printHelp(toStderr = false) {
|
|
37144
|
-
const print = toStderr ? console.error : console.log;
|
|
37145
|
-
print(`Usage: argent e2e <subcommand> [options]
|
|
37146
|
-
|
|
37147
|
-
Run a YAML e2e test without an LLM in the loop. \`run\` takes any of these forms:
|
|
36879
|
+
Run a YAML e2e test without an LLM in the loop. \`run\` takes any of these forms:
|
|
37148
36880
|
|
|
37149
36881
|
a name An e2e test saved under .argent/e2e or .argent/flows, resolved
|
|
37150
36882
|
from the current directory. "checkout" runs
|
|
@@ -37405,14 +37137,14 @@ function shellQuoteArg(arg) {
|
|
|
37405
37137
|
return `'${arg.replaceAll("'", "'\\''")}'`;
|
|
37406
37138
|
}
|
|
37407
37139
|
function rerunCommand(flowPath, rel, projectRoot, args) {
|
|
37408
|
-
const pathArg = (p) => shellQuoteArg(p.startsWith("-") ? `.${
|
|
37409
|
-
const fromCwd =
|
|
37410
|
-
const shown =
|
|
37140
|
+
const pathArg = (p) => shellQuoteArg(p.startsWith("-") ? `.${path17.sep}${p}` : p);
|
|
37141
|
+
const fromCwd = path17.relative(projectRoot, flowPath);
|
|
37142
|
+
const shown = path17.isAbsolute(fromCwd) || fromCwd.split(/[\\/]+/).includes("..") ? flowPath : fromCwd;
|
|
37411
37143
|
const parts = ["argent e2e run", pathArg(shown)];
|
|
37412
37144
|
if (args.device) parts.push("--device", shellQuoteArg(args.device));
|
|
37413
37145
|
if (args.platform) parts.push("--platform", shellQuoteArg(args.platform));
|
|
37414
37146
|
if (args.updateBaselines) parts.push("--update-baselines");
|
|
37415
|
-
if (args.output) parts.push("--output", pathArg(
|
|
37147
|
+
if (args.output) parts.push("--output", pathArg(path17.join(args.output, path17.dirname(rel))));
|
|
37416
37148
|
return parts.join(" ");
|
|
37417
37149
|
}
|
|
37418
37150
|
var EXPORT_SOURCE_MARKER = ".argent-e2e-source";
|
|
@@ -37420,8 +37152,8 @@ var LEGACY_EXPORT_SOURCE_MARKER = ".argent-flow-source";
|
|
|
37420
37152
|
var MARKER_READ_RETRIES = 4;
|
|
37421
37153
|
var MARKER_READ_DELAY_MS = 5;
|
|
37422
37154
|
async function readExportMarker(dir) {
|
|
37423
|
-
const owner = await readMarkerFile(
|
|
37424
|
-
return owner !== void 0 ? owner : await readMarkerFile(
|
|
37155
|
+
const owner = await readMarkerFile(path17.join(dir, EXPORT_SOURCE_MARKER));
|
|
37156
|
+
return owner !== void 0 ? owner : await readMarkerFile(path17.join(dir, LEGACY_EXPORT_SOURCE_MARKER));
|
|
37425
37157
|
}
|
|
37426
37158
|
async function readMarkerFile(marker) {
|
|
37427
37159
|
for (let attempt = 0; ; attempt++) {
|
|
@@ -37458,7 +37190,7 @@ function occupiedBy(owner) {
|
|
|
37458
37190
|
async function takeExportDir(dir, flowPath) {
|
|
37459
37191
|
try {
|
|
37460
37192
|
await fsp.mkdir(dir, { recursive: true });
|
|
37461
|
-
await fsp.writeFile(
|
|
37193
|
+
await fsp.writeFile(path17.join(dir, EXPORT_SOURCE_MARKER), `${flowPath}
|
|
37462
37194
|
`, { flag: "wx" });
|
|
37463
37195
|
return null;
|
|
37464
37196
|
} catch (err) {
|
|
@@ -37477,7 +37209,7 @@ async function claimExportDirName(outputDir, flowPath, stem) {
|
|
|
37477
37209
|
}
|
|
37478
37210
|
const avoided = [];
|
|
37479
37211
|
for (const name of candidates) {
|
|
37480
|
-
const dir =
|
|
37212
|
+
const dir = path17.join(outputDir, name);
|
|
37481
37213
|
const claim2 = await classifyExportDir(dir, flowPath);
|
|
37482
37214
|
const reason = claim2.state === "foreign" ? occupiedBy(claim2.owner) : await takeExportDir(dir, flowPath);
|
|
37483
37215
|
if (reason !== null) {
|
|
@@ -37497,7 +37229,7 @@ async function claimExportDirName(outputDir, flowPath, stem) {
|
|
|
37497
37229
|
return null;
|
|
37498
37230
|
}
|
|
37499
37231
|
async function exportFailureArtifacts(report, outputDir, flowPath, ctx) {
|
|
37500
|
-
const stem =
|
|
37232
|
+
const stem = path17.basename(flowPath, ".yaml");
|
|
37501
37233
|
if (!SAFE_ARTIFACT_NAME.test(stem)) {
|
|
37502
37234
|
console.error(
|
|
37503
37235
|
`warning: skipping artifact export for unsafe e2e test filename ${JSON.stringify(stem)}`
|
|
@@ -37530,11 +37262,11 @@ async function exportFailureArtifacts(report, outputDir, flowPath, ctx) {
|
|
|
37530
37262
|
if (dir === null) {
|
|
37531
37263
|
const dirName = await claimExportDirName(outputDir, flowPath, stem);
|
|
37532
37264
|
if (dirName === null) return;
|
|
37533
|
-
dir =
|
|
37265
|
+
dir = path17.join(outputDir, dirName);
|
|
37534
37266
|
}
|
|
37535
|
-
const dest =
|
|
37536
|
-
const rel =
|
|
37537
|
-
if (rel.startsWith("..") ||
|
|
37267
|
+
const dest = path17.join(dir, fileName(role));
|
|
37268
|
+
const rel = path17.relative(outputDir, dest);
|
|
37269
|
+
if (rel.startsWith("..") || path17.isAbsolute(rel)) continue;
|
|
37538
37270
|
try {
|
|
37539
37271
|
await fsp.copyFile(value, dest);
|
|
37540
37272
|
s.artifacts[role] = dest;
|
|
@@ -37549,7 +37281,7 @@ async function exportFailureArtifacts(report, outputDir, flowPath, ctx) {
|
|
|
37549
37281
|
function keyFromBaselinePath(artifacts) {
|
|
37550
37282
|
const baseline = artifacts.baseline;
|
|
37551
37283
|
if (typeof baseline !== "string") return null;
|
|
37552
|
-
return
|
|
37284
|
+
return path17.basename(baseline).replace(/\.png$/, "");
|
|
37553
37285
|
}
|
|
37554
37286
|
function resolveArtifactDisplayPaths(report) {
|
|
37555
37287
|
for (const s of report.steps) {
|
|
@@ -37606,17 +37338,17 @@ async function collectRunnableFlowPaths(dir, relDir = "") {
|
|
|
37606
37338
|
const found = [];
|
|
37607
37339
|
const entries = await fsp.readdir(dir, { withFileTypes: true });
|
|
37608
37340
|
for (const entry of entries) {
|
|
37609
|
-
const rel = relDir ?
|
|
37341
|
+
const rel = relDir ? path17.join(relDir, entry.name) : entry.name;
|
|
37610
37342
|
if (entry.isDirectory()) {
|
|
37611
37343
|
if (entry.name === "__baselines__") continue;
|
|
37612
37344
|
found.push(
|
|
37613
|
-
...await collectRunnableFlowPaths(
|
|
37345
|
+
...await collectRunnableFlowPaths(path17.join(dir, entry.name), rel).catch(() => [])
|
|
37614
37346
|
);
|
|
37615
37347
|
continue;
|
|
37616
37348
|
}
|
|
37617
37349
|
if (!entry.name.endsWith(".yaml")) continue;
|
|
37618
|
-
if (!SAFE_FLOW_NAME.test(
|
|
37619
|
-
if (await isRunnableFlowFile(
|
|
37350
|
+
if (!SAFE_FLOW_NAME.test(path17.basename(entry.name, ".yaml"))) continue;
|
|
37351
|
+
if (await isRunnableFlowFile(path17.join(dir, entry.name))) found.push(rel);
|
|
37620
37352
|
}
|
|
37621
37353
|
return found;
|
|
37622
37354
|
}
|
|
@@ -37624,26 +37356,26 @@ async function resolveFlowRef(ref, projectRoot) {
|
|
|
37624
37356
|
if (!SAFE_FLOW_NAME.test(ref)) return { suppliedPath: ref, fromName: false };
|
|
37625
37357
|
const picked = await resolveE2eFile(projectRoot, ref);
|
|
37626
37358
|
return {
|
|
37627
|
-
suppliedPath:
|
|
37359
|
+
suppliedPath: path17.relative(projectRoot, picked.path),
|
|
37628
37360
|
fromName: true,
|
|
37629
|
-
...picked.shadowed === void 0 ? {} : { shadowed:
|
|
37361
|
+
...picked.shadowed === void 0 ? {} : { shadowed: path17.relative(projectRoot, picked.shadowed) }
|
|
37630
37362
|
};
|
|
37631
37363
|
}
|
|
37632
37364
|
async function savedFlowHint(projectRoot, missingPath) {
|
|
37633
|
-
const dirs = E2E_DIRS.map((rel) => ({ rel, abs:
|
|
37365
|
+
const dirs = E2E_DIRS.map((rel) => ({ rel, abs: path17.resolve(projectRoot, rel) }));
|
|
37634
37366
|
for (const { abs } of dirs) {
|
|
37635
|
-
const within =
|
|
37636
|
-
if (!within.startsWith("..") && !
|
|
37367
|
+
const within = path17.relative(abs, missingPath);
|
|
37368
|
+
if (!within.startsWith("..") && !path17.isAbsolute(within)) return "";
|
|
37637
37369
|
}
|
|
37638
|
-
const wanted = `${
|
|
37370
|
+
const wanted = `${path17.basename(missingPath, ".yaml")}.yaml`;
|
|
37639
37371
|
for (const { rel, abs } of dirs) {
|
|
37640
37372
|
const entries = await fsp.readdir(abs).catch(() => null);
|
|
37641
37373
|
if (entries === null) continue;
|
|
37642
37374
|
const actual = entries.includes(wanted) ? wanted : entries.find((name2) => name2.toLowerCase() === wanted.toLowerCase());
|
|
37643
37375
|
if (actual === void 0) continue;
|
|
37644
|
-
const name =
|
|
37376
|
+
const name = path17.basename(actual, ".yaml");
|
|
37645
37377
|
if (!SAFE_FLOW_NAME.test(name)) return "";
|
|
37646
|
-
if (!await isRunnableFlowFile(
|
|
37378
|
+
if (!await isRunnableFlowFile(path17.join(abs, actual))) return "";
|
|
37647
37379
|
return `
|
|
37648
37380
|
An e2e test named "${name}" is saved under ${rel} \u2014 did you mean: argent e2e run ${name}`;
|
|
37649
37381
|
}
|
|
@@ -37653,17 +37385,17 @@ async function collectFlowFiles(dir, recursive2) {
|
|
|
37653
37385
|
const found = [];
|
|
37654
37386
|
const walk = async (current, rel) => {
|
|
37655
37387
|
for (const entry of await fsp.readdir(current, { withFileTypes: true })) {
|
|
37656
|
-
const entryRel = rel ?
|
|
37388
|
+
const entryRel = rel ? path17.join(rel, entry.name) : entry.name;
|
|
37657
37389
|
if (entry.isDirectory()) {
|
|
37658
37390
|
if (recursive2 && !entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
37659
|
-
await walk(
|
|
37391
|
+
await walk(path17.join(current, entry.name), entryRel).catch(() => {
|
|
37660
37392
|
});
|
|
37661
37393
|
}
|
|
37662
37394
|
continue;
|
|
37663
37395
|
}
|
|
37664
37396
|
if (!entry.name.endsWith(".yaml")) continue;
|
|
37665
|
-
if (!SAFE_FLOW_NAME.test(
|
|
37666
|
-
if (await isRunnableFlowFile(
|
|
37397
|
+
if (!SAFE_FLOW_NAME.test(path17.basename(entry.name, ".yaml"))) continue;
|
|
37398
|
+
if (await isRunnableFlowFile(path17.join(current, entry.name))) found.push(entryRel);
|
|
37667
37399
|
}
|
|
37668
37400
|
};
|
|
37669
37401
|
await walk(dir, "");
|
|
@@ -37810,7 +37542,7 @@ async function runFlowDirectory(dir, args, projectRoot, options) {
|
|
|
37810
37542
|
);
|
|
37811
37543
|
}
|
|
37812
37544
|
const { callTool, baseUrl } = runToolsClient(args, options);
|
|
37813
|
-
const outputBase = args.output ?
|
|
37545
|
+
const outputBase = args.output ? path17.resolve(args.output) : void 0;
|
|
37814
37546
|
const results = [];
|
|
37815
37547
|
const failures = [];
|
|
37816
37548
|
const batchStartedAt = Date.now();
|
|
@@ -37823,7 +37555,7 @@ async function runFlowDirectory(dir, args, projectRoot, options) {
|
|
|
37823
37555
|
if (!args.json) console.log(` ${STATUS_GLYPH.skip} not run (batch stopped)`);
|
|
37824
37556
|
continue;
|
|
37825
37557
|
}
|
|
37826
|
-
const flowPath =
|
|
37558
|
+
const flowPath = path17.join(dir, rel);
|
|
37827
37559
|
const rerun = rerunCommand(flowPath, rel, projectRoot, args);
|
|
37828
37560
|
let report;
|
|
37829
37561
|
try {
|
|
@@ -37865,7 +37597,7 @@ async function runFlowDirectory(dir, args, projectRoot, options) {
|
|
|
37865
37597
|
printWarnings(nestedStepWarnings(report.steps), args.json);
|
|
37866
37598
|
await exportAndResolveArtifacts(
|
|
37867
37599
|
report,
|
|
37868
|
-
outputBase ?
|
|
37600
|
+
outputBase ? path17.join(outputBase, path17.dirname(rel)) : void 0,
|
|
37869
37601
|
flowPath,
|
|
37870
37602
|
baseUrl
|
|
37871
37603
|
);
|
|
@@ -37931,14 +37663,14 @@ async function e2e(argv, options) {
|
|
|
37931
37663
|
for (const dir of E2E_DIRS) {
|
|
37932
37664
|
let rels;
|
|
37933
37665
|
try {
|
|
37934
|
-
rels = (await collectRunnableFlowPaths(
|
|
37666
|
+
rels = (await collectRunnableFlowPaths(path17.join(process.cwd(), dir))).sort();
|
|
37935
37667
|
} catch {
|
|
37936
37668
|
continue;
|
|
37937
37669
|
}
|
|
37938
37670
|
anyDir = true;
|
|
37939
37671
|
for (const rel of rels) {
|
|
37940
|
-
const shown =
|
|
37941
|
-
const name =
|
|
37672
|
+
const shown = path17.join(dir, rel);
|
|
37673
|
+
const name = path17.dirname(rel) === "." ? path17.basename(rel, ".yaml") : void 0;
|
|
37942
37674
|
const usedByName = name === void 0 ? void 0 : byName.get(name);
|
|
37943
37675
|
if (name !== void 0 && usedByName === void 0) byName.set(name, shown);
|
|
37944
37676
|
lines.push(shown);
|
|
@@ -38009,10 +37741,10 @@ async function e2e(argv, options) {
|
|
|
38009
37741
|
}
|
|
38010
37742
|
if (suppliedPath.split(/[\\/]+/).includes("..")) {
|
|
38011
37743
|
let recovery = "Pass the fully resolved path to the e2e test's YAML.";
|
|
38012
|
-
const suppliedBase2 =
|
|
37744
|
+
const suppliedBase2 = path17.basename(suppliedPath);
|
|
38013
37745
|
if (suppliedBase2 !== ".." && suppliedBase2 !== ".") {
|
|
38014
37746
|
try {
|
|
38015
|
-
const resolved =
|
|
37747
|
+
const resolved = path17.join(await fsp.realpath(path17.dirname(suppliedPath)), suppliedBase2);
|
|
38016
37748
|
await fsp.stat(resolved);
|
|
38017
37749
|
recovery = `Did you mean: argent e2e run ${shellQuoteArg(resolved)}`;
|
|
38018
37750
|
} catch {
|
|
@@ -38024,7 +37756,7 @@ async function e2e(argv, options) {
|
|
|
38024
37756
|
2
|
|
38025
37757
|
);
|
|
38026
37758
|
}
|
|
38027
|
-
const resolvedPath =
|
|
37759
|
+
const resolvedPath = path17.resolve(projectRoot, suppliedPath);
|
|
38028
37760
|
let isDirectory = false;
|
|
38029
37761
|
try {
|
|
38030
37762
|
isDirectory = (await fsp.stat(resolvedPath)).isDirectory();
|
|
@@ -38047,16 +37779,16 @@ async function e2e(argv, options) {
|
|
|
38047
37779
|
}
|
|
38048
37780
|
const separatorTrimmedPath = suppliedPath.replace(/[\\/]+$/, "");
|
|
38049
37781
|
if (separatorTrimmedPath !== suppliedPath && separatorTrimmedPath !== "") {
|
|
38050
|
-
const hint = SAFE_FLOW_NAME.test(separatorTrimmedPath) ? `.${
|
|
37782
|
+
const hint = SAFE_FLOW_NAME.test(separatorTrimmedPath) ? `.${path17.sep}${separatorTrimmedPath}` : separatorTrimmedPath;
|
|
38051
37783
|
return fail(
|
|
38052
37784
|
`E2E test path must not end in a path separator \u2014 the separator claims a directory, which the kernel would refuse to open as a file, so the CLI would run a file this string does not name: ${suppliedPath}
|
|
38053
37785
|
Did you mean: argent e2e run ${shellQuoteArg(hint)}`,
|
|
38054
37786
|
2
|
|
38055
37787
|
);
|
|
38056
37788
|
}
|
|
38057
|
-
if (
|
|
38058
|
-
const looksLikeName = !suppliedPath.includes("/") && !suppliedPath.includes("\\") &&
|
|
38059
|
-
if (
|
|
37789
|
+
if (path17.extname(suppliedPath) !== ".yaml") {
|
|
37790
|
+
const looksLikeName = !suppliedPath.includes("/") && !suppliedPath.includes("\\") && path17.extname(suppliedPath) === "";
|
|
37791
|
+
if (path17.basename(suppliedPath).toLowerCase() === ".yaml") {
|
|
38060
37792
|
return fail(
|
|
38061
37793
|
`E2E test filename must have a non-empty name containing only letters, numbers, "_", or "-": ${suppliedPath}`,
|
|
38062
37794
|
2
|
|
@@ -38069,15 +37801,15 @@ Names run \`${E2E_DIRS.map((dir) => `${dir}/<name>.yaml`).join("` or `")}\`; pas
|
|
|
38069
37801
|
2
|
|
38070
37802
|
);
|
|
38071
37803
|
}
|
|
38072
|
-
if (
|
|
37804
|
+
if (path17.extname(suppliedPath).toLowerCase() === ".yaml") {
|
|
38073
37805
|
return fail(
|
|
38074
|
-
`E2E test extension must be lowercase .yaml, not ${
|
|
37806
|
+
`E2E test extension must be lowercase .yaml, not ${path17.extname(suppliedPath)}: ${suppliedPath}`,
|
|
38075
37807
|
2
|
|
38076
37808
|
);
|
|
38077
37809
|
}
|
|
38078
37810
|
return fail(`E2E test path must end in .yaml: ${suppliedPath}`, 2);
|
|
38079
37811
|
}
|
|
38080
|
-
const flowName =
|
|
37812
|
+
const flowName = path17.basename(suppliedPath, ".yaml");
|
|
38081
37813
|
if (!SAFE_FLOW_NAME.test(flowName)) {
|
|
38082
37814
|
return fail(
|
|
38083
37815
|
`E2E test filename must have a non-empty name containing only letters, numbers, "_", or "-": ${suppliedPath}`,
|
|
@@ -38101,12 +37833,12 @@ No e2e test named "${args.flowRef}" is saved in ${E2E_DIRS.join(" or ")} \u2014
|
|
|
38101
37833
|
}
|
|
38102
37834
|
return fail(`${detail}: ${flowPath}${recovery}`, 2);
|
|
38103
37835
|
}
|
|
38104
|
-
const suppliedBase =
|
|
38105
|
-
const siblings = await fsp.readdir(
|
|
37836
|
+
const suppliedBase = path17.basename(flowPath);
|
|
37837
|
+
const siblings = await fsp.readdir(path17.dirname(flowPath)).catch(() => null);
|
|
38106
37838
|
if (siblings !== null && !siblings.includes(suppliedBase)) {
|
|
38107
37839
|
const actual = siblings.find((name) => name.toLowerCase() === suppliedBase.toLowerCase());
|
|
38108
|
-
const actualRunnable = actual !== void 0 &&
|
|
38109
|
-
const recovery = actualRunnable ? fromName ? `Did you mean: argent e2e run ${
|
|
37840
|
+
const actualRunnable = actual !== void 0 && path17.extname(actual) === ".yaml" && SAFE_FLOW_NAME.test(path17.basename(actual, ".yaml"));
|
|
37841
|
+
const recovery = actualRunnable ? fromName ? `Did you mean: argent e2e run ${path17.basename(actual, ".yaml")}` : `Did you mean: argent e2e run ${shellQuoteArg(path17.join(path17.dirname(suppliedPath), actual))}` : actual !== void 0 ? `Rename ${actual} to ${suppliedBase} to run it \u2014 e2e test files must be lowercase .yaml.` : "Pass the e2e test file's name exactly as it appears on disk.";
|
|
38110
37842
|
return fail(
|
|
38111
37843
|
`E2E test path must name the file as it appears on disk \u2014 this filesystem matched ${JSON.stringify(suppliedBase)} case-insensitively${actual !== void 0 ? ` to ${JSON.stringify(actual)}` : ""}, so the test name (which keys the report, __baselines__/, and --output) would be one no file carries: ${suppliedPath}
|
|
38112
37844
|
${recovery}`,
|
|
@@ -38165,7 +37897,7 @@ ${recovery}`,
|
|
|
38165
37897
|
try {
|
|
38166
37898
|
await exportAndResolveArtifacts(
|
|
38167
37899
|
report,
|
|
38168
|
-
args.output ?
|
|
37900
|
+
args.output ? path17.resolve(args.output) : void 0,
|
|
38169
37901
|
flowPath,
|
|
38170
37902
|
baseUrl
|
|
38171
37903
|
);
|
|
@@ -38194,6 +37926,313 @@ ${renderSummary(report, { withDevice: true })}`);
|
|
|
38194
37926
|
return exitAfterFlush(report.ok && unwritten.length === 0 ? 0 : 1);
|
|
38195
37927
|
}
|
|
38196
37928
|
|
|
37929
|
+
// ../argent-cli/src/run.ts
|
|
37930
|
+
function splitOptions(argv) {
|
|
37931
|
+
let json2 = false;
|
|
37932
|
+
let outPath = null;
|
|
37933
|
+
const rest = [];
|
|
37934
|
+
for (let i2 = 0; i2 < argv.length; i2++) {
|
|
37935
|
+
const tok = argv[i2];
|
|
37936
|
+
if (tok === "--json") {
|
|
37937
|
+
json2 = true;
|
|
37938
|
+
continue;
|
|
37939
|
+
}
|
|
37940
|
+
if (tok === "--out") {
|
|
37941
|
+
const v = argv[i2 + 1];
|
|
37942
|
+
if (!v) throw new FlagParseException("--out requires a path");
|
|
37943
|
+
outPath = v;
|
|
37944
|
+
i2 += 1;
|
|
37945
|
+
continue;
|
|
37946
|
+
}
|
|
37947
|
+
if (tok.startsWith("--out=")) {
|
|
37948
|
+
outPath = tok.slice("--out=".length);
|
|
37949
|
+
continue;
|
|
37950
|
+
}
|
|
37951
|
+
rest.push(tok);
|
|
37952
|
+
}
|
|
37953
|
+
return { json: json2, outPath, argvForFlags: rest };
|
|
37954
|
+
}
|
|
37955
|
+
async function readStdin() {
|
|
37956
|
+
return new Promise((resolve13, reject) => {
|
|
37957
|
+
let data = "";
|
|
37958
|
+
process.stdin.setEncoding("utf8");
|
|
37959
|
+
process.stdin.on("data", (chunk) => {
|
|
37960
|
+
data += chunk;
|
|
37961
|
+
});
|
|
37962
|
+
process.stdin.on("end", () => resolve13(data));
|
|
37963
|
+
process.stdin.on("error", reject);
|
|
37964
|
+
});
|
|
37965
|
+
}
|
|
37966
|
+
function printToolHelp(meta3) {
|
|
37967
|
+
const description = meta3.description?.trim() ?? "";
|
|
37968
|
+
const schema = meta3.inputSchema;
|
|
37969
|
+
const hasOwnArgsField = schema?.properties?.args !== void 0;
|
|
37970
|
+
console.log(`argent run ${meta3.name} [flags]`);
|
|
37971
|
+
if (description) console.log(`
|
|
37972
|
+
${description}
|
|
37973
|
+
`);
|
|
37974
|
+
console.log("Flags:");
|
|
37975
|
+
console.log(formatSchemaUsage(schema));
|
|
37976
|
+
console.log("\nGlobal flags:");
|
|
37977
|
+
if (!hasOwnArgsField) {
|
|
37978
|
+
console.log(" --args <json> Pass the entire payload as JSON (overrides flags)");
|
|
37979
|
+
console.log(" --args - Read the entire payload as JSON from stdin");
|
|
37980
|
+
}
|
|
37981
|
+
console.log(" --<field>-json <json> Pass a single field as JSON (objects/nested arrays)");
|
|
37982
|
+
console.log(" --json Print the raw JSON result");
|
|
37983
|
+
console.log(" --out <path> For image results, save to <path> instead of fetching URL");
|
|
37984
|
+
console.log(" --help, -h Show this help");
|
|
37985
|
+
}
|
|
37986
|
+
async function fetchImageToFile(result, outPath) {
|
|
37987
|
+
const url2 = result.url;
|
|
37988
|
+
if (!url2) {
|
|
37989
|
+
throw new Error("Tool result did not include a `url`; cannot save image");
|
|
37990
|
+
}
|
|
37991
|
+
const res = await fetch(url2);
|
|
37992
|
+
if (!res.ok) throw new Error(`Failed to download image: ${res.status} ${res.statusText}`);
|
|
37993
|
+
const buf = Buffer.from(await res.arrayBuffer());
|
|
37994
|
+
fs12.mkdirSync(path18.dirname(path18.resolve(outPath)), { recursive: true });
|
|
37995
|
+
fs12.writeFileSync(outPath, buf);
|
|
37996
|
+
}
|
|
37997
|
+
function renderResult(result, outputHint, images, json2) {
|
|
37998
|
+
if (json2) return JSON.stringify(result, null, 2);
|
|
37999
|
+
if (outputHint === "image") {
|
|
38000
|
+
if (images.length > 0) return `Saved screenshot: ${images[0].localPath}`;
|
|
38001
|
+
if (result && typeof result === "object" && "path" in result && typeof result.path === "string") {
|
|
38002
|
+
return `Saved screenshot: ${result.path}`;
|
|
38003
|
+
}
|
|
38004
|
+
}
|
|
38005
|
+
if (typeof result === "string") return result;
|
|
38006
|
+
return JSON.stringify(result, null, 2);
|
|
38007
|
+
}
|
|
38008
|
+
var SAFE_TOOL_RE = /^[a-z][a-z0-9_-]{0,63}$/;
|
|
38009
|
+
function safeToolName(toolName) {
|
|
38010
|
+
return toolName && SAFE_TOOL_RE.test(toolName) ? toolName : "unknown";
|
|
38011
|
+
}
|
|
38012
|
+
async function trackRunFailure(toolName, startedAt, signal) {
|
|
38013
|
+
const tool = toolName ? canonicalToolId(toolName) : toolName;
|
|
38014
|
+
track("cli:run_fail", {
|
|
38015
|
+
tool: safeToolName(tool),
|
|
38016
|
+
...tool !== toolName ? { alias_used: true } : {},
|
|
38017
|
+
duration_ms: performance.now() - startedAt,
|
|
38018
|
+
...signal
|
|
38019
|
+
});
|
|
38020
|
+
await shutdown();
|
|
38021
|
+
}
|
|
38022
|
+
async function run(argv, options) {
|
|
38023
|
+
init("cli");
|
|
38024
|
+
const startedAt = performance.now();
|
|
38025
|
+
const { fetchTool, callTool, baseUrl } = createToolsClient({ paths: options.paths });
|
|
38026
|
+
const [toolName, ...rest] = argv;
|
|
38027
|
+
if (!toolName || toolName === "--help" || toolName === "-h") {
|
|
38028
|
+
console.log(`Usage: argent run <tool> [flags]
|
|
38029
|
+
|
|
38030
|
+
Invoke a tool exposed by the argent tool-server. Run \`argent tools\` to list
|
|
38031
|
+
available tools, or \`argent tools describe <name>\` to see one tool's flags.
|
|
38032
|
+
|
|
38033
|
+
Examples:
|
|
38034
|
+
argent run list-devices
|
|
38035
|
+
argent run gesture-tap --udid <UDID> --x 0.5 --y 0.5
|
|
38036
|
+
argent run screenshot --udid <UDID> --out ./screen.png
|
|
38037
|
+
argent run run-sequence --udid <UDID> --steps-json '[{"tool":"button","args":{"button":"home"}}]'
|
|
38038
|
+
argent run gesture-tap --args '{"udid":"<UDID>","x":0.5,"y":0.5}'
|
|
38039
|
+
|
|
38040
|
+
Exits 1 when the tool fails. Also exits 1 when the result reports that the
|
|
38041
|
+
call did not do its job: an e2e test that does not pass, an await-ui-element
|
|
38042
|
+
wait with success=false, a run-sequence that a step stopped, a debugger tool
|
|
38043
|
+
with no connection or an error, a native-devtools precheck that stopped the
|
|
38044
|
+
tool, a native-profiler-analyze with status analysis_failed, an e2e recording
|
|
38045
|
+
call that recorded nothing, or a baseline that was not written on this client.
|
|
38046
|
+
Other results exit 0, also a negative answer such as await-screen-idle's
|
|
38047
|
+
settled=false or debugger-status's not_connected.
|
|
38048
|
+
`);
|
|
38049
|
+
return;
|
|
38050
|
+
}
|
|
38051
|
+
let cliOptions;
|
|
38052
|
+
try {
|
|
38053
|
+
cliOptions = splitOptions(rest);
|
|
38054
|
+
} catch (err) {
|
|
38055
|
+
if (err instanceof FlagParseException) {
|
|
38056
|
+
console.error(`Error: ${err.message}
|
|
38057
|
+
`);
|
|
38058
|
+
console.error(`Run \`argent run ${toolName} --help\` to see this tool's flags.`);
|
|
38059
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38060
|
+
error_code: FAILURE_CODES.CLI_RUN_FLAG_PARSE_FAILED,
|
|
38061
|
+
failure_stage: "cli_run_split_options",
|
|
38062
|
+
failure_area: "cli",
|
|
38063
|
+
error_kind: "validation"
|
|
38064
|
+
});
|
|
38065
|
+
process.exit(2);
|
|
38066
|
+
}
|
|
38067
|
+
throw err;
|
|
38068
|
+
}
|
|
38069
|
+
const { json: json2, outPath, argvForFlags } = cliOptions;
|
|
38070
|
+
const meta3 = await fetchTool(toolName);
|
|
38071
|
+
if (!meta3) {
|
|
38072
|
+
console.error(`Tool "${toolName}" not found. Run \`argent tools\` to list available tools.`);
|
|
38073
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38074
|
+
error_code: FAILURE_CODES.CLI_RUN_TOOL_NOT_FOUND,
|
|
38075
|
+
failure_stage: "cli_run_fetch_tool",
|
|
38076
|
+
failure_area: "cli",
|
|
38077
|
+
error_kind: "not_found"
|
|
38078
|
+
});
|
|
38079
|
+
process.exit(1);
|
|
38080
|
+
}
|
|
38081
|
+
const schema = meta3.inputSchema;
|
|
38082
|
+
const failInvocation = async (summary, report, failure3) => {
|
|
38083
|
+
if (json2) {
|
|
38084
|
+
console.error(
|
|
38085
|
+
JSON.stringify(
|
|
38086
|
+
{
|
|
38087
|
+
error: summary,
|
|
38088
|
+
missing: report ? missingFlagNames(report, schema) : [],
|
|
38089
|
+
issues: report?.rawIssues ?? []
|
|
38090
|
+
},
|
|
38091
|
+
null,
|
|
38092
|
+
2
|
|
38093
|
+
)
|
|
38094
|
+
);
|
|
38095
|
+
} else {
|
|
38096
|
+
console.error(`Error: ${summary}
|
|
38097
|
+
`);
|
|
38098
|
+
printToolHelp(meta3);
|
|
38099
|
+
}
|
|
38100
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38101
|
+
...failure3,
|
|
38102
|
+
failure_area: "cli",
|
|
38103
|
+
error_kind: "validation"
|
|
38104
|
+
});
|
|
38105
|
+
process.exit(2);
|
|
38106
|
+
};
|
|
38107
|
+
const failValidation = (report, stage) => failInvocation(formatValidationError(report, schema), report, {
|
|
38108
|
+
error_code: FAILURE_CODES.CLI_RUN_INPUT_VALIDATION_FAILED,
|
|
38109
|
+
failure_stage: stage
|
|
38110
|
+
});
|
|
38111
|
+
let parsed;
|
|
38112
|
+
try {
|
|
38113
|
+
parsed = parseFlags(argvForFlags, schema);
|
|
38114
|
+
} catch (err) {
|
|
38115
|
+
if (err instanceof FlagParseException) {
|
|
38116
|
+
await failInvocation(err.message, null, {
|
|
38117
|
+
error_code: FAILURE_CODES.CLI_RUN_FLAG_PARSE_FAILED,
|
|
38118
|
+
failure_stage: "cli_run_parse_flags"
|
|
38119
|
+
});
|
|
38120
|
+
}
|
|
38121
|
+
throw err;
|
|
38122
|
+
}
|
|
38123
|
+
if (parsed.helpRequested) {
|
|
38124
|
+
printToolHelp(meta3);
|
|
38125
|
+
return;
|
|
38126
|
+
}
|
|
38127
|
+
if (parsed.positional.length > 0) {
|
|
38128
|
+
console.error(
|
|
38129
|
+
`Note: ignoring unused argument(s): ${parsed.positional.join(", ")}. Pass values as --flag <value> or --flag=<value>.`
|
|
38130
|
+
);
|
|
38131
|
+
}
|
|
38132
|
+
let payload = {};
|
|
38133
|
+
if (parsed.rawArgs !== null) {
|
|
38134
|
+
let rawJson = parsed.rawArgs;
|
|
38135
|
+
if (rawJson === "-") {
|
|
38136
|
+
rawJson = await readStdin();
|
|
38137
|
+
}
|
|
38138
|
+
try {
|
|
38139
|
+
const parsedRaw = JSON.parse(rawJson);
|
|
38140
|
+
if (parsedRaw === null || typeof parsedRaw !== "object" || Array.isArray(parsedRaw)) {
|
|
38141
|
+
console.error("--args must be a JSON object");
|
|
38142
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38143
|
+
error_code: FAILURE_CODES.CLI_RUN_ARGS_NOT_OBJECT,
|
|
38144
|
+
failure_stage: "cli_run_parse_raw_args",
|
|
38145
|
+
failure_area: "cli",
|
|
38146
|
+
error_kind: "validation"
|
|
38147
|
+
});
|
|
38148
|
+
process.exit(2);
|
|
38149
|
+
}
|
|
38150
|
+
payload = parsedRaw;
|
|
38151
|
+
} catch (err) {
|
|
38152
|
+
console.error(`--args is not valid JSON: ${err instanceof Error ? err.message : err}`);
|
|
38153
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38154
|
+
error_code: FAILURE_CODES.CLI_RUN_ARGS_JSON_INVALID,
|
|
38155
|
+
failure_stage: "cli_run_parse_raw_args",
|
|
38156
|
+
failure_area: "cli",
|
|
38157
|
+
error_kind: "validation"
|
|
38158
|
+
});
|
|
38159
|
+
process.exit(2);
|
|
38160
|
+
}
|
|
38161
|
+
}
|
|
38162
|
+
for (const [k, v] of Object.entries(parsed.args)) {
|
|
38163
|
+
payload[k] = v;
|
|
38164
|
+
}
|
|
38165
|
+
const missing = findMissingRequired(payload, schema);
|
|
38166
|
+
if (missing.length > 0) {
|
|
38167
|
+
await failValidation({ missing, invalid: [], rawIssues: null }, "cli_run_required_flags");
|
|
38168
|
+
}
|
|
38169
|
+
let result;
|
|
38170
|
+
let note;
|
|
38171
|
+
let failure2;
|
|
38172
|
+
let images = [];
|
|
38173
|
+
try {
|
|
38174
|
+
const resp = await callTool(toolName, payload);
|
|
38175
|
+
const { url: url2, token } = await baseUrl();
|
|
38176
|
+
const materialized = await materializeArtifacts(resp.data, {
|
|
38177
|
+
toolsUrl: url2,
|
|
38178
|
+
authToken: token,
|
|
38179
|
+
deviceId: getDeviceIdFromArgs(payload)
|
|
38180
|
+
});
|
|
38181
|
+
result = materialized.result;
|
|
38182
|
+
images = materialized.images;
|
|
38183
|
+
note = resp.note;
|
|
38184
|
+
failure2 = resp.failure;
|
|
38185
|
+
} catch (err) {
|
|
38186
|
+
const report = describeServerValidationFailure(err, payload, schema);
|
|
38187
|
+
if (report) {
|
|
38188
|
+
await failValidation(report, "cli_run_server_validation");
|
|
38189
|
+
}
|
|
38190
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
38191
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38192
|
+
error_code: FAILURE_CODES.CLI_RUN_TOOL_CALL_FAILED,
|
|
38193
|
+
failure_stage: "cli_run_call_tool",
|
|
38194
|
+
failure_area: "cli",
|
|
38195
|
+
error_kind: "unknown"
|
|
38196
|
+
});
|
|
38197
|
+
process.exit(1);
|
|
38198
|
+
}
|
|
38199
|
+
if (outPath && meta3.outputHint === "image") {
|
|
38200
|
+
try {
|
|
38201
|
+
if (images.length > 0) {
|
|
38202
|
+
fs12.mkdirSync(path18.dirname(path18.resolve(outPath)), { recursive: true });
|
|
38203
|
+
fs12.writeFileSync(outPath, images[0].data);
|
|
38204
|
+
} else if (result && typeof result === "object") {
|
|
38205
|
+
await fetchImageToFile(result, outPath);
|
|
38206
|
+
}
|
|
38207
|
+
} catch (err) {
|
|
38208
|
+
console.error(`Failed to save image: ${err instanceof Error ? err.message : err}`);
|
|
38209
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38210
|
+
error_code: FAILURE_CODES.CLI_RUN_SAVE_IMAGE_FAILED,
|
|
38211
|
+
failure_stage: "cli_run_save_image",
|
|
38212
|
+
failure_area: "cli",
|
|
38213
|
+
error_kind: "unknown"
|
|
38214
|
+
});
|
|
38215
|
+
process.exit(1);
|
|
38216
|
+
}
|
|
38217
|
+
}
|
|
38218
|
+
if (note) console.error(note);
|
|
38219
|
+
console.log(renderResult(result, meta3.outputHint, images, json2));
|
|
38220
|
+
if (outPath && meta3.outputHint === "image" && !json2) {
|
|
38221
|
+
console.log(`Wrote: ${outPath}`);
|
|
38222
|
+
}
|
|
38223
|
+
if (failure2) {
|
|
38224
|
+
await new Promise((resolve13) => process.stdout.write("", () => resolve13()));
|
|
38225
|
+
console.error(failure2);
|
|
38226
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38227
|
+
error_code: FAILURE_CODES.CLI_RUN_TOOL_RESULT_FAILED,
|
|
38228
|
+
failure_stage: "cli_run_tool_result",
|
|
38229
|
+
failure_area: "cli",
|
|
38230
|
+
error_kind: "unknown"
|
|
38231
|
+
});
|
|
38232
|
+
await exitAfterFlush(1, [process.stderr]);
|
|
38233
|
+
}
|
|
38234
|
+
}
|
|
38235
|
+
|
|
38197
38236
|
// ../argent-cli/src/tools.ts
|
|
38198
38237
|
function summarize(description, max = 80) {
|
|
38199
38238
|
if (!description) return "";
|