@swmansion/argent 0.32.1-next.8 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/assets/manifest.json +2 -2
- package/bin/argent-android-devtools-0.4.0.apk +0 -0
- package/bin/darwin/argent-macos-helper +0 -0
- package/bin/darwin/ax-service +0 -0
- package/bin/darwin/tvos-ax-service +0 -0
- package/bin/darwin/tvos-hid-daemon +0 -0
- package/bin/network-inspector/network-inspector.jar +0 -0
- package/bin/tcp/ax-service +0 -0
- package/dist/cli-cmds.mjs +530 -438
- package/dist/client.d.ts +5 -0
- package/dist/client.js +60 -9
- package/dist/installer.mjs +372 -202
- package/dist/mcp-server.mjs +156 -20
- package/dist/tool-args.generated.d.ts +87 -51
- package/dist/tool-server.cjs +39520 -34927
- package/dylibs/libArgentInjectionBootstrap.dylib +0 -0
- package/dylibs/libKeyboardPatch.dylib +0 -0
- package/dylibs/libNativeDevtoolsIos.dylib +0 -0
- package/dylibs/macos/libArgentInjectionBootstrap.dylib +0 -0
- package/dylibs/macos/libNativeDevtoolsMacos.dylib +0 -0
- package/dylibs/tcp/libArgentInjectionBootstrap.dylib +0 -0
- package/dylibs/tcp/libKeyboardPatch.dylib +0 -0
- package/dylibs/tcp/libNativeDevtoolsIos.dylib +0 -0
- package/dylibs/tvos/libArgentInjectionBootstrap.dylib +0 -0
- package/dylibs/tvos/libKeyboardPatch.dylib +0 -0
- package/dylibs/tvos/libNativeDevtoolsIos.dylib +0 -0
- package/package.json +2 -2
- package/rules/argent.md +1 -1
- package/skills/argent-create-e2e/references/e2e-yaml.md +4 -4
- package/skills/argent-create-e2e/references/reliability-and-recovery.md +3 -3
- package/skills/argent-device-interact/SKILL.md +3 -2
- package/skills/argent-device-interact/references/chromium.md +1 -1
- package/skills/argent-device-interact/references/harmonyos.md +1 -1
- package/skills/argent-ios-simulator-setup/SKILL.md +1 -1
- package/skills/argent-macos-app-interact/SKILL.md +44 -0
- package/skills/argent-macos-app-interact/references/e2e.md +6 -0
- package/skills/argent-qa-e2e/SKILL.md +1 -1
- package/skills/argent-react-native-app-workflow/SKILL.md +2 -0
- package/skills/argent-react-native-optimization/SKILL.md +2 -3
- package/skills/argent-react-native-profiler/SKILL.md +8 -8
- package/skills/argent-screenshot-diff/SKILL.md +1 -1
- package/skills/argent-test-ui-flow/SKILL.md +1 -1
- package/skills/argent-tv-interact/SKILL.md +4 -4
- package/bin/argent-android-devtools-0.3.0.apk +0 -0
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";
|
|
@@ -9481,6 +9481,11 @@ var FLAG_REGISTRY = [
|
|
|
9481
9481
|
name: "video-watermark",
|
|
9482
9482
|
description: "Overlay the argent corner watermark on recorded screen videos. On by default; turn it off with `argent disable video-watermark`.",
|
|
9483
9483
|
defaultEnabled: true
|
|
9484
|
+
},
|
|
9485
|
+
{
|
|
9486
|
+
name: "macos-apps",
|
|
9487
|
+
description: "Drive native Mac apps (AppKit, SwiftUI, react-native-macos) from inside the app. Adds the macos platform to list-devices and boot-device, and the file-panel and menu-bar tools. On by default; turn it off with `argent disable macos-apps`.",
|
|
9488
|
+
defaultEnabled: true
|
|
9484
9489
|
}
|
|
9485
9490
|
];
|
|
9486
9491
|
function getFlagDefinition(name, registry2 = FLAG_REGISTRY) {
|
|
@@ -10452,6 +10457,8 @@ var FAILURE_CODES = {
|
|
|
10452
10457
|
CLI_RUN_ARGS_JSON_INVALID: "CLI_RUN_ARGS_JSON_INVALID",
|
|
10453
10458
|
CLI_RUN_INPUT_VALIDATION_FAILED: "CLI_RUN_INPUT_VALIDATION_FAILED",
|
|
10454
10459
|
CLI_RUN_TOOL_CALL_FAILED: "CLI_RUN_TOOL_CALL_FAILED",
|
|
10460
|
+
// The result carried the tool-server's `failure` field.
|
|
10461
|
+
CLI_RUN_TOOL_RESULT_FAILED: "CLI_RUN_TOOL_RESULT_FAILED",
|
|
10455
10462
|
CLI_RUN_SAVE_IMAGE_FAILED: "CLI_RUN_SAVE_IMAGE_FAILED",
|
|
10456
10463
|
TOOL_CAPABILITY_UNSUPPORTED_OPERATION: "TOOL_CAPABILITY_UNSUPPORTED_OPERATION",
|
|
10457
10464
|
TOOL_PLATFORM_NOT_IMPLEMENTED: "TOOL_PLATFORM_NOT_IMPLEMENTED",
|
|
@@ -10467,6 +10474,7 @@ var FAILURE_CODES = {
|
|
|
10467
10474
|
INSTALL_MODE_FLAG_CONFLICT: "INSTALL_MODE_FLAG_CONFLICT",
|
|
10468
10475
|
INSTALL_FROM_TAR_PACKAGE_FAILED: "INSTALL_FROM_TAR_PACKAGE_FAILED",
|
|
10469
10476
|
INSTALL_INIT_TRIGGERED_UPDATE_FAILED: "INSTALL_INIT_TRIGGERED_UPDATE_FAILED",
|
|
10477
|
+
INSTALL_SKILLS_FAILED: "INSTALL_SKILLS_FAILED",
|
|
10470
10478
|
INSTALL_SKILLS_REFRESH_FAILED: "INSTALL_SKILLS_REFRESH_FAILED",
|
|
10471
10479
|
INSTALL_UNCLASSIFIED_FAILED: "INSTALL_UNCLASSIFIED_FAILED",
|
|
10472
10480
|
UPDATE_INSTALLED_VERSION_DETECT_FAILED: "UPDATE_INSTALLED_VERSION_DETECT_FAILED",
|
|
@@ -10663,6 +10671,8 @@ var FAILURE_CODES = {
|
|
|
10663
10671
|
REACT_PROFILER_START_FAILED: "REACT_PROFILER_START_FAILED",
|
|
10664
10672
|
REACT_PROFILER_START_VERIFY_FAILED: "REACT_PROFILER_START_VERIFY_FAILED",
|
|
10665
10673
|
REACT_PROFILER_SESSION_TORN_DOWN: "REACT_PROFILER_SESSION_TORN_DOWN",
|
|
10674
|
+
REACT_PROFILER_SESSION_TAKEN_OVER: "REACT_PROFILER_SESSION_TAKEN_OVER",
|
|
10675
|
+
REACT_PROFILER_STOP_IN_PROGRESS: "REACT_PROFILER_STOP_IN_PROGRESS",
|
|
10666
10676
|
REACT_PROFILER_HOOK_ERROR: "REACT_PROFILER_HOOK_ERROR",
|
|
10667
10677
|
REACT_PROFILER_ANALYZE_NO_DATA: "REACT_PROFILER_ANALYZE_NO_DATA",
|
|
10668
10678
|
NATIVE_PROFILER_FACTORY_OPTIONS_MISSING: "NATIVE_PROFILER_FACTORY_OPTIONS_MISSING",
|
|
@@ -10741,6 +10751,32 @@ var FAILURE_CODES = {
|
|
|
10741
10751
|
CHROMIUM_ELECTRON_SPAWN_FAILED: "CHROMIUM_ELECTRON_SPAWN_FAILED",
|
|
10742
10752
|
CHROMIUM_ELECTRON_CDP_TIMEOUT: "CHROMIUM_ELECTRON_CDP_TIMEOUT",
|
|
10743
10753
|
CHROMIUM_ELECTRON_EXITED_BEFORE_READY: "CHROMIUM_ELECTRON_EXITED_BEFORE_READY",
|
|
10754
|
+
/**
|
|
10755
|
+
* Native Mac apps (the `macos-apps` flag)
|
|
10756
|
+
* @see [macos-app.ts](../../tool-server/src/blueprints/macos-app.ts)
|
|
10757
|
+
*/
|
|
10758
|
+
MACOS_APP_UNSUPPORTED_HOST: "MACOS_APP_UNSUPPORTED_HOST",
|
|
10759
|
+
MACOS_APP_PATH_INVALID: "MACOS_APP_PATH_INVALID",
|
|
10760
|
+
MACOS_APP_BUNDLE_INVALID: "MACOS_APP_BUNDLE_INVALID",
|
|
10761
|
+
MACOS_APP_NOT_FOUND: "MACOS_APP_NOT_FOUND",
|
|
10762
|
+
MACOS_APP_HARDENED_RUNTIME: "MACOS_APP_HARDENED_RUNTIME",
|
|
10763
|
+
MACOS_APP_LIBRARY_MISSING: "MACOS_APP_LIBRARY_MISSING",
|
|
10764
|
+
MACOS_APP_LIBRARY_STAGE_FAILED: "MACOS_APP_LIBRARY_STAGE_FAILED",
|
|
10765
|
+
MACOS_APP_ALREADY_RUNNING: "MACOS_APP_ALREADY_RUNNING",
|
|
10766
|
+
MACOS_APP_SPAWN_FAILED: "MACOS_APP_SPAWN_FAILED",
|
|
10767
|
+
MACOS_APP_EXITED_BEFORE_READY: "MACOS_APP_EXITED_BEFORE_READY",
|
|
10768
|
+
MACOS_APP_HANDSHAKE_TIMEOUT: "MACOS_APP_HANDSHAKE_TIMEOUT",
|
|
10769
|
+
MACOS_APP_HANDSHAKE_INVALID: "MACOS_APP_HANDSHAKE_INVALID",
|
|
10770
|
+
MACOS_APP_NOT_RUNNING: "MACOS_APP_NOT_RUNNING",
|
|
10771
|
+
MACOS_APP_NOT_CONNECTED: "MACOS_APP_NOT_CONNECTED",
|
|
10772
|
+
MACOS_APP_CONNECTION_LOST: "MACOS_APP_CONNECTION_LOST",
|
|
10773
|
+
MACOS_APP_CONNECTION_CLOSED: "MACOS_APP_CONNECTION_CLOSED",
|
|
10774
|
+
MACOS_APP_RPC_TIMEOUT: "MACOS_APP_RPC_TIMEOUT",
|
|
10775
|
+
MACOS_APP_RPC_ERROR: "MACOS_APP_RPC_ERROR",
|
|
10776
|
+
MACOS_APP_TERMINATE_FAILED: "MACOS_APP_TERMINATE_FAILED",
|
|
10777
|
+
MACOS_APP_BUNDLE_ID_MISMATCH: "MACOS_APP_BUNDLE_ID_MISMATCH",
|
|
10778
|
+
MACOS_APP_OPEN_URL_FAILED: "MACOS_APP_OPEN_URL_FAILED",
|
|
10779
|
+
MACOS_APP_FILE_ACCESS_FAILED: "MACOS_APP_FILE_ACCESS_FAILED",
|
|
10744
10780
|
KEYBOARD_KEY_UNSUPPORTED: "KEYBOARD_KEY_UNSUPPORTED",
|
|
10745
10781
|
KEYBOARD_CHARACTER_UNSUPPORTED: "KEYBOARD_CHARACTER_UNSUPPORTED",
|
|
10746
10782
|
KEYBOARD_TEXT_AND_KEY_COMBINED: "KEYBOARD_TEXT_AND_KEY_COMBINED",
|
|
@@ -31651,7 +31687,8 @@ async function consumeToolStream(name, body, onProgress, signal) {
|
|
|
31651
31687
|
final = {
|
|
31652
31688
|
data: msg.data,
|
|
31653
31689
|
note: msg.note,
|
|
31654
|
-
...msg.profiling === true ? { profiling: true } : {}
|
|
31690
|
+
...msg.profiling === true ? { profiling: true } : {},
|
|
31691
|
+
...typeof msg.failure === "string" ? { failure: msg.failure } : {}
|
|
31655
31692
|
};
|
|
31656
31693
|
} else if (msg.event === "error") {
|
|
31657
31694
|
throw new ToolInvocationError(msg.error ?? "tool invocation failed", {
|
|
@@ -31703,7 +31740,8 @@ async function consumeToolStream(name, body, onProgress, signal) {
|
|
|
31703
31740
|
return {
|
|
31704
31741
|
data: final.data,
|
|
31705
31742
|
note: final.note,
|
|
31706
|
-
...final.profiling ? { profiling: true } : {}
|
|
31743
|
+
...final.profiling ? { profiling: true } : {},
|
|
31744
|
+
...final.failure !== void 0 ? { failure: final.failure } : {}
|
|
31707
31745
|
};
|
|
31708
31746
|
}
|
|
31709
31747
|
function errorBodyMessage(body) {
|
|
@@ -31868,6 +31906,7 @@ function createToolsClient(options = {}) {
|
|
|
31868
31906
|
}
|
|
31869
31907
|
const shadowWarning = await e2eShadowWarningFor(name, args);
|
|
31870
31908
|
const baselineDirs = [];
|
|
31909
|
+
let unwrittenBaselines2 = [];
|
|
31871
31910
|
if (meta3?.fileInputs?.length) {
|
|
31872
31911
|
if (remote) assertRequiredPresent(meta3, finalArgs);
|
|
31873
31912
|
finalArgs = await prepareFileInputs(meta3.fileInputs, finalArgs ?? {}, {
|
|
@@ -31881,8 +31920,9 @@ function createToolsClient(options = {}) {
|
|
|
31881
31920
|
signal: opts?.signal
|
|
31882
31921
|
});
|
|
31883
31922
|
}
|
|
31884
|
-
const settle2 = async (
|
|
31885
|
-
const applied = await applyClientFileDirectives(
|
|
31923
|
+
const settle2 = async (data2) => {
|
|
31924
|
+
const applied = await applyClientFileDirectives(data2, { allowedDirs: baselineDirs });
|
|
31925
|
+
unwrittenBaselines2 = applied.failed.map((f) => f.path);
|
|
31886
31926
|
for (const { path: file2, error: error63 } of applied.failed) {
|
|
31887
31927
|
diagnose(`The baseline ${file2} was not written on this client: ${error63}`);
|
|
31888
31928
|
}
|
|
@@ -31899,6 +31939,7 @@ function createToolsClient(options = {}) {
|
|
|
31899
31939
|
}
|
|
31900
31940
|
return { ...result, warning: shadowWarning };
|
|
31901
31941
|
};
|
|
31942
|
+
const unwrittenFailure = () => unwrittenBaselines2.length > 0 ? `Baselines not written on this client: ${unwrittenBaselines2.join(", ")}` : void 0;
|
|
31902
31943
|
const stream = opts?.onProgress !== void 0 || carriesMembers(finalArgs);
|
|
31903
31944
|
const sentOnce = carriesUpload(finalArgs);
|
|
31904
31945
|
const forwarded = remote ? await forwardedSecrets(finalArgs) : void 0;
|
|
@@ -31962,11 +32003,14 @@ function createToolsClient(options = {}) {
|
|
|
31962
32003
|
}),
|
|
31963
32004
|
opts?.signal
|
|
31964
32005
|
);
|
|
32006
|
+
const data2 = await settle2(streamed.data);
|
|
32007
|
+
const failure3 = streamed.failure ?? unwrittenFailure();
|
|
31965
32008
|
return {
|
|
31966
|
-
data:
|
|
32009
|
+
data: data2,
|
|
31967
32010
|
note: streamed.note,
|
|
31968
32011
|
outputHint: meta3?.outputHint,
|
|
31969
|
-
...streamed.profiling ? { profiling: true } : {}
|
|
32012
|
+
...streamed.profiling ? { profiling: true } : {},
|
|
32013
|
+
...failure3 !== void 0 ? { failure: failure3 } : {}
|
|
31970
32014
|
};
|
|
31971
32015
|
}
|
|
31972
32016
|
let json2;
|
|
@@ -32002,11 +32046,14 @@ function createToolsClient(options = {}) {
|
|
|
32002
32046
|
});
|
|
32003
32047
|
}
|
|
32004
32048
|
opts?.signal?.throwIfAborted();
|
|
32049
|
+
const data = await settle2(json2.data);
|
|
32050
|
+
const failure2 = (typeof json2.failure === "string" ? json2.failure : void 0) ?? unwrittenFailure();
|
|
32005
32051
|
return {
|
|
32006
|
-
data
|
|
32052
|
+
data,
|
|
32007
32053
|
note: json2.note,
|
|
32008
32054
|
outputHint: meta3?.outputHint,
|
|
32009
|
-
...json2.profiling === true ? { profiling: true } : {}
|
|
32055
|
+
...json2.profiling === true ? { profiling: true } : {},
|
|
32056
|
+
...failure2 !== void 0 ? { failure: failure2 } : {}
|
|
32010
32057
|
};
|
|
32011
32058
|
}
|
|
32012
32059
|
return { fetchTools, fetchTool, callTool, baseUrl };
|
|
@@ -35069,7 +35116,8 @@ var PLATFORMS = [
|
|
|
35069
35116
|
"vega",
|
|
35070
35117
|
"harmony",
|
|
35071
35118
|
"tvos",
|
|
35072
|
-
"android-tv"
|
|
35119
|
+
"android-tv",
|
|
35120
|
+
"macos"
|
|
35073
35121
|
];
|
|
35074
35122
|
var DEVICE_KINDS = [
|
|
35075
35123
|
"simulator",
|
|
@@ -35221,6 +35269,9 @@ var ALLOWED = {
|
|
|
35221
35269
|
warned_count: COUNT
|
|
35222
35270
|
},
|
|
35223
35271
|
"installation:skill_install": {
|
|
35272
|
+
source: oneOf(["pinned", "bundled"]),
|
|
35273
|
+
used_fallback: bool,
|
|
35274
|
+
fallback_reason: oneOf(["ref_missing", "unclassified"]),
|
|
35224
35275
|
method: oneOf(["default", "interactive", "manual"]),
|
|
35225
35276
|
is_online: bool,
|
|
35226
35277
|
has_offline_cache: bool,
|
|
@@ -35821,7 +35872,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
|
|
|
35821
35872
|
var SESSION_ID2 = randomUUID5();
|
|
35822
35873
|
function readCliVersion() {
|
|
35823
35874
|
if (true) {
|
|
35824
|
-
return "0.
|
|
35875
|
+
return "0.33.0";
|
|
35825
35876
|
}
|
|
35826
35877
|
return "0.0.0";
|
|
35827
35878
|
}
|
|
@@ -36760,391 +36811,116 @@ function isValidationIssue(value) {
|
|
|
36760
36811
|
return typeof issue2.code === "string" && Array.isArray(issue2.path) && typeof issue2.message === "string";
|
|
36761
36812
|
}
|
|
36762
36813
|
|
|
36763
|
-
// ../argent-cli/src/
|
|
36764
|
-
|
|
36765
|
-
|
|
36766
|
-
|
|
36767
|
-
|
|
36814
|
+
// ../argent-cli/src/e2e.ts
|
|
36815
|
+
import * as fsp from "node:fs/promises";
|
|
36816
|
+
import { constants as fsConstants2 } from "node:fs";
|
|
36817
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
36818
|
+
import * as path17 from "node:path";
|
|
36819
|
+
|
|
36820
|
+
// ../argent-cli/src/command-args.ts
|
|
36821
|
+
var UsageError = class extends Error {
|
|
36822
|
+
constructor(message) {
|
|
36823
|
+
super(message);
|
|
36824
|
+
this.name = "UsageError";
|
|
36825
|
+
}
|
|
36826
|
+
};
|
|
36827
|
+
function listChoices(choices) {
|
|
36828
|
+
const quoted = choices.map((c2) => `"${c2}"`);
|
|
36829
|
+
if (quoted.length <= 1) return quoted.join("");
|
|
36830
|
+
return `${quoted.slice(0, -1).join(", ")} or ${quoted[quoted.length - 1]}`;
|
|
36831
|
+
}
|
|
36832
|
+
function resolveName(tok, specs) {
|
|
36833
|
+
if (tok.startsWith("--")) return tok.slice(2) in specs ? tok.slice(2) : null;
|
|
36834
|
+
const short = tok.slice(1);
|
|
36835
|
+
for (const [name, spec] of Object.entries(specs)) {
|
|
36836
|
+
if (spec.alias === short) return name;
|
|
36837
|
+
}
|
|
36838
|
+
return null;
|
|
36839
|
+
}
|
|
36840
|
+
function parseCommandArgs(argv, specs) {
|
|
36841
|
+
const positionals = [];
|
|
36842
|
+
const options = {};
|
|
36768
36843
|
for (let i2 = 0; i2 < argv.length; i2++) {
|
|
36769
36844
|
const tok = argv[i2];
|
|
36770
|
-
if (tok === "--
|
|
36771
|
-
|
|
36772
|
-
|
|
36845
|
+
if (tok === "--") {
|
|
36846
|
+
positionals.push(...argv.slice(i2 + 1));
|
|
36847
|
+
break;
|
|
36773
36848
|
}
|
|
36774
|
-
if (tok === "
|
|
36775
|
-
|
|
36776
|
-
if (!v) throw new FlagParseException("--out requires a path");
|
|
36777
|
-
outPath = v;
|
|
36778
|
-
i2 += 1;
|
|
36849
|
+
if (!tok.startsWith("-") || tok === "-") {
|
|
36850
|
+
positionals.push(tok);
|
|
36779
36851
|
continue;
|
|
36780
36852
|
}
|
|
36781
|
-
|
|
36782
|
-
|
|
36853
|
+
const eq = tok.startsWith("--") ? tok.indexOf("=") : -1;
|
|
36854
|
+
const flag = eq === -1 ? tok : tok.slice(0, eq);
|
|
36855
|
+
const inlineValue = eq === -1 ? void 0 : tok.slice(eq + 1);
|
|
36856
|
+
const name = resolveName(flag, specs);
|
|
36857
|
+
if (name === null) throw new UsageError(`Unknown flag: ${tok}`);
|
|
36858
|
+
const spec = specs[name];
|
|
36859
|
+
const display = `--${name}`;
|
|
36860
|
+
if (spec.kind === "boolean") {
|
|
36861
|
+
if (inlineValue !== void 0) throw new UsageError(`${display} does not take a value`);
|
|
36862
|
+
const next = argv[i2 + 1]?.trim().toLowerCase();
|
|
36863
|
+
if (next === "true" || next === "false") {
|
|
36864
|
+
throw new UsageError(
|
|
36865
|
+
`${display} does not take a value \u2014 it is a switch; omit it to leave the option off`
|
|
36866
|
+
);
|
|
36867
|
+
}
|
|
36868
|
+
options[name] = true;
|
|
36783
36869
|
continue;
|
|
36784
36870
|
}
|
|
36785
|
-
|
|
36871
|
+
let value = inlineValue;
|
|
36872
|
+
if (value === void 0) {
|
|
36873
|
+
const next = argv[i2 + 1];
|
|
36874
|
+
if (next !== void 0 && (!next.startsWith("-") || next === "-")) {
|
|
36875
|
+
value = next;
|
|
36876
|
+
i2 += 1;
|
|
36877
|
+
}
|
|
36878
|
+
} else if (value === "") {
|
|
36879
|
+
value = void 0;
|
|
36880
|
+
}
|
|
36881
|
+
if (value === void 0) throw new UsageError(`${display} requires a value`);
|
|
36882
|
+
if (spec.choices && !spec.choices.includes(value)) {
|
|
36883
|
+
throw new UsageError(`${display} must be ${listChoices(spec.choices)}, got "${value}"`);
|
|
36884
|
+
}
|
|
36885
|
+
options[name] = value;
|
|
36786
36886
|
}
|
|
36787
|
-
return {
|
|
36788
|
-
}
|
|
36789
|
-
async function readStdin() {
|
|
36790
|
-
return new Promise((resolve13, reject) => {
|
|
36791
|
-
let data = "";
|
|
36792
|
-
process.stdin.setEncoding("utf8");
|
|
36793
|
-
process.stdin.on("data", (chunk) => {
|
|
36794
|
-
data += chunk;
|
|
36795
|
-
});
|
|
36796
|
-
process.stdin.on("end", () => resolve13(data));
|
|
36797
|
-
process.stdin.on("error", reject);
|
|
36798
|
-
});
|
|
36887
|
+
return { positionals, options };
|
|
36799
36888
|
}
|
|
36800
|
-
|
|
36801
|
-
|
|
36802
|
-
|
|
36803
|
-
|
|
36804
|
-
|
|
36805
|
-
|
|
36806
|
-
|
|
36807
|
-
|
|
36808
|
-
|
|
36809
|
-
|
|
36810
|
-
|
|
36811
|
-
|
|
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");
|
|
36889
|
+
|
|
36890
|
+
// ../argent-cli/src/e2e.ts
|
|
36891
|
+
var STATUS_GLYPH = {
|
|
36892
|
+
pass: "\u2713",
|
|
36893
|
+
fail: "\u2717",
|
|
36894
|
+
error: "\u2717",
|
|
36895
|
+
skip: "\xB7"
|
|
36896
|
+
};
|
|
36897
|
+
var MAX_RENDER_DEPTH = 20;
|
|
36898
|
+
function stepIndent(depth) {
|
|
36899
|
+
if (typeof depth !== "number" || !Number.isInteger(depth) || depth <= 0) return "";
|
|
36900
|
+
return " ".repeat(Math.min(depth, MAX_RENDER_DEPTH));
|
|
36819
36901
|
}
|
|
36820
|
-
|
|
36821
|
-
|
|
36822
|
-
|
|
36823
|
-
|
|
36824
|
-
|
|
36825
|
-
|
|
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);
|
|
36902
|
+
function durationSuffix(ms) {
|
|
36903
|
+
if (typeof ms !== "number" || !Number.isFinite(ms) || ms < 0) return "";
|
|
36904
|
+
const tenths = Math.round(ms / 100);
|
|
36905
|
+
if (tenths < 600) return ` (${(tenths / 10).toFixed(1)}s)`;
|
|
36906
|
+
const seconds = Math.round(ms / 1e3);
|
|
36907
|
+
return ` (${Math.floor(seconds / 60)}m ${seconds % 60}s)`;
|
|
36830
36908
|
}
|
|
36831
|
-
function
|
|
36832
|
-
if (
|
|
36833
|
-
if (
|
|
36834
|
-
|
|
36835
|
-
|
|
36836
|
-
|
|
36837
|
-
|
|
36909
|
+
async function offersMacosPlatform() {
|
|
36910
|
+
if (!isFeatureEnabled("macos-apps")) return false;
|
|
36911
|
+
if (process.platform === "darwin") return true;
|
|
36912
|
+
try {
|
|
36913
|
+
return (await getResolvedToolsUrl()).url !== null;
|
|
36914
|
+
} catch {
|
|
36915
|
+
return false;
|
|
36838
36916
|
}
|
|
36839
|
-
if (typeof result === "string") return result;
|
|
36840
|
-
return JSON.stringify(result, null, 2);
|
|
36841
|
-
}
|
|
36842
|
-
var SAFE_TOOL_RE = /^[a-z][a-z0-9_-]{0,63}$/;
|
|
36843
|
-
function safeToolName(toolName) {
|
|
36844
|
-
return toolName && SAFE_TOOL_RE.test(toolName) ? toolName : "unknown";
|
|
36845
|
-
}
|
|
36846
|
-
async function trackRunFailure(toolName, startedAt, signal) {
|
|
36847
|
-
const tool = toolName ? canonicalToolId(toolName) : toolName;
|
|
36848
|
-
track("cli:run_fail", {
|
|
36849
|
-
tool: safeToolName(tool),
|
|
36850
|
-
...tool !== toolName ? { alias_used: true } : {},
|
|
36851
|
-
duration_ms: performance.now() - startedAt,
|
|
36852
|
-
...signal
|
|
36853
|
-
});
|
|
36854
|
-
await shutdown();
|
|
36855
36917
|
}
|
|
36856
|
-
async function
|
|
36857
|
-
|
|
36858
|
-
const
|
|
36859
|
-
|
|
36860
|
-
const [toolName, ...rest] = argv;
|
|
36861
|
-
if (!toolName || toolName === "--help" || toolName === "-h") {
|
|
36862
|
-
console.log(`Usage: argent run <tool> [flags]
|
|
36918
|
+
async function printHelp(toStderr = false) {
|
|
36919
|
+
const print = toStderr ? console.error : console.log;
|
|
36920
|
+
const macos = await offersMacosPlatform() ? " macos |" : "";
|
|
36921
|
+
print(`Usage: argent e2e <subcommand> [options]
|
|
36863
36922
|
|
|
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:
|
|
36923
|
+
Run a YAML e2e test without an LLM in the loop. \`run\` takes any of these forms:
|
|
37148
36924
|
|
|
37149
36925
|
a name An e2e test saved under .argent/e2e or .argent/flows, resolved
|
|
37150
36926
|
from the current directory. "checkout" runs
|
|
@@ -37212,7 +36988,7 @@ Subcommands:
|
|
|
37212
36988
|
|
|
37213
36989
|
Options (run):
|
|
37214
36990
|
--device <id> Device id to run against (auto-detected when omitted)
|
|
37215
|
-
--platform <p> ios | android | chromium | vega
|
|
36991
|
+
--platform <p> ios | android | chromium | vega |${macos} ios-remote \u2014 narrow
|
|
37216
36992
|
auto-detection (ios never picks a remote simulator)
|
|
37217
36993
|
--update-baselines Write/refresh screenshot baselines instead of diffing,
|
|
37218
36994
|
also those of tests that tool: e2e-execute steps run,
|
|
@@ -37405,14 +37181,14 @@ function shellQuoteArg(arg) {
|
|
|
37405
37181
|
return `'${arg.replaceAll("'", "'\\''")}'`;
|
|
37406
37182
|
}
|
|
37407
37183
|
function rerunCommand(flowPath, rel, projectRoot, args) {
|
|
37408
|
-
const pathArg = (p) => shellQuoteArg(p.startsWith("-") ? `.${
|
|
37409
|
-
const fromCwd =
|
|
37410
|
-
const shown =
|
|
37184
|
+
const pathArg = (p) => shellQuoteArg(p.startsWith("-") ? `.${path17.sep}${p}` : p);
|
|
37185
|
+
const fromCwd = path17.relative(projectRoot, flowPath);
|
|
37186
|
+
const shown = path17.isAbsolute(fromCwd) || fromCwd.split(/[\\/]+/).includes("..") ? flowPath : fromCwd;
|
|
37411
37187
|
const parts = ["argent e2e run", pathArg(shown)];
|
|
37412
37188
|
if (args.device) parts.push("--device", shellQuoteArg(args.device));
|
|
37413
37189
|
if (args.platform) parts.push("--platform", shellQuoteArg(args.platform));
|
|
37414
37190
|
if (args.updateBaselines) parts.push("--update-baselines");
|
|
37415
|
-
if (args.output) parts.push("--output", pathArg(
|
|
37191
|
+
if (args.output) parts.push("--output", pathArg(path17.join(args.output, path17.dirname(rel))));
|
|
37416
37192
|
return parts.join(" ");
|
|
37417
37193
|
}
|
|
37418
37194
|
var EXPORT_SOURCE_MARKER = ".argent-e2e-source";
|
|
@@ -37420,8 +37196,8 @@ var LEGACY_EXPORT_SOURCE_MARKER = ".argent-flow-source";
|
|
|
37420
37196
|
var MARKER_READ_RETRIES = 4;
|
|
37421
37197
|
var MARKER_READ_DELAY_MS = 5;
|
|
37422
37198
|
async function readExportMarker(dir) {
|
|
37423
|
-
const owner = await readMarkerFile(
|
|
37424
|
-
return owner !== void 0 ? owner : await readMarkerFile(
|
|
37199
|
+
const owner = await readMarkerFile(path17.join(dir, EXPORT_SOURCE_MARKER));
|
|
37200
|
+
return owner !== void 0 ? owner : await readMarkerFile(path17.join(dir, LEGACY_EXPORT_SOURCE_MARKER));
|
|
37425
37201
|
}
|
|
37426
37202
|
async function readMarkerFile(marker) {
|
|
37427
37203
|
for (let attempt = 0; ; attempt++) {
|
|
@@ -37458,7 +37234,7 @@ function occupiedBy(owner) {
|
|
|
37458
37234
|
async function takeExportDir(dir, flowPath) {
|
|
37459
37235
|
try {
|
|
37460
37236
|
await fsp.mkdir(dir, { recursive: true });
|
|
37461
|
-
await fsp.writeFile(
|
|
37237
|
+
await fsp.writeFile(path17.join(dir, EXPORT_SOURCE_MARKER), `${flowPath}
|
|
37462
37238
|
`, { flag: "wx" });
|
|
37463
37239
|
return null;
|
|
37464
37240
|
} catch (err) {
|
|
@@ -37477,7 +37253,7 @@ async function claimExportDirName(outputDir, flowPath, stem) {
|
|
|
37477
37253
|
}
|
|
37478
37254
|
const avoided = [];
|
|
37479
37255
|
for (const name of candidates) {
|
|
37480
|
-
const dir =
|
|
37256
|
+
const dir = path17.join(outputDir, name);
|
|
37481
37257
|
const claim2 = await classifyExportDir(dir, flowPath);
|
|
37482
37258
|
const reason = claim2.state === "foreign" ? occupiedBy(claim2.owner) : await takeExportDir(dir, flowPath);
|
|
37483
37259
|
if (reason !== null) {
|
|
@@ -37497,7 +37273,7 @@ async function claimExportDirName(outputDir, flowPath, stem) {
|
|
|
37497
37273
|
return null;
|
|
37498
37274
|
}
|
|
37499
37275
|
async function exportFailureArtifacts(report, outputDir, flowPath, ctx) {
|
|
37500
|
-
const stem =
|
|
37276
|
+
const stem = path17.basename(flowPath, ".yaml");
|
|
37501
37277
|
if (!SAFE_ARTIFACT_NAME.test(stem)) {
|
|
37502
37278
|
console.error(
|
|
37503
37279
|
`warning: skipping artifact export for unsafe e2e test filename ${JSON.stringify(stem)}`
|
|
@@ -37530,11 +37306,11 @@ async function exportFailureArtifacts(report, outputDir, flowPath, ctx) {
|
|
|
37530
37306
|
if (dir === null) {
|
|
37531
37307
|
const dirName = await claimExportDirName(outputDir, flowPath, stem);
|
|
37532
37308
|
if (dirName === null) return;
|
|
37533
|
-
dir =
|
|
37309
|
+
dir = path17.join(outputDir, dirName);
|
|
37534
37310
|
}
|
|
37535
|
-
const dest =
|
|
37536
|
-
const rel =
|
|
37537
|
-
if (rel.startsWith("..") ||
|
|
37311
|
+
const dest = path17.join(dir, fileName(role));
|
|
37312
|
+
const rel = path17.relative(outputDir, dest);
|
|
37313
|
+
if (rel.startsWith("..") || path17.isAbsolute(rel)) continue;
|
|
37538
37314
|
try {
|
|
37539
37315
|
await fsp.copyFile(value, dest);
|
|
37540
37316
|
s.artifacts[role] = dest;
|
|
@@ -37549,7 +37325,7 @@ async function exportFailureArtifacts(report, outputDir, flowPath, ctx) {
|
|
|
37549
37325
|
function keyFromBaselinePath(artifacts) {
|
|
37550
37326
|
const baseline = artifacts.baseline;
|
|
37551
37327
|
if (typeof baseline !== "string") return null;
|
|
37552
|
-
return
|
|
37328
|
+
return path17.basename(baseline).replace(/\.png$/, "");
|
|
37553
37329
|
}
|
|
37554
37330
|
function resolveArtifactDisplayPaths(report) {
|
|
37555
37331
|
for (const s of report.steps) {
|
|
@@ -37606,17 +37382,17 @@ async function collectRunnableFlowPaths(dir, relDir = "") {
|
|
|
37606
37382
|
const found = [];
|
|
37607
37383
|
const entries = await fsp.readdir(dir, { withFileTypes: true });
|
|
37608
37384
|
for (const entry of entries) {
|
|
37609
|
-
const rel = relDir ?
|
|
37385
|
+
const rel = relDir ? path17.join(relDir, entry.name) : entry.name;
|
|
37610
37386
|
if (entry.isDirectory()) {
|
|
37611
37387
|
if (entry.name === "__baselines__") continue;
|
|
37612
37388
|
found.push(
|
|
37613
|
-
...await collectRunnableFlowPaths(
|
|
37389
|
+
...await collectRunnableFlowPaths(path17.join(dir, entry.name), rel).catch(() => [])
|
|
37614
37390
|
);
|
|
37615
37391
|
continue;
|
|
37616
37392
|
}
|
|
37617
37393
|
if (!entry.name.endsWith(".yaml")) continue;
|
|
37618
|
-
if (!SAFE_FLOW_NAME.test(
|
|
37619
|
-
if (await isRunnableFlowFile(
|
|
37394
|
+
if (!SAFE_FLOW_NAME.test(path17.basename(entry.name, ".yaml"))) continue;
|
|
37395
|
+
if (await isRunnableFlowFile(path17.join(dir, entry.name))) found.push(rel);
|
|
37620
37396
|
}
|
|
37621
37397
|
return found;
|
|
37622
37398
|
}
|
|
@@ -37624,26 +37400,26 @@ async function resolveFlowRef(ref, projectRoot) {
|
|
|
37624
37400
|
if (!SAFE_FLOW_NAME.test(ref)) return { suppliedPath: ref, fromName: false };
|
|
37625
37401
|
const picked = await resolveE2eFile(projectRoot, ref);
|
|
37626
37402
|
return {
|
|
37627
|
-
suppliedPath:
|
|
37403
|
+
suppliedPath: path17.relative(projectRoot, picked.path),
|
|
37628
37404
|
fromName: true,
|
|
37629
|
-
...picked.shadowed === void 0 ? {} : { shadowed:
|
|
37405
|
+
...picked.shadowed === void 0 ? {} : { shadowed: path17.relative(projectRoot, picked.shadowed) }
|
|
37630
37406
|
};
|
|
37631
37407
|
}
|
|
37632
37408
|
async function savedFlowHint(projectRoot, missingPath) {
|
|
37633
|
-
const dirs = E2E_DIRS.map((rel) => ({ rel, abs:
|
|
37409
|
+
const dirs = E2E_DIRS.map((rel) => ({ rel, abs: path17.resolve(projectRoot, rel) }));
|
|
37634
37410
|
for (const { abs } of dirs) {
|
|
37635
|
-
const within =
|
|
37636
|
-
if (!within.startsWith("..") && !
|
|
37411
|
+
const within = path17.relative(abs, missingPath);
|
|
37412
|
+
if (!within.startsWith("..") && !path17.isAbsolute(within)) return "";
|
|
37637
37413
|
}
|
|
37638
|
-
const wanted = `${
|
|
37414
|
+
const wanted = `${path17.basename(missingPath, ".yaml")}.yaml`;
|
|
37639
37415
|
for (const { rel, abs } of dirs) {
|
|
37640
37416
|
const entries = await fsp.readdir(abs).catch(() => null);
|
|
37641
37417
|
if (entries === null) continue;
|
|
37642
37418
|
const actual = entries.includes(wanted) ? wanted : entries.find((name2) => name2.toLowerCase() === wanted.toLowerCase());
|
|
37643
37419
|
if (actual === void 0) continue;
|
|
37644
|
-
const name =
|
|
37420
|
+
const name = path17.basename(actual, ".yaml");
|
|
37645
37421
|
if (!SAFE_FLOW_NAME.test(name)) return "";
|
|
37646
|
-
if (!await isRunnableFlowFile(
|
|
37422
|
+
if (!await isRunnableFlowFile(path17.join(abs, actual))) return "";
|
|
37647
37423
|
return `
|
|
37648
37424
|
An e2e test named "${name}" is saved under ${rel} \u2014 did you mean: argent e2e run ${name}`;
|
|
37649
37425
|
}
|
|
@@ -37653,17 +37429,17 @@ async function collectFlowFiles(dir, recursive2) {
|
|
|
37653
37429
|
const found = [];
|
|
37654
37430
|
const walk = async (current, rel) => {
|
|
37655
37431
|
for (const entry of await fsp.readdir(current, { withFileTypes: true })) {
|
|
37656
|
-
const entryRel = rel ?
|
|
37432
|
+
const entryRel = rel ? path17.join(rel, entry.name) : entry.name;
|
|
37657
37433
|
if (entry.isDirectory()) {
|
|
37658
37434
|
if (recursive2 && !entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
37659
|
-
await walk(
|
|
37435
|
+
await walk(path17.join(current, entry.name), entryRel).catch(() => {
|
|
37660
37436
|
});
|
|
37661
37437
|
}
|
|
37662
37438
|
continue;
|
|
37663
37439
|
}
|
|
37664
37440
|
if (!entry.name.endsWith(".yaml")) continue;
|
|
37665
|
-
if (!SAFE_FLOW_NAME.test(
|
|
37666
|
-
if (await isRunnableFlowFile(
|
|
37441
|
+
if (!SAFE_FLOW_NAME.test(path17.basename(entry.name, ".yaml"))) continue;
|
|
37442
|
+
if (await isRunnableFlowFile(path17.join(current, entry.name))) found.push(entryRel);
|
|
37667
37443
|
}
|
|
37668
37444
|
};
|
|
37669
37445
|
await walk(dir, "");
|
|
@@ -37810,7 +37586,7 @@ async function runFlowDirectory(dir, args, projectRoot, options) {
|
|
|
37810
37586
|
);
|
|
37811
37587
|
}
|
|
37812
37588
|
const { callTool, baseUrl } = runToolsClient(args, options);
|
|
37813
|
-
const outputBase = args.output ?
|
|
37589
|
+
const outputBase = args.output ? path17.resolve(args.output) : void 0;
|
|
37814
37590
|
const results = [];
|
|
37815
37591
|
const failures = [];
|
|
37816
37592
|
const batchStartedAt = Date.now();
|
|
@@ -37823,7 +37599,7 @@ async function runFlowDirectory(dir, args, projectRoot, options) {
|
|
|
37823
37599
|
if (!args.json) console.log(` ${STATUS_GLYPH.skip} not run (batch stopped)`);
|
|
37824
37600
|
continue;
|
|
37825
37601
|
}
|
|
37826
|
-
const flowPath =
|
|
37602
|
+
const flowPath = path17.join(dir, rel);
|
|
37827
37603
|
const rerun = rerunCommand(flowPath, rel, projectRoot, args);
|
|
37828
37604
|
let report;
|
|
37829
37605
|
try {
|
|
@@ -37865,7 +37641,7 @@ async function runFlowDirectory(dir, args, projectRoot, options) {
|
|
|
37865
37641
|
printWarnings(nestedStepWarnings(report.steps), args.json);
|
|
37866
37642
|
await exportAndResolveArtifacts(
|
|
37867
37643
|
report,
|
|
37868
|
-
outputBase ?
|
|
37644
|
+
outputBase ? path17.join(outputBase, path17.dirname(rel)) : void 0,
|
|
37869
37645
|
flowPath,
|
|
37870
37646
|
baseUrl
|
|
37871
37647
|
);
|
|
@@ -37919,7 +37695,7 @@ ${renderBatchSummary(counts, durationMs)}`);
|
|
|
37919
37695
|
async function e2e(argv, options) {
|
|
37920
37696
|
const [sub, ...rest] = argv;
|
|
37921
37697
|
if (!sub || sub === "--help" || sub === "-h") {
|
|
37922
|
-
printHelp();
|
|
37698
|
+
await printHelp();
|
|
37923
37699
|
return;
|
|
37924
37700
|
}
|
|
37925
37701
|
if (sub === "list") {
|
|
@@ -37931,14 +37707,14 @@ async function e2e(argv, options) {
|
|
|
37931
37707
|
for (const dir of E2E_DIRS) {
|
|
37932
37708
|
let rels;
|
|
37933
37709
|
try {
|
|
37934
|
-
rels = (await collectRunnableFlowPaths(
|
|
37710
|
+
rels = (await collectRunnableFlowPaths(path17.join(process.cwd(), dir))).sort();
|
|
37935
37711
|
} catch {
|
|
37936
37712
|
continue;
|
|
37937
37713
|
}
|
|
37938
37714
|
anyDir = true;
|
|
37939
37715
|
for (const rel of rels) {
|
|
37940
|
-
const shown =
|
|
37941
|
-
const name =
|
|
37716
|
+
const shown = path17.join(dir, rel);
|
|
37717
|
+
const name = path17.dirname(rel) === "." ? path17.basename(rel, ".yaml") : void 0;
|
|
37942
37718
|
const usedByName = name === void 0 ? void 0 : byName.get(name);
|
|
37943
37719
|
if (name !== void 0 && usedByName === void 0) byName.set(name, shown);
|
|
37944
37720
|
lines.push(shown);
|
|
@@ -37970,17 +37746,17 @@ async function e2e(argv, options) {
|
|
|
37970
37746
|
const jsonStream = flagGiven("--json-stream");
|
|
37971
37747
|
const json2 = !jsonStream && flagGiven("--json");
|
|
37972
37748
|
if (rest.includes("--help") || rest.includes("-h")) {
|
|
37973
|
-
printHelp(jsonStream);
|
|
37749
|
+
await printHelp(jsonStream);
|
|
37974
37750
|
return;
|
|
37975
37751
|
}
|
|
37976
|
-
const usageError = (message, prose) => {
|
|
37752
|
+
const usageError = async (message, prose) => {
|
|
37977
37753
|
if (json2) {
|
|
37978
37754
|
console.error(JSON.stringify(errorRecord(message)));
|
|
37979
37755
|
return exitAfterFlush(2);
|
|
37980
37756
|
}
|
|
37981
37757
|
if (jsonStream) writeJsonStreamError(message);
|
|
37982
37758
|
console.error(prose);
|
|
37983
|
-
printHelp(jsonStream);
|
|
37759
|
+
await printHelp(jsonStream);
|
|
37984
37760
|
return exitAfterFlush(2);
|
|
37985
37761
|
};
|
|
37986
37762
|
let args;
|
|
@@ -38009,10 +37785,10 @@ async function e2e(argv, options) {
|
|
|
38009
37785
|
}
|
|
38010
37786
|
if (suppliedPath.split(/[\\/]+/).includes("..")) {
|
|
38011
37787
|
let recovery = "Pass the fully resolved path to the e2e test's YAML.";
|
|
38012
|
-
const suppliedBase2 =
|
|
37788
|
+
const suppliedBase2 = path17.basename(suppliedPath);
|
|
38013
37789
|
if (suppliedBase2 !== ".." && suppliedBase2 !== ".") {
|
|
38014
37790
|
try {
|
|
38015
|
-
const resolved =
|
|
37791
|
+
const resolved = path17.join(await fsp.realpath(path17.dirname(suppliedPath)), suppliedBase2);
|
|
38016
37792
|
await fsp.stat(resolved);
|
|
38017
37793
|
recovery = `Did you mean: argent e2e run ${shellQuoteArg(resolved)}`;
|
|
38018
37794
|
} catch {
|
|
@@ -38024,7 +37800,7 @@ async function e2e(argv, options) {
|
|
|
38024
37800
|
2
|
|
38025
37801
|
);
|
|
38026
37802
|
}
|
|
38027
|
-
const resolvedPath =
|
|
37803
|
+
const resolvedPath = path17.resolve(projectRoot, suppliedPath);
|
|
38028
37804
|
let isDirectory = false;
|
|
38029
37805
|
try {
|
|
38030
37806
|
isDirectory = (await fsp.stat(resolvedPath)).isDirectory();
|
|
@@ -38047,16 +37823,16 @@ async function e2e(argv, options) {
|
|
|
38047
37823
|
}
|
|
38048
37824
|
const separatorTrimmedPath = suppliedPath.replace(/[\\/]+$/, "");
|
|
38049
37825
|
if (separatorTrimmedPath !== suppliedPath && separatorTrimmedPath !== "") {
|
|
38050
|
-
const hint = SAFE_FLOW_NAME.test(separatorTrimmedPath) ? `.${
|
|
37826
|
+
const hint = SAFE_FLOW_NAME.test(separatorTrimmedPath) ? `.${path17.sep}${separatorTrimmedPath}` : separatorTrimmedPath;
|
|
38051
37827
|
return fail(
|
|
38052
37828
|
`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
37829
|
Did you mean: argent e2e run ${shellQuoteArg(hint)}`,
|
|
38054
37830
|
2
|
|
38055
37831
|
);
|
|
38056
37832
|
}
|
|
38057
|
-
if (
|
|
38058
|
-
const looksLikeName = !suppliedPath.includes("/") && !suppliedPath.includes("\\") &&
|
|
38059
|
-
if (
|
|
37833
|
+
if (path17.extname(suppliedPath) !== ".yaml") {
|
|
37834
|
+
const looksLikeName = !suppliedPath.includes("/") && !suppliedPath.includes("\\") && path17.extname(suppliedPath) === "";
|
|
37835
|
+
if (path17.basename(suppliedPath).toLowerCase() === ".yaml") {
|
|
38060
37836
|
return fail(
|
|
38061
37837
|
`E2E test filename must have a non-empty name containing only letters, numbers, "_", or "-": ${suppliedPath}`,
|
|
38062
37838
|
2
|
|
@@ -38069,15 +37845,15 @@ Names run \`${E2E_DIRS.map((dir) => `${dir}/<name>.yaml`).join("` or `")}\`; pas
|
|
|
38069
37845
|
2
|
|
38070
37846
|
);
|
|
38071
37847
|
}
|
|
38072
|
-
if (
|
|
37848
|
+
if (path17.extname(suppliedPath).toLowerCase() === ".yaml") {
|
|
38073
37849
|
return fail(
|
|
38074
|
-
`E2E test extension must be lowercase .yaml, not ${
|
|
37850
|
+
`E2E test extension must be lowercase .yaml, not ${path17.extname(suppliedPath)}: ${suppliedPath}`,
|
|
38075
37851
|
2
|
|
38076
37852
|
);
|
|
38077
37853
|
}
|
|
38078
37854
|
return fail(`E2E test path must end in .yaml: ${suppliedPath}`, 2);
|
|
38079
37855
|
}
|
|
38080
|
-
const flowName =
|
|
37856
|
+
const flowName = path17.basename(suppliedPath, ".yaml");
|
|
38081
37857
|
if (!SAFE_FLOW_NAME.test(flowName)) {
|
|
38082
37858
|
return fail(
|
|
38083
37859
|
`E2E test filename must have a non-empty name containing only letters, numbers, "_", or "-": ${suppliedPath}`,
|
|
@@ -38101,12 +37877,12 @@ No e2e test named "${args.flowRef}" is saved in ${E2E_DIRS.join(" or ")} \u2014
|
|
|
38101
37877
|
}
|
|
38102
37878
|
return fail(`${detail}: ${flowPath}${recovery}`, 2);
|
|
38103
37879
|
}
|
|
38104
|
-
const suppliedBase =
|
|
38105
|
-
const siblings = await fsp.readdir(
|
|
37880
|
+
const suppliedBase = path17.basename(flowPath);
|
|
37881
|
+
const siblings = await fsp.readdir(path17.dirname(flowPath)).catch(() => null);
|
|
38106
37882
|
if (siblings !== null && !siblings.includes(suppliedBase)) {
|
|
38107
37883
|
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 ${
|
|
37884
|
+
const actualRunnable = actual !== void 0 && path17.extname(actual) === ".yaml" && SAFE_FLOW_NAME.test(path17.basename(actual, ".yaml"));
|
|
37885
|
+
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
37886
|
return fail(
|
|
38111
37887
|
`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
37888
|
${recovery}`,
|
|
@@ -38165,7 +37941,7 @@ ${recovery}`,
|
|
|
38165
37941
|
try {
|
|
38166
37942
|
await exportAndResolveArtifacts(
|
|
38167
37943
|
report,
|
|
38168
|
-
args.output ?
|
|
37944
|
+
args.output ? path17.resolve(args.output) : void 0,
|
|
38169
37945
|
flowPath,
|
|
38170
37946
|
baseUrl
|
|
38171
37947
|
);
|
|
@@ -38194,6 +37970,313 @@ ${renderSummary(report, { withDevice: true })}`);
|
|
|
38194
37970
|
return exitAfterFlush(report.ok && unwritten.length === 0 ? 0 : 1);
|
|
38195
37971
|
}
|
|
38196
37972
|
|
|
37973
|
+
// ../argent-cli/src/run.ts
|
|
37974
|
+
function splitOptions(argv) {
|
|
37975
|
+
let json2 = false;
|
|
37976
|
+
let outPath = null;
|
|
37977
|
+
const rest = [];
|
|
37978
|
+
for (let i2 = 0; i2 < argv.length; i2++) {
|
|
37979
|
+
const tok = argv[i2];
|
|
37980
|
+
if (tok === "--json") {
|
|
37981
|
+
json2 = true;
|
|
37982
|
+
continue;
|
|
37983
|
+
}
|
|
37984
|
+
if (tok === "--out") {
|
|
37985
|
+
const v = argv[i2 + 1];
|
|
37986
|
+
if (!v) throw new FlagParseException("--out requires a path");
|
|
37987
|
+
outPath = v;
|
|
37988
|
+
i2 += 1;
|
|
37989
|
+
continue;
|
|
37990
|
+
}
|
|
37991
|
+
if (tok.startsWith("--out=")) {
|
|
37992
|
+
outPath = tok.slice("--out=".length);
|
|
37993
|
+
continue;
|
|
37994
|
+
}
|
|
37995
|
+
rest.push(tok);
|
|
37996
|
+
}
|
|
37997
|
+
return { json: json2, outPath, argvForFlags: rest };
|
|
37998
|
+
}
|
|
37999
|
+
async function readStdin() {
|
|
38000
|
+
return new Promise((resolve13, reject) => {
|
|
38001
|
+
let data = "";
|
|
38002
|
+
process.stdin.setEncoding("utf8");
|
|
38003
|
+
process.stdin.on("data", (chunk) => {
|
|
38004
|
+
data += chunk;
|
|
38005
|
+
});
|
|
38006
|
+
process.stdin.on("end", () => resolve13(data));
|
|
38007
|
+
process.stdin.on("error", reject);
|
|
38008
|
+
});
|
|
38009
|
+
}
|
|
38010
|
+
function printToolHelp(meta3) {
|
|
38011
|
+
const description = meta3.description?.trim() ?? "";
|
|
38012
|
+
const schema = meta3.inputSchema;
|
|
38013
|
+
const hasOwnArgsField = schema?.properties?.args !== void 0;
|
|
38014
|
+
console.log(`argent run ${meta3.name} [flags]`);
|
|
38015
|
+
if (description) console.log(`
|
|
38016
|
+
${description}
|
|
38017
|
+
`);
|
|
38018
|
+
console.log("Flags:");
|
|
38019
|
+
console.log(formatSchemaUsage(schema));
|
|
38020
|
+
console.log("\nGlobal flags:");
|
|
38021
|
+
if (!hasOwnArgsField) {
|
|
38022
|
+
console.log(" --args <json> Pass the entire payload as JSON (overrides flags)");
|
|
38023
|
+
console.log(" --args - Read the entire payload as JSON from stdin");
|
|
38024
|
+
}
|
|
38025
|
+
console.log(" --<field>-json <json> Pass a single field as JSON (objects/nested arrays)");
|
|
38026
|
+
console.log(" --json Print the raw JSON result");
|
|
38027
|
+
console.log(" --out <path> For image results, save to <path> instead of fetching URL");
|
|
38028
|
+
console.log(" --help, -h Show this help");
|
|
38029
|
+
}
|
|
38030
|
+
async function fetchImageToFile(result, outPath) {
|
|
38031
|
+
const url2 = result.url;
|
|
38032
|
+
if (!url2) {
|
|
38033
|
+
throw new Error("Tool result did not include a `url`; cannot save image");
|
|
38034
|
+
}
|
|
38035
|
+
const res = await fetch(url2);
|
|
38036
|
+
if (!res.ok) throw new Error(`Failed to download image: ${res.status} ${res.statusText}`);
|
|
38037
|
+
const buf = Buffer.from(await res.arrayBuffer());
|
|
38038
|
+
fs12.mkdirSync(path18.dirname(path18.resolve(outPath)), { recursive: true });
|
|
38039
|
+
fs12.writeFileSync(outPath, buf);
|
|
38040
|
+
}
|
|
38041
|
+
function renderResult(result, outputHint, images, json2) {
|
|
38042
|
+
if (json2) return JSON.stringify(result, null, 2);
|
|
38043
|
+
if (outputHint === "image") {
|
|
38044
|
+
if (images.length > 0) return `Saved screenshot: ${images[0].localPath}`;
|
|
38045
|
+
if (result && typeof result === "object" && "path" in result && typeof result.path === "string") {
|
|
38046
|
+
return `Saved screenshot: ${result.path}`;
|
|
38047
|
+
}
|
|
38048
|
+
}
|
|
38049
|
+
if (typeof result === "string") return result;
|
|
38050
|
+
return JSON.stringify(result, null, 2);
|
|
38051
|
+
}
|
|
38052
|
+
var SAFE_TOOL_RE = /^[a-z][a-z0-9_-]{0,63}$/;
|
|
38053
|
+
function safeToolName(toolName) {
|
|
38054
|
+
return toolName && SAFE_TOOL_RE.test(toolName) ? toolName : "unknown";
|
|
38055
|
+
}
|
|
38056
|
+
async function trackRunFailure(toolName, startedAt, signal) {
|
|
38057
|
+
const tool = toolName ? canonicalToolId(toolName) : toolName;
|
|
38058
|
+
track("cli:run_fail", {
|
|
38059
|
+
tool: safeToolName(tool),
|
|
38060
|
+
...tool !== toolName ? { alias_used: true } : {},
|
|
38061
|
+
duration_ms: performance.now() - startedAt,
|
|
38062
|
+
...signal
|
|
38063
|
+
});
|
|
38064
|
+
await shutdown();
|
|
38065
|
+
}
|
|
38066
|
+
async function run(argv, options) {
|
|
38067
|
+
init("cli");
|
|
38068
|
+
const startedAt = performance.now();
|
|
38069
|
+
const { fetchTool, callTool, baseUrl } = createToolsClient({ paths: options.paths });
|
|
38070
|
+
const [toolName, ...rest] = argv;
|
|
38071
|
+
if (!toolName || toolName === "--help" || toolName === "-h") {
|
|
38072
|
+
console.log(`Usage: argent run <tool> [flags]
|
|
38073
|
+
|
|
38074
|
+
Invoke a tool exposed by the argent tool-server. Run \`argent tools\` to list
|
|
38075
|
+
available tools, or \`argent tools describe <name>\` to see one tool's flags.
|
|
38076
|
+
|
|
38077
|
+
Examples:
|
|
38078
|
+
argent run list-devices
|
|
38079
|
+
argent run gesture-tap --udid <UDID> --x 0.5 --y 0.5
|
|
38080
|
+
argent run screenshot --udid <UDID> --out ./screen.png
|
|
38081
|
+
argent run run-sequence --udid <UDID> --steps-json '[{"tool":"button","args":{"button":"home"}}]'
|
|
38082
|
+
argent run gesture-tap --args '{"udid":"<UDID>","x":0.5,"y":0.5}'
|
|
38083
|
+
|
|
38084
|
+
Exits 1 when the tool fails. Also exits 1 when the result reports that the
|
|
38085
|
+
call did not do its job: an e2e test that does not pass, an await-ui-element
|
|
38086
|
+
wait with success=false, a run-sequence that a step stopped, a debugger tool
|
|
38087
|
+
with no connection or an error, a native-devtools precheck that stopped the
|
|
38088
|
+
tool, a native-profiler-analyze with status analysis_failed, an e2e recording
|
|
38089
|
+
call that recorded nothing, or a baseline that was not written on this client.
|
|
38090
|
+
Other results exit 0, also a negative answer such as await-screen-idle's
|
|
38091
|
+
settled=false or debugger-status's not_connected.
|
|
38092
|
+
`);
|
|
38093
|
+
return;
|
|
38094
|
+
}
|
|
38095
|
+
let cliOptions;
|
|
38096
|
+
try {
|
|
38097
|
+
cliOptions = splitOptions(rest);
|
|
38098
|
+
} catch (err) {
|
|
38099
|
+
if (err instanceof FlagParseException) {
|
|
38100
|
+
console.error(`Error: ${err.message}
|
|
38101
|
+
`);
|
|
38102
|
+
console.error(`Run \`argent run ${toolName} --help\` to see this tool's flags.`);
|
|
38103
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38104
|
+
error_code: FAILURE_CODES.CLI_RUN_FLAG_PARSE_FAILED,
|
|
38105
|
+
failure_stage: "cli_run_split_options",
|
|
38106
|
+
failure_area: "cli",
|
|
38107
|
+
error_kind: "validation"
|
|
38108
|
+
});
|
|
38109
|
+
process.exit(2);
|
|
38110
|
+
}
|
|
38111
|
+
throw err;
|
|
38112
|
+
}
|
|
38113
|
+
const { json: json2, outPath, argvForFlags } = cliOptions;
|
|
38114
|
+
const meta3 = await fetchTool(toolName);
|
|
38115
|
+
if (!meta3) {
|
|
38116
|
+
console.error(`Tool "${toolName}" not found. Run \`argent tools\` to list available tools.`);
|
|
38117
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38118
|
+
error_code: FAILURE_CODES.CLI_RUN_TOOL_NOT_FOUND,
|
|
38119
|
+
failure_stage: "cli_run_fetch_tool",
|
|
38120
|
+
failure_area: "cli",
|
|
38121
|
+
error_kind: "not_found"
|
|
38122
|
+
});
|
|
38123
|
+
process.exit(1);
|
|
38124
|
+
}
|
|
38125
|
+
const schema = meta3.inputSchema;
|
|
38126
|
+
const failInvocation = async (summary, report, failure3) => {
|
|
38127
|
+
if (json2) {
|
|
38128
|
+
console.error(
|
|
38129
|
+
JSON.stringify(
|
|
38130
|
+
{
|
|
38131
|
+
error: summary,
|
|
38132
|
+
missing: report ? missingFlagNames(report, schema) : [],
|
|
38133
|
+
issues: report?.rawIssues ?? []
|
|
38134
|
+
},
|
|
38135
|
+
null,
|
|
38136
|
+
2
|
|
38137
|
+
)
|
|
38138
|
+
);
|
|
38139
|
+
} else {
|
|
38140
|
+
console.error(`Error: ${summary}
|
|
38141
|
+
`);
|
|
38142
|
+
printToolHelp(meta3);
|
|
38143
|
+
}
|
|
38144
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38145
|
+
...failure3,
|
|
38146
|
+
failure_area: "cli",
|
|
38147
|
+
error_kind: "validation"
|
|
38148
|
+
});
|
|
38149
|
+
process.exit(2);
|
|
38150
|
+
};
|
|
38151
|
+
const failValidation = (report, stage) => failInvocation(formatValidationError(report, schema), report, {
|
|
38152
|
+
error_code: FAILURE_CODES.CLI_RUN_INPUT_VALIDATION_FAILED,
|
|
38153
|
+
failure_stage: stage
|
|
38154
|
+
});
|
|
38155
|
+
let parsed;
|
|
38156
|
+
try {
|
|
38157
|
+
parsed = parseFlags(argvForFlags, schema);
|
|
38158
|
+
} catch (err) {
|
|
38159
|
+
if (err instanceof FlagParseException) {
|
|
38160
|
+
await failInvocation(err.message, null, {
|
|
38161
|
+
error_code: FAILURE_CODES.CLI_RUN_FLAG_PARSE_FAILED,
|
|
38162
|
+
failure_stage: "cli_run_parse_flags"
|
|
38163
|
+
});
|
|
38164
|
+
}
|
|
38165
|
+
throw err;
|
|
38166
|
+
}
|
|
38167
|
+
if (parsed.helpRequested) {
|
|
38168
|
+
printToolHelp(meta3);
|
|
38169
|
+
return;
|
|
38170
|
+
}
|
|
38171
|
+
if (parsed.positional.length > 0) {
|
|
38172
|
+
console.error(
|
|
38173
|
+
`Note: ignoring unused argument(s): ${parsed.positional.join(", ")}. Pass values as --flag <value> or --flag=<value>.`
|
|
38174
|
+
);
|
|
38175
|
+
}
|
|
38176
|
+
let payload = {};
|
|
38177
|
+
if (parsed.rawArgs !== null) {
|
|
38178
|
+
let rawJson = parsed.rawArgs;
|
|
38179
|
+
if (rawJson === "-") {
|
|
38180
|
+
rawJson = await readStdin();
|
|
38181
|
+
}
|
|
38182
|
+
try {
|
|
38183
|
+
const parsedRaw = JSON.parse(rawJson);
|
|
38184
|
+
if (parsedRaw === null || typeof parsedRaw !== "object" || Array.isArray(parsedRaw)) {
|
|
38185
|
+
console.error("--args must be a JSON object");
|
|
38186
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38187
|
+
error_code: FAILURE_CODES.CLI_RUN_ARGS_NOT_OBJECT,
|
|
38188
|
+
failure_stage: "cli_run_parse_raw_args",
|
|
38189
|
+
failure_area: "cli",
|
|
38190
|
+
error_kind: "validation"
|
|
38191
|
+
});
|
|
38192
|
+
process.exit(2);
|
|
38193
|
+
}
|
|
38194
|
+
payload = parsedRaw;
|
|
38195
|
+
} catch (err) {
|
|
38196
|
+
console.error(`--args is not valid JSON: ${err instanceof Error ? err.message : err}`);
|
|
38197
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38198
|
+
error_code: FAILURE_CODES.CLI_RUN_ARGS_JSON_INVALID,
|
|
38199
|
+
failure_stage: "cli_run_parse_raw_args",
|
|
38200
|
+
failure_area: "cli",
|
|
38201
|
+
error_kind: "validation"
|
|
38202
|
+
});
|
|
38203
|
+
process.exit(2);
|
|
38204
|
+
}
|
|
38205
|
+
}
|
|
38206
|
+
for (const [k, v] of Object.entries(parsed.args)) {
|
|
38207
|
+
payload[k] = v;
|
|
38208
|
+
}
|
|
38209
|
+
const missing = findMissingRequired(payload, schema);
|
|
38210
|
+
if (missing.length > 0) {
|
|
38211
|
+
await failValidation({ missing, invalid: [], rawIssues: null }, "cli_run_required_flags");
|
|
38212
|
+
}
|
|
38213
|
+
let result;
|
|
38214
|
+
let note;
|
|
38215
|
+
let failure2;
|
|
38216
|
+
let images = [];
|
|
38217
|
+
try {
|
|
38218
|
+
const resp = await callTool(toolName, payload);
|
|
38219
|
+
const { url: url2, token } = await baseUrl();
|
|
38220
|
+
const materialized = await materializeArtifacts(resp.data, {
|
|
38221
|
+
toolsUrl: url2,
|
|
38222
|
+
authToken: token,
|
|
38223
|
+
deviceId: getDeviceIdFromArgs(payload)
|
|
38224
|
+
});
|
|
38225
|
+
result = materialized.result;
|
|
38226
|
+
images = materialized.images;
|
|
38227
|
+
note = resp.note;
|
|
38228
|
+
failure2 = resp.failure;
|
|
38229
|
+
} catch (err) {
|
|
38230
|
+
const report = describeServerValidationFailure(err, payload, schema);
|
|
38231
|
+
if (report) {
|
|
38232
|
+
await failValidation(report, "cli_run_server_validation");
|
|
38233
|
+
}
|
|
38234
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
38235
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38236
|
+
error_code: FAILURE_CODES.CLI_RUN_TOOL_CALL_FAILED,
|
|
38237
|
+
failure_stage: "cli_run_call_tool",
|
|
38238
|
+
failure_area: "cli",
|
|
38239
|
+
error_kind: "unknown"
|
|
38240
|
+
});
|
|
38241
|
+
process.exit(1);
|
|
38242
|
+
}
|
|
38243
|
+
if (outPath && meta3.outputHint === "image") {
|
|
38244
|
+
try {
|
|
38245
|
+
if (images.length > 0) {
|
|
38246
|
+
fs12.mkdirSync(path18.dirname(path18.resolve(outPath)), { recursive: true });
|
|
38247
|
+
fs12.writeFileSync(outPath, images[0].data);
|
|
38248
|
+
} else if (result && typeof result === "object") {
|
|
38249
|
+
await fetchImageToFile(result, outPath);
|
|
38250
|
+
}
|
|
38251
|
+
} catch (err) {
|
|
38252
|
+
console.error(`Failed to save image: ${err instanceof Error ? err.message : err}`);
|
|
38253
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38254
|
+
error_code: FAILURE_CODES.CLI_RUN_SAVE_IMAGE_FAILED,
|
|
38255
|
+
failure_stage: "cli_run_save_image",
|
|
38256
|
+
failure_area: "cli",
|
|
38257
|
+
error_kind: "unknown"
|
|
38258
|
+
});
|
|
38259
|
+
process.exit(1);
|
|
38260
|
+
}
|
|
38261
|
+
}
|
|
38262
|
+
if (note) console.error(note);
|
|
38263
|
+
console.log(renderResult(result, meta3.outputHint, images, json2));
|
|
38264
|
+
if (outPath && meta3.outputHint === "image" && !json2) {
|
|
38265
|
+
console.log(`Wrote: ${outPath}`);
|
|
38266
|
+
}
|
|
38267
|
+
if (failure2) {
|
|
38268
|
+
await new Promise((resolve13) => process.stdout.write("", () => resolve13()));
|
|
38269
|
+
console.error(failure2);
|
|
38270
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38271
|
+
error_code: FAILURE_CODES.CLI_RUN_TOOL_RESULT_FAILED,
|
|
38272
|
+
failure_stage: "cli_run_tool_result",
|
|
38273
|
+
failure_area: "cli",
|
|
38274
|
+
error_kind: "unknown"
|
|
38275
|
+
});
|
|
38276
|
+
await exitAfterFlush(1, [process.stderr]);
|
|
38277
|
+
}
|
|
38278
|
+
}
|
|
38279
|
+
|
|
38197
38280
|
// ../argent-cli/src/tools.ts
|
|
38198
38281
|
function summarize(description, max = 80) {
|
|
38199
38282
|
if (!description) return "";
|
|
@@ -39818,8 +39901,17 @@ function runToggle(argv, command, registry2) {
|
|
|
39818
39901
|
} else {
|
|
39819
39902
|
console.log(`Disabled flag "${parsed.name}" (${parsed.scope}).`);
|
|
39820
39903
|
}
|
|
39904
|
+
const shadow = projectShadowNote(parsed.name, parsed.scope, command);
|
|
39905
|
+
if (shadow) console.log(import_picocolors2.default.yellow(shadow));
|
|
39821
39906
|
return parsed.name;
|
|
39822
39907
|
}
|
|
39908
|
+
function projectShadowNote(name, scope, command) {
|
|
39909
|
+
if (scope !== "global") return void 0;
|
|
39910
|
+
const wanted = command === "enable";
|
|
39911
|
+
const project = readFlags("project");
|
|
39912
|
+
if (!Object.hasOwn(project, name) || project[name] === wanted) return void 0;
|
|
39913
|
+
return `The project flags file ${getFlagsPath("project")} sets "${name}" to ${project[name]}, which overrides the global value, so the flag stays ${wanted ? "off" : "on"} in this project. Run: argent ${command} ${name} --scope project`;
|
|
39914
|
+
}
|
|
39823
39915
|
function enable(argv, registry2 = FLAG_REGISTRY) {
|
|
39824
39916
|
if (runToggle(argv, "enable", registry2) !== "forward-secrets") return;
|
|
39825
39917
|
return linkedSecretsNote().then((note) => {
|