@swmansion/argent 0.32.1-next.2 → 0.32.1-next.21
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 +552 -440
- package/dist/client.d.ts +5 -0
- package/dist/client.js +71 -9
- package/dist/installer.mjs +384 -202
- package/dist/mcp-server.mjs +167 -20
- package/dist/tool-args.generated.d.ts +91 -50
- package/dist/tool-server.cjs +34748 -29334
- 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 +8 -4
- package/skills/argent-create-e2e/references/live-authoring.md +1 -0
- 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,10 @@ 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. Off by default."
|
|
9484
9488
|
}
|
|
9485
9489
|
];
|
|
9486
9490
|
function getFlagDefinition(name, registry2 = FLAG_REGISTRY) {
|
|
@@ -10452,6 +10456,8 @@ var FAILURE_CODES = {
|
|
|
10452
10456
|
CLI_RUN_ARGS_JSON_INVALID: "CLI_RUN_ARGS_JSON_INVALID",
|
|
10453
10457
|
CLI_RUN_INPUT_VALIDATION_FAILED: "CLI_RUN_INPUT_VALIDATION_FAILED",
|
|
10454
10458
|
CLI_RUN_TOOL_CALL_FAILED: "CLI_RUN_TOOL_CALL_FAILED",
|
|
10459
|
+
// The result carried the tool-server's `failure` field.
|
|
10460
|
+
CLI_RUN_TOOL_RESULT_FAILED: "CLI_RUN_TOOL_RESULT_FAILED",
|
|
10455
10461
|
CLI_RUN_SAVE_IMAGE_FAILED: "CLI_RUN_SAVE_IMAGE_FAILED",
|
|
10456
10462
|
TOOL_CAPABILITY_UNSUPPORTED_OPERATION: "TOOL_CAPABILITY_UNSUPPORTED_OPERATION",
|
|
10457
10463
|
TOOL_PLATFORM_NOT_IMPLEMENTED: "TOOL_PLATFORM_NOT_IMPLEMENTED",
|
|
@@ -10467,6 +10473,7 @@ var FAILURE_CODES = {
|
|
|
10467
10473
|
INSTALL_MODE_FLAG_CONFLICT: "INSTALL_MODE_FLAG_CONFLICT",
|
|
10468
10474
|
INSTALL_FROM_TAR_PACKAGE_FAILED: "INSTALL_FROM_TAR_PACKAGE_FAILED",
|
|
10469
10475
|
INSTALL_INIT_TRIGGERED_UPDATE_FAILED: "INSTALL_INIT_TRIGGERED_UPDATE_FAILED",
|
|
10476
|
+
INSTALL_SKILLS_FAILED: "INSTALL_SKILLS_FAILED",
|
|
10470
10477
|
INSTALL_SKILLS_REFRESH_FAILED: "INSTALL_SKILLS_REFRESH_FAILED",
|
|
10471
10478
|
INSTALL_UNCLASSIFIED_FAILED: "INSTALL_UNCLASSIFIED_FAILED",
|
|
10472
10479
|
UPDATE_INSTALLED_VERSION_DETECT_FAILED: "UPDATE_INSTALLED_VERSION_DETECT_FAILED",
|
|
@@ -10550,15 +10557,21 @@ var FAILURE_CODES = {
|
|
|
10550
10557
|
ANDROID_LAUNCH_AM_START_FAILED: "ANDROID_LAUNCH_AM_START_FAILED",
|
|
10551
10558
|
ANDROID_OPEN_URL_FAILED: "ANDROID_OPEN_URL_FAILED",
|
|
10552
10559
|
ANDROID_REINSTALL_INSTALL_FAILED: "ANDROID_REINSTALL_INSTALL_FAILED",
|
|
10560
|
+
ANDROID_REINSTALL_UNINSTALL_FAILED: "ANDROID_REINSTALL_UNINSTALL_FAILED",
|
|
10553
10561
|
ANDROID_RESTART_FAILED: "ANDROID_RESTART_FAILED",
|
|
10554
10562
|
ANDROID_SETTINGS_PERMISSION_FAILED: "ANDROID_SETTINGS_PERMISSION_FAILED",
|
|
10555
10563
|
IOS_LAUNCH_SIMCTL_FAILED: "IOS_LAUNCH_SIMCTL_FAILED",
|
|
10556
10564
|
IOS_OPEN_URL_FAILED: "IOS_OPEN_URL_FAILED",
|
|
10557
10565
|
IOS_REINSTALL_INSTALL_FAILED: "IOS_REINSTALL_INSTALL_FAILED",
|
|
10566
|
+
IOS_REINSTALL_UNINSTALL_FAILED: "IOS_REINSTALL_UNINSTALL_FAILED",
|
|
10558
10567
|
IOS_RESTART_LAUNCH_FAILED: "IOS_RESTART_LAUNCH_FAILED",
|
|
10568
|
+
IOS_RESTART_TERMINATE_FAILED: "IOS_RESTART_TERMINATE_FAILED",
|
|
10569
|
+
IOS_TERMINATE_APP_FAILED: "IOS_TERMINATE_APP_FAILED",
|
|
10559
10570
|
IOS_SETTINGS_PERMISSION_FAILED: "IOS_SETTINGS_PERMISSION_FAILED",
|
|
10560
10571
|
IOS_SHAKE_FAILED: "IOS_SHAKE_FAILED",
|
|
10561
10572
|
ANDROID_SHAKE_FAILED: "ANDROID_SHAKE_FAILED",
|
|
10573
|
+
STOP_METRO_PORT_PROBE_FAILED: "STOP_METRO_PORT_PROBE_FAILED",
|
|
10574
|
+
STOP_METRO_SIGNAL_FAILED: "STOP_METRO_SIGNAL_FAILED",
|
|
10562
10575
|
// The hinge of a foldable iOS simulator: the server refused the request on a
|
|
10563
10576
|
// foldable (a bad angle, a hinge that would not move) vs. nothing to fold —
|
|
10564
10577
|
// a device that is not foldable, no hinge route, a remote simulator.
|
|
@@ -10657,6 +10670,8 @@ var FAILURE_CODES = {
|
|
|
10657
10670
|
REACT_PROFILER_START_FAILED: "REACT_PROFILER_START_FAILED",
|
|
10658
10671
|
REACT_PROFILER_START_VERIFY_FAILED: "REACT_PROFILER_START_VERIFY_FAILED",
|
|
10659
10672
|
REACT_PROFILER_SESSION_TORN_DOWN: "REACT_PROFILER_SESSION_TORN_DOWN",
|
|
10673
|
+
REACT_PROFILER_SESSION_TAKEN_OVER: "REACT_PROFILER_SESSION_TAKEN_OVER",
|
|
10674
|
+
REACT_PROFILER_STOP_IN_PROGRESS: "REACT_PROFILER_STOP_IN_PROGRESS",
|
|
10660
10675
|
REACT_PROFILER_HOOK_ERROR: "REACT_PROFILER_HOOK_ERROR",
|
|
10661
10676
|
REACT_PROFILER_ANALYZE_NO_DATA: "REACT_PROFILER_ANALYZE_NO_DATA",
|
|
10662
10677
|
NATIVE_PROFILER_FACTORY_OPTIONS_MISSING: "NATIVE_PROFILER_FACTORY_OPTIONS_MISSING",
|
|
@@ -10704,10 +10719,13 @@ var FAILURE_CODES = {
|
|
|
10704
10719
|
FLOW_NAME_INVALID: "FLOW_NAME_INVALID",
|
|
10705
10720
|
FLOW_NO_ACTIVE_RECORDING: "FLOW_NO_ACTIVE_RECORDING",
|
|
10706
10721
|
FLOW_FILE_INVALID: "FLOW_FILE_INVALID",
|
|
10722
|
+
FLOW_FILE_NEWER_VERSION: "FLOW_FILE_NEWER_VERSION",
|
|
10707
10723
|
FLOW_FILE_WRITE_FAILED: "FLOW_FILE_WRITE_FAILED",
|
|
10708
10724
|
FLOW_ENTRY_UNRECOGNIZED: "FLOW_ENTRY_UNRECOGNIZED",
|
|
10709
10725
|
FLOW_E2E_HAS_PREREQUISITE: "FLOW_E2E_HAS_PREREQUISITE",
|
|
10710
10726
|
FLOW_DEVICE_RESOLUTION: "FLOW_DEVICE_RESOLUTION",
|
|
10727
|
+
// The target does not satisfy the test's `requires:` block; a directory run skips it.
|
|
10728
|
+
FLOW_REQUIREMENTS_UNMET: "FLOW_REQUIREMENTS_UNMET",
|
|
10711
10729
|
PROFILER_QUERY_MODE_INVALID: "PROFILER_QUERY_MODE_INVALID",
|
|
10712
10730
|
PROFILER_QUERY_REQUIRED_PARAM_MISSING: "PROFILER_QUERY_REQUIRED_PARAM_MISSING",
|
|
10713
10731
|
PROFILER_DATA_NOT_LOADED: "PROFILER_DATA_NOT_LOADED",
|
|
@@ -10726,11 +10744,38 @@ var FAILURE_CODES = {
|
|
|
10726
10744
|
CHROMIUM_STORAGE_EVAL_FAILED: "CHROMIUM_STORAGE_EVAL_FAILED",
|
|
10727
10745
|
CHROMIUM_TAB_NOT_FOUND: "CHROMIUM_TAB_NOT_FOUND",
|
|
10728
10746
|
CHROMIUM_TAB_OPEN_FAILED: "CHROMIUM_TAB_OPEN_FAILED",
|
|
10747
|
+
CHROMIUM_NAVIGATE_FAILED: "CHROMIUM_NAVIGATE_FAILED",
|
|
10729
10748
|
CHROMIUM_DESCRIBE_FAILED: "CHROMIUM_DESCRIBE_FAILED",
|
|
10730
10749
|
CHROMIUM_ELECTRON_APP_PATH_INVALID: "CHROMIUM_ELECTRON_APP_PATH_INVALID",
|
|
10731
10750
|
CHROMIUM_ELECTRON_SPAWN_FAILED: "CHROMIUM_ELECTRON_SPAWN_FAILED",
|
|
10732
10751
|
CHROMIUM_ELECTRON_CDP_TIMEOUT: "CHROMIUM_ELECTRON_CDP_TIMEOUT",
|
|
10733
10752
|
CHROMIUM_ELECTRON_EXITED_BEFORE_READY: "CHROMIUM_ELECTRON_EXITED_BEFORE_READY",
|
|
10753
|
+
/**
|
|
10754
|
+
* Native Mac apps (the `macos-apps` flag)
|
|
10755
|
+
* @see [macos-app.ts](../../tool-server/src/blueprints/macos-app.ts)
|
|
10756
|
+
*/
|
|
10757
|
+
MACOS_APP_UNSUPPORTED_HOST: "MACOS_APP_UNSUPPORTED_HOST",
|
|
10758
|
+
MACOS_APP_PATH_INVALID: "MACOS_APP_PATH_INVALID",
|
|
10759
|
+
MACOS_APP_BUNDLE_INVALID: "MACOS_APP_BUNDLE_INVALID",
|
|
10760
|
+
MACOS_APP_NOT_FOUND: "MACOS_APP_NOT_FOUND",
|
|
10761
|
+
MACOS_APP_HARDENED_RUNTIME: "MACOS_APP_HARDENED_RUNTIME",
|
|
10762
|
+
MACOS_APP_LIBRARY_MISSING: "MACOS_APP_LIBRARY_MISSING",
|
|
10763
|
+
MACOS_APP_LIBRARY_STAGE_FAILED: "MACOS_APP_LIBRARY_STAGE_FAILED",
|
|
10764
|
+
MACOS_APP_ALREADY_RUNNING: "MACOS_APP_ALREADY_RUNNING",
|
|
10765
|
+
MACOS_APP_SPAWN_FAILED: "MACOS_APP_SPAWN_FAILED",
|
|
10766
|
+
MACOS_APP_EXITED_BEFORE_READY: "MACOS_APP_EXITED_BEFORE_READY",
|
|
10767
|
+
MACOS_APP_HANDSHAKE_TIMEOUT: "MACOS_APP_HANDSHAKE_TIMEOUT",
|
|
10768
|
+
MACOS_APP_HANDSHAKE_INVALID: "MACOS_APP_HANDSHAKE_INVALID",
|
|
10769
|
+
MACOS_APP_NOT_RUNNING: "MACOS_APP_NOT_RUNNING",
|
|
10770
|
+
MACOS_APP_NOT_CONNECTED: "MACOS_APP_NOT_CONNECTED",
|
|
10771
|
+
MACOS_APP_CONNECTION_LOST: "MACOS_APP_CONNECTION_LOST",
|
|
10772
|
+
MACOS_APP_CONNECTION_CLOSED: "MACOS_APP_CONNECTION_CLOSED",
|
|
10773
|
+
MACOS_APP_RPC_TIMEOUT: "MACOS_APP_RPC_TIMEOUT",
|
|
10774
|
+
MACOS_APP_RPC_ERROR: "MACOS_APP_RPC_ERROR",
|
|
10775
|
+
MACOS_APP_TERMINATE_FAILED: "MACOS_APP_TERMINATE_FAILED",
|
|
10776
|
+
MACOS_APP_BUNDLE_ID_MISMATCH: "MACOS_APP_BUNDLE_ID_MISMATCH",
|
|
10777
|
+
MACOS_APP_OPEN_URL_FAILED: "MACOS_APP_OPEN_URL_FAILED",
|
|
10778
|
+
MACOS_APP_FILE_ACCESS_FAILED: "MACOS_APP_FILE_ACCESS_FAILED",
|
|
10734
10779
|
KEYBOARD_KEY_UNSUPPORTED: "KEYBOARD_KEY_UNSUPPORTED",
|
|
10735
10780
|
KEYBOARD_CHARACTER_UNSUPPORTED: "KEYBOARD_CHARACTER_UNSUPPORTED",
|
|
10736
10781
|
KEYBOARD_TEXT_AND_KEY_COMBINED: "KEYBOARD_TEXT_AND_KEY_COMBINED",
|
|
@@ -10742,6 +10787,8 @@ var FAILURE_CODES = {
|
|
|
10742
10787
|
SCREENSHOT_DIFF_INPUT_INVALID: "SCREENSHOT_DIFF_INPUT_INVALID",
|
|
10743
10788
|
BOOT_DEVICE_TARGET_SELECTION_INVALID: "BOOT_DEVICE_TARGET_SELECTION_INVALID",
|
|
10744
10789
|
BOOT_IOS_UNSUPPORTED_HOST: "BOOT_IOS_UNSUPPORTED_HOST",
|
|
10790
|
+
BOOT_IOS_SIMCTL_LIST_TIMEOUT: "BOOT_IOS_SIMCTL_LIST_TIMEOUT",
|
|
10791
|
+
BOOT_IOS_SIMCTL_TIMEOUT: "BOOT_IOS_SIMCTL_TIMEOUT",
|
|
10745
10792
|
BOOT_ANDROID_NO_AVDS: "BOOT_ANDROID_NO_AVDS",
|
|
10746
10793
|
BOOT_ANDROID_AVD_NOT_FOUND: "BOOT_ANDROID_AVD_NOT_FOUND",
|
|
10747
10794
|
BOOT_ANDROID_ADB_UNAVAILABLE: "BOOT_ANDROID_ADB_UNAVAILABLE",
|
|
@@ -31639,7 +31686,8 @@ async function consumeToolStream(name, body, onProgress, signal) {
|
|
|
31639
31686
|
final = {
|
|
31640
31687
|
data: msg.data,
|
|
31641
31688
|
note: msg.note,
|
|
31642
|
-
...msg.profiling === true ? { profiling: true } : {}
|
|
31689
|
+
...msg.profiling === true ? { profiling: true } : {},
|
|
31690
|
+
...typeof msg.failure === "string" ? { failure: msg.failure } : {}
|
|
31643
31691
|
};
|
|
31644
31692
|
} else if (msg.event === "error") {
|
|
31645
31693
|
throw new ToolInvocationError(msg.error ?? "tool invocation failed", {
|
|
@@ -31691,7 +31739,8 @@ async function consumeToolStream(name, body, onProgress, signal) {
|
|
|
31691
31739
|
return {
|
|
31692
31740
|
data: final.data,
|
|
31693
31741
|
note: final.note,
|
|
31694
|
-
...final.profiling ? { profiling: true } : {}
|
|
31742
|
+
...final.profiling ? { profiling: true } : {},
|
|
31743
|
+
...final.failure !== void 0 ? { failure: final.failure } : {}
|
|
31695
31744
|
};
|
|
31696
31745
|
}
|
|
31697
31746
|
function errorBodyMessage(body) {
|
|
@@ -31856,6 +31905,7 @@ function createToolsClient(options = {}) {
|
|
|
31856
31905
|
}
|
|
31857
31906
|
const shadowWarning = await e2eShadowWarningFor(name, args);
|
|
31858
31907
|
const baselineDirs = [];
|
|
31908
|
+
let unwrittenBaselines2 = [];
|
|
31859
31909
|
if (meta3?.fileInputs?.length) {
|
|
31860
31910
|
if (remote) assertRequiredPresent(meta3, finalArgs);
|
|
31861
31911
|
finalArgs = await prepareFileInputs(meta3.fileInputs, finalArgs ?? {}, {
|
|
@@ -31869,8 +31919,9 @@ function createToolsClient(options = {}) {
|
|
|
31869
31919
|
signal: opts?.signal
|
|
31870
31920
|
});
|
|
31871
31921
|
}
|
|
31872
|
-
const settle2 = async (
|
|
31873
|
-
const applied = await applyClientFileDirectives(
|
|
31922
|
+
const settle2 = async (data2) => {
|
|
31923
|
+
const applied = await applyClientFileDirectives(data2, { allowedDirs: baselineDirs });
|
|
31924
|
+
unwrittenBaselines2 = applied.failed.map((f) => f.path);
|
|
31874
31925
|
for (const { path: file2, error: error63 } of applied.failed) {
|
|
31875
31926
|
diagnose(`The baseline ${file2} was not written on this client: ${error63}`);
|
|
31876
31927
|
}
|
|
@@ -31887,6 +31938,7 @@ function createToolsClient(options = {}) {
|
|
|
31887
31938
|
}
|
|
31888
31939
|
return { ...result, warning: shadowWarning };
|
|
31889
31940
|
};
|
|
31941
|
+
const unwrittenFailure = () => unwrittenBaselines2.length > 0 ? `Baselines not written on this client: ${unwrittenBaselines2.join(", ")}` : void 0;
|
|
31890
31942
|
const stream = opts?.onProgress !== void 0 || carriesMembers(finalArgs);
|
|
31891
31943
|
const sentOnce = carriesUpload(finalArgs);
|
|
31892
31944
|
const forwarded = remote ? await forwardedSecrets(finalArgs) : void 0;
|
|
@@ -31950,11 +32002,14 @@ function createToolsClient(options = {}) {
|
|
|
31950
32002
|
}),
|
|
31951
32003
|
opts?.signal
|
|
31952
32004
|
);
|
|
32005
|
+
const data2 = await settle2(streamed.data);
|
|
32006
|
+
const failure3 = streamed.failure ?? unwrittenFailure();
|
|
31953
32007
|
return {
|
|
31954
|
-
data:
|
|
32008
|
+
data: data2,
|
|
31955
32009
|
note: streamed.note,
|
|
31956
32010
|
outputHint: meta3?.outputHint,
|
|
31957
|
-
...streamed.profiling ? { profiling: true } : {}
|
|
32011
|
+
...streamed.profiling ? { profiling: true } : {},
|
|
32012
|
+
...failure3 !== void 0 ? { failure: failure3 } : {}
|
|
31958
32013
|
};
|
|
31959
32014
|
}
|
|
31960
32015
|
let json2;
|
|
@@ -31990,11 +32045,14 @@ function createToolsClient(options = {}) {
|
|
|
31990
32045
|
});
|
|
31991
32046
|
}
|
|
31992
32047
|
opts?.signal?.throwIfAborted();
|
|
32048
|
+
const data = await settle2(json2.data);
|
|
32049
|
+
const failure2 = (typeof json2.failure === "string" ? json2.failure : void 0) ?? unwrittenFailure();
|
|
31993
32050
|
return {
|
|
31994
|
-
data
|
|
32051
|
+
data,
|
|
31995
32052
|
note: json2.note,
|
|
31996
32053
|
outputHint: meta3?.outputHint,
|
|
31997
|
-
...json2.profiling === true ? { profiling: true } : {}
|
|
32054
|
+
...json2.profiling === true ? { profiling: true } : {},
|
|
32055
|
+
...failure2 !== void 0 ? { failure: failure2 } : {}
|
|
31998
32056
|
};
|
|
31999
32057
|
}
|
|
32000
32058
|
return { fetchTools, fetchTool, callTool, baseUrl };
|
|
@@ -35057,7 +35115,8 @@ var PLATFORMS = [
|
|
|
35057
35115
|
"vega",
|
|
35058
35116
|
"harmony",
|
|
35059
35117
|
"tvos",
|
|
35060
|
-
"android-tv"
|
|
35118
|
+
"android-tv",
|
|
35119
|
+
"macos"
|
|
35061
35120
|
];
|
|
35062
35121
|
var DEVICE_KINDS = [
|
|
35063
35122
|
"simulator",
|
|
@@ -35209,6 +35268,9 @@ var ALLOWED = {
|
|
|
35209
35268
|
warned_count: COUNT
|
|
35210
35269
|
},
|
|
35211
35270
|
"installation:skill_install": {
|
|
35271
|
+
source: oneOf(["pinned", "bundled"]),
|
|
35272
|
+
used_fallback: bool,
|
|
35273
|
+
fallback_reason: oneOf(["ref_missing", "unclassified"]),
|
|
35212
35274
|
method: oneOf(["default", "interactive", "manual"]),
|
|
35213
35275
|
is_online: bool,
|
|
35214
35276
|
has_offline_cache: bool,
|
|
@@ -35809,7 +35871,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
|
|
|
35809
35871
|
var SESSION_ID2 = randomUUID5();
|
|
35810
35872
|
function readCliVersion() {
|
|
35811
35873
|
if (true) {
|
|
35812
|
-
return "0.32.1-next.
|
|
35874
|
+
return "0.32.1-next.21";
|
|
35813
35875
|
}
|
|
35814
35876
|
return "0.0.0";
|
|
35815
35877
|
}
|
|
@@ -36748,391 +36810,106 @@ function isValidationIssue(value) {
|
|
|
36748
36810
|
return typeof issue2.code === "string" && Array.isArray(issue2.path) && typeof issue2.message === "string";
|
|
36749
36811
|
}
|
|
36750
36812
|
|
|
36751
|
-
// ../argent-cli/src/
|
|
36752
|
-
|
|
36753
|
-
|
|
36754
|
-
|
|
36755
|
-
|
|
36813
|
+
// ../argent-cli/src/e2e.ts
|
|
36814
|
+
import * as fsp from "node:fs/promises";
|
|
36815
|
+
import { constants as fsConstants2 } from "node:fs";
|
|
36816
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
36817
|
+
import * as path17 from "node:path";
|
|
36818
|
+
|
|
36819
|
+
// ../argent-cli/src/command-args.ts
|
|
36820
|
+
var UsageError = class extends Error {
|
|
36821
|
+
constructor(message) {
|
|
36822
|
+
super(message);
|
|
36823
|
+
this.name = "UsageError";
|
|
36824
|
+
}
|
|
36825
|
+
};
|
|
36826
|
+
function listChoices(choices) {
|
|
36827
|
+
const quoted = choices.map((c2) => `"${c2}"`);
|
|
36828
|
+
if (quoted.length <= 1) return quoted.join("");
|
|
36829
|
+
return `${quoted.slice(0, -1).join(", ")} or ${quoted[quoted.length - 1]}`;
|
|
36830
|
+
}
|
|
36831
|
+
function resolveName(tok, specs) {
|
|
36832
|
+
if (tok.startsWith("--")) return tok.slice(2) in specs ? tok.slice(2) : null;
|
|
36833
|
+
const short = tok.slice(1);
|
|
36834
|
+
for (const [name, spec] of Object.entries(specs)) {
|
|
36835
|
+
if (spec.alias === short) return name;
|
|
36836
|
+
}
|
|
36837
|
+
return null;
|
|
36838
|
+
}
|
|
36839
|
+
function parseCommandArgs(argv, specs) {
|
|
36840
|
+
const positionals = [];
|
|
36841
|
+
const options = {};
|
|
36756
36842
|
for (let i2 = 0; i2 < argv.length; i2++) {
|
|
36757
36843
|
const tok = argv[i2];
|
|
36758
|
-
if (tok === "--
|
|
36759
|
-
|
|
36760
|
-
|
|
36844
|
+
if (tok === "--") {
|
|
36845
|
+
positionals.push(...argv.slice(i2 + 1));
|
|
36846
|
+
break;
|
|
36761
36847
|
}
|
|
36762
|
-
if (tok === "
|
|
36763
|
-
|
|
36764
|
-
if (!v) throw new FlagParseException("--out requires a path");
|
|
36765
|
-
outPath = v;
|
|
36766
|
-
i2 += 1;
|
|
36848
|
+
if (!tok.startsWith("-") || tok === "-") {
|
|
36849
|
+
positionals.push(tok);
|
|
36767
36850
|
continue;
|
|
36768
36851
|
}
|
|
36769
|
-
|
|
36770
|
-
|
|
36852
|
+
const eq = tok.startsWith("--") ? tok.indexOf("=") : -1;
|
|
36853
|
+
const flag = eq === -1 ? tok : tok.slice(0, eq);
|
|
36854
|
+
const inlineValue = eq === -1 ? void 0 : tok.slice(eq + 1);
|
|
36855
|
+
const name = resolveName(flag, specs);
|
|
36856
|
+
if (name === null) throw new UsageError(`Unknown flag: ${tok}`);
|
|
36857
|
+
const spec = specs[name];
|
|
36858
|
+
const display = `--${name}`;
|
|
36859
|
+
if (spec.kind === "boolean") {
|
|
36860
|
+
if (inlineValue !== void 0) throw new UsageError(`${display} does not take a value`);
|
|
36861
|
+
const next = argv[i2 + 1]?.trim().toLowerCase();
|
|
36862
|
+
if (next === "true" || next === "false") {
|
|
36863
|
+
throw new UsageError(
|
|
36864
|
+
`${display} does not take a value \u2014 it is a switch; omit it to leave the option off`
|
|
36865
|
+
);
|
|
36866
|
+
}
|
|
36867
|
+
options[name] = true;
|
|
36771
36868
|
continue;
|
|
36772
36869
|
}
|
|
36773
|
-
|
|
36774
|
-
|
|
36775
|
-
|
|
36776
|
-
|
|
36777
|
-
|
|
36778
|
-
|
|
36779
|
-
|
|
36780
|
-
|
|
36781
|
-
|
|
36782
|
-
|
|
36783
|
-
});
|
|
36784
|
-
|
|
36785
|
-
|
|
36786
|
-
});
|
|
36787
|
-
}
|
|
36788
|
-
function printToolHelp(meta3) {
|
|
36789
|
-
const description = meta3.description?.trim() ?? "";
|
|
36790
|
-
const schema = meta3.inputSchema;
|
|
36791
|
-
const hasOwnArgsField = schema?.properties?.args !== void 0;
|
|
36792
|
-
console.log(`argent run ${meta3.name} [flags]`);
|
|
36793
|
-
if (description) console.log(`
|
|
36794
|
-
${description}
|
|
36795
|
-
`);
|
|
36796
|
-
console.log("Flags:");
|
|
36797
|
-
console.log(formatSchemaUsage(schema));
|
|
36798
|
-
console.log("\nGlobal flags:");
|
|
36799
|
-
if (!hasOwnArgsField) {
|
|
36800
|
-
console.log(" --args <json> Pass the entire payload as JSON (overrides flags)");
|
|
36801
|
-
console.log(" --args - Read the entire payload as JSON from stdin");
|
|
36802
|
-
}
|
|
36803
|
-
console.log(" --<field>-json <json> Pass a single field as JSON (objects/nested arrays)");
|
|
36804
|
-
console.log(" --json Print the raw JSON result");
|
|
36805
|
-
console.log(" --out <path> For image results, save to <path> instead of fetching URL");
|
|
36806
|
-
console.log(" --help, -h Show this help");
|
|
36807
|
-
}
|
|
36808
|
-
async function fetchImageToFile(result, outPath) {
|
|
36809
|
-
const url2 = result.url;
|
|
36810
|
-
if (!url2) {
|
|
36811
|
-
throw new Error("Tool result did not include a `url`; cannot save image");
|
|
36812
|
-
}
|
|
36813
|
-
const res = await fetch(url2);
|
|
36814
|
-
if (!res.ok) throw new Error(`Failed to download image: ${res.status} ${res.statusText}`);
|
|
36815
|
-
const buf = Buffer.from(await res.arrayBuffer());
|
|
36816
|
-
fs12.mkdirSync(path17.dirname(path17.resolve(outPath)), { recursive: true });
|
|
36817
|
-
fs12.writeFileSync(outPath, buf);
|
|
36818
|
-
}
|
|
36819
|
-
function renderResult(result, outputHint, images, json2) {
|
|
36820
|
-
if (json2) return JSON.stringify(result, null, 2);
|
|
36821
|
-
if (outputHint === "image") {
|
|
36822
|
-
if (images.length > 0) return `Saved screenshot: ${images[0].localPath}`;
|
|
36823
|
-
if (result && typeof result === "object" && "path" in result && typeof result.path === "string") {
|
|
36824
|
-
return `Saved screenshot: ${result.path}`;
|
|
36870
|
+
let value = inlineValue;
|
|
36871
|
+
if (value === void 0) {
|
|
36872
|
+
const next = argv[i2 + 1];
|
|
36873
|
+
if (next !== void 0 && (!next.startsWith("-") || next === "-")) {
|
|
36874
|
+
value = next;
|
|
36875
|
+
i2 += 1;
|
|
36876
|
+
}
|
|
36877
|
+
} else if (value === "") {
|
|
36878
|
+
value = void 0;
|
|
36879
|
+
}
|
|
36880
|
+
if (value === void 0) throw new UsageError(`${display} requires a value`);
|
|
36881
|
+
if (spec.choices && !spec.choices.includes(value)) {
|
|
36882
|
+
throw new UsageError(`${display} must be ${listChoices(spec.choices)}, got "${value}"`);
|
|
36825
36883
|
}
|
|
36884
|
+
options[name] = value;
|
|
36826
36885
|
}
|
|
36827
|
-
|
|
36828
|
-
return JSON.stringify(result, null, 2);
|
|
36886
|
+
return { positionals, options };
|
|
36829
36887
|
}
|
|
36830
|
-
|
|
36831
|
-
|
|
36832
|
-
|
|
36888
|
+
|
|
36889
|
+
// ../argent-cli/src/e2e.ts
|
|
36890
|
+
var STATUS_GLYPH = {
|
|
36891
|
+
pass: "\u2713",
|
|
36892
|
+
fail: "\u2717",
|
|
36893
|
+
error: "\u2717",
|
|
36894
|
+
skip: "\xB7"
|
|
36895
|
+
};
|
|
36896
|
+
var MAX_RENDER_DEPTH = 20;
|
|
36897
|
+
function stepIndent(depth) {
|
|
36898
|
+
if (typeof depth !== "number" || !Number.isInteger(depth) || depth <= 0) return "";
|
|
36899
|
+
return " ".repeat(Math.min(depth, MAX_RENDER_DEPTH));
|
|
36833
36900
|
}
|
|
36834
|
-
|
|
36835
|
-
|
|
36836
|
-
|
|
36837
|
-
|
|
36838
|
-
|
|
36839
|
-
|
|
36840
|
-
...signal
|
|
36841
|
-
});
|
|
36842
|
-
await shutdown();
|
|
36901
|
+
function durationSuffix(ms) {
|
|
36902
|
+
if (typeof ms !== "number" || !Number.isFinite(ms) || ms < 0) return "";
|
|
36903
|
+
const tenths = Math.round(ms / 100);
|
|
36904
|
+
if (tenths < 600) return ` (${(tenths / 10).toFixed(1)}s)`;
|
|
36905
|
+
const seconds = Math.round(ms / 1e3);
|
|
36906
|
+
return ` (${Math.floor(seconds / 60)}m ${seconds % 60}s)`;
|
|
36843
36907
|
}
|
|
36844
|
-
|
|
36845
|
-
|
|
36846
|
-
|
|
36847
|
-
const { fetchTool, callTool, baseUrl } = createToolsClient({ paths: options.paths });
|
|
36848
|
-
const [toolName, ...rest] = argv;
|
|
36849
|
-
if (!toolName || toolName === "--help" || toolName === "-h") {
|
|
36850
|
-
console.log(`Usage: argent run <tool> [flags]
|
|
36908
|
+
function printHelp(toStderr = false) {
|
|
36909
|
+
const print = toStderr ? console.error : console.log;
|
|
36910
|
+
print(`Usage: argent e2e <subcommand> [options]
|
|
36851
36911
|
|
|
36852
|
-
|
|
36853
|
-
available tools, or \`argent tools describe <name>\` to see one tool's flags.
|
|
36854
|
-
|
|
36855
|
-
Examples:
|
|
36856
|
-
argent run list-devices
|
|
36857
|
-
argent run gesture-tap --udid <UDID> --x 0.5 --y 0.5
|
|
36858
|
-
argent run screenshot --udid <UDID> --out ./screen.png
|
|
36859
|
-
argent run run-sequence --udid <UDID> --steps-json '[{"tool":"button","args":{"button":"home"}}]'
|
|
36860
|
-
argent run gesture-tap --args '{"udid":"<UDID>","x":0.5,"y":0.5}'
|
|
36861
|
-
`);
|
|
36862
|
-
return;
|
|
36863
|
-
}
|
|
36864
|
-
let cliOptions;
|
|
36865
|
-
try {
|
|
36866
|
-
cliOptions = splitOptions(rest);
|
|
36867
|
-
} catch (err) {
|
|
36868
|
-
if (err instanceof FlagParseException) {
|
|
36869
|
-
console.error(`Error: ${err.message}
|
|
36870
|
-
`);
|
|
36871
|
-
console.error(`Run \`argent run ${toolName} --help\` to see this tool's flags.`);
|
|
36872
|
-
await trackRunFailure(toolName, startedAt, {
|
|
36873
|
-
error_code: FAILURE_CODES.CLI_RUN_FLAG_PARSE_FAILED,
|
|
36874
|
-
failure_stage: "cli_run_split_options",
|
|
36875
|
-
failure_area: "cli",
|
|
36876
|
-
error_kind: "validation"
|
|
36877
|
-
});
|
|
36878
|
-
process.exit(2);
|
|
36879
|
-
}
|
|
36880
|
-
throw err;
|
|
36881
|
-
}
|
|
36882
|
-
const { json: json2, outPath, argvForFlags } = cliOptions;
|
|
36883
|
-
const meta3 = await fetchTool(toolName);
|
|
36884
|
-
if (!meta3) {
|
|
36885
|
-
console.error(`Tool "${toolName}" not found. Run \`argent tools\` to list available tools.`);
|
|
36886
|
-
await trackRunFailure(toolName, startedAt, {
|
|
36887
|
-
error_code: FAILURE_CODES.CLI_RUN_TOOL_NOT_FOUND,
|
|
36888
|
-
failure_stage: "cli_run_fetch_tool",
|
|
36889
|
-
failure_area: "cli",
|
|
36890
|
-
error_kind: "not_found"
|
|
36891
|
-
});
|
|
36892
|
-
process.exit(1);
|
|
36893
|
-
}
|
|
36894
|
-
const schema = meta3.inputSchema;
|
|
36895
|
-
const failInvocation = async (summary, report, failure2) => {
|
|
36896
|
-
if (json2) {
|
|
36897
|
-
console.error(
|
|
36898
|
-
JSON.stringify(
|
|
36899
|
-
{
|
|
36900
|
-
error: summary,
|
|
36901
|
-
missing: report ? missingFlagNames(report, schema) : [],
|
|
36902
|
-
issues: report?.rawIssues ?? []
|
|
36903
|
-
},
|
|
36904
|
-
null,
|
|
36905
|
-
2
|
|
36906
|
-
)
|
|
36907
|
-
);
|
|
36908
|
-
} else {
|
|
36909
|
-
console.error(`Error: ${summary}
|
|
36910
|
-
`);
|
|
36911
|
-
printToolHelp(meta3);
|
|
36912
|
-
}
|
|
36913
|
-
await trackRunFailure(toolName, startedAt, {
|
|
36914
|
-
...failure2,
|
|
36915
|
-
failure_area: "cli",
|
|
36916
|
-
error_kind: "validation"
|
|
36917
|
-
});
|
|
36918
|
-
process.exit(2);
|
|
36919
|
-
};
|
|
36920
|
-
const failValidation = (report, stage) => failInvocation(formatValidationError(report, schema), report, {
|
|
36921
|
-
error_code: FAILURE_CODES.CLI_RUN_INPUT_VALIDATION_FAILED,
|
|
36922
|
-
failure_stage: stage
|
|
36923
|
-
});
|
|
36924
|
-
let parsed;
|
|
36925
|
-
try {
|
|
36926
|
-
parsed = parseFlags(argvForFlags, schema);
|
|
36927
|
-
} catch (err) {
|
|
36928
|
-
if (err instanceof FlagParseException) {
|
|
36929
|
-
await failInvocation(err.message, null, {
|
|
36930
|
-
error_code: FAILURE_CODES.CLI_RUN_FLAG_PARSE_FAILED,
|
|
36931
|
-
failure_stage: "cli_run_parse_flags"
|
|
36932
|
-
});
|
|
36933
|
-
}
|
|
36934
|
-
throw err;
|
|
36935
|
-
}
|
|
36936
|
-
if (parsed.helpRequested) {
|
|
36937
|
-
printToolHelp(meta3);
|
|
36938
|
-
return;
|
|
36939
|
-
}
|
|
36940
|
-
if (parsed.positional.length > 0) {
|
|
36941
|
-
console.error(
|
|
36942
|
-
`Note: ignoring unused argument(s): ${parsed.positional.join(", ")}. Pass values as --flag <value> or --flag=<value>.`
|
|
36943
|
-
);
|
|
36944
|
-
}
|
|
36945
|
-
let payload = {};
|
|
36946
|
-
if (parsed.rawArgs !== null) {
|
|
36947
|
-
let rawJson = parsed.rawArgs;
|
|
36948
|
-
if (rawJson === "-") {
|
|
36949
|
-
rawJson = await readStdin();
|
|
36950
|
-
}
|
|
36951
|
-
try {
|
|
36952
|
-
const parsedRaw = JSON.parse(rawJson);
|
|
36953
|
-
if (parsedRaw === null || typeof parsedRaw !== "object" || Array.isArray(parsedRaw)) {
|
|
36954
|
-
console.error("--args must be a JSON object");
|
|
36955
|
-
await trackRunFailure(toolName, startedAt, {
|
|
36956
|
-
error_code: FAILURE_CODES.CLI_RUN_ARGS_NOT_OBJECT,
|
|
36957
|
-
failure_stage: "cli_run_parse_raw_args",
|
|
36958
|
-
failure_area: "cli",
|
|
36959
|
-
error_kind: "validation"
|
|
36960
|
-
});
|
|
36961
|
-
process.exit(2);
|
|
36962
|
-
}
|
|
36963
|
-
payload = parsedRaw;
|
|
36964
|
-
} catch (err) {
|
|
36965
|
-
console.error(`--args is not valid JSON: ${err instanceof Error ? err.message : err}`);
|
|
36966
|
-
await trackRunFailure(toolName, startedAt, {
|
|
36967
|
-
error_code: FAILURE_CODES.CLI_RUN_ARGS_JSON_INVALID,
|
|
36968
|
-
failure_stage: "cli_run_parse_raw_args",
|
|
36969
|
-
failure_area: "cli",
|
|
36970
|
-
error_kind: "validation"
|
|
36971
|
-
});
|
|
36972
|
-
process.exit(2);
|
|
36973
|
-
}
|
|
36974
|
-
}
|
|
36975
|
-
for (const [k, v] of Object.entries(parsed.args)) {
|
|
36976
|
-
payload[k] = v;
|
|
36977
|
-
}
|
|
36978
|
-
const missing = findMissingRequired(payload, schema);
|
|
36979
|
-
if (missing.length > 0) {
|
|
36980
|
-
await failValidation({ missing, invalid: [], rawIssues: null }, "cli_run_required_flags");
|
|
36981
|
-
}
|
|
36982
|
-
let result;
|
|
36983
|
-
let note;
|
|
36984
|
-
let images = [];
|
|
36985
|
-
try {
|
|
36986
|
-
const resp = await callTool(toolName, payload);
|
|
36987
|
-
const { url: url2, token } = await baseUrl();
|
|
36988
|
-
const materialized = await materializeArtifacts(resp.data, {
|
|
36989
|
-
toolsUrl: url2,
|
|
36990
|
-
authToken: token,
|
|
36991
|
-
deviceId: getDeviceIdFromArgs(payload)
|
|
36992
|
-
});
|
|
36993
|
-
result = materialized.result;
|
|
36994
|
-
images = materialized.images;
|
|
36995
|
-
note = resp.note;
|
|
36996
|
-
} catch (err) {
|
|
36997
|
-
const report = describeServerValidationFailure(err, payload, schema);
|
|
36998
|
-
if (report) {
|
|
36999
|
-
await failValidation(report, "cli_run_server_validation");
|
|
37000
|
-
}
|
|
37001
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
37002
|
-
await trackRunFailure(toolName, startedAt, {
|
|
37003
|
-
error_code: FAILURE_CODES.CLI_RUN_TOOL_CALL_FAILED,
|
|
37004
|
-
failure_stage: "cli_run_call_tool",
|
|
37005
|
-
failure_area: "cli",
|
|
37006
|
-
error_kind: "unknown"
|
|
37007
|
-
});
|
|
37008
|
-
process.exit(1);
|
|
37009
|
-
}
|
|
37010
|
-
if (outPath && meta3.outputHint === "image") {
|
|
37011
|
-
try {
|
|
37012
|
-
if (images.length > 0) {
|
|
37013
|
-
fs12.mkdirSync(path17.dirname(path17.resolve(outPath)), { recursive: true });
|
|
37014
|
-
fs12.writeFileSync(outPath, images[0].data);
|
|
37015
|
-
} else if (result && typeof result === "object") {
|
|
37016
|
-
await fetchImageToFile(result, outPath);
|
|
37017
|
-
}
|
|
37018
|
-
} catch (err) {
|
|
37019
|
-
console.error(`Failed to save image: ${err instanceof Error ? err.message : err}`);
|
|
37020
|
-
await trackRunFailure(toolName, startedAt, {
|
|
37021
|
-
error_code: FAILURE_CODES.CLI_RUN_SAVE_IMAGE_FAILED,
|
|
37022
|
-
failure_stage: "cli_run_save_image",
|
|
37023
|
-
failure_area: "cli",
|
|
37024
|
-
error_kind: "unknown"
|
|
37025
|
-
});
|
|
37026
|
-
process.exit(1);
|
|
37027
|
-
}
|
|
37028
|
-
}
|
|
37029
|
-
if (note) console.error(note);
|
|
37030
|
-
console.log(renderResult(result, meta3.outputHint, images, json2));
|
|
37031
|
-
if (outPath && meta3.outputHint === "image" && !json2) {
|
|
37032
|
-
console.log(`Wrote: ${outPath}`);
|
|
37033
|
-
}
|
|
37034
|
-
}
|
|
37035
|
-
|
|
37036
|
-
// ../argent-cli/src/e2e.ts
|
|
37037
|
-
import * as fsp from "node:fs/promises";
|
|
37038
|
-
import { constants as fsConstants2 } from "node:fs";
|
|
37039
|
-
import { createHash as createHash5 } from "node:crypto";
|
|
37040
|
-
import * as path18 from "node:path";
|
|
37041
|
-
|
|
37042
|
-
// ../argent-cli/src/command-args.ts
|
|
37043
|
-
var UsageError = class extends Error {
|
|
37044
|
-
constructor(message) {
|
|
37045
|
-
super(message);
|
|
37046
|
-
this.name = "UsageError";
|
|
37047
|
-
}
|
|
37048
|
-
};
|
|
37049
|
-
function listChoices(choices) {
|
|
37050
|
-
const quoted = choices.map((c2) => `"${c2}"`);
|
|
37051
|
-
if (quoted.length <= 1) return quoted.join("");
|
|
37052
|
-
return `${quoted.slice(0, -1).join(", ")} or ${quoted[quoted.length - 1]}`;
|
|
37053
|
-
}
|
|
37054
|
-
function resolveName(tok, specs) {
|
|
37055
|
-
if (tok.startsWith("--")) return tok.slice(2) in specs ? tok.slice(2) : null;
|
|
37056
|
-
const short = tok.slice(1);
|
|
37057
|
-
for (const [name, spec] of Object.entries(specs)) {
|
|
37058
|
-
if (spec.alias === short) return name;
|
|
37059
|
-
}
|
|
37060
|
-
return null;
|
|
37061
|
-
}
|
|
37062
|
-
function parseCommandArgs(argv, specs) {
|
|
37063
|
-
const positionals = [];
|
|
37064
|
-
const options = {};
|
|
37065
|
-
for (let i2 = 0; i2 < argv.length; i2++) {
|
|
37066
|
-
const tok = argv[i2];
|
|
37067
|
-
if (tok === "--") {
|
|
37068
|
-
positionals.push(...argv.slice(i2 + 1));
|
|
37069
|
-
break;
|
|
37070
|
-
}
|
|
37071
|
-
if (!tok.startsWith("-") || tok === "-") {
|
|
37072
|
-
positionals.push(tok);
|
|
37073
|
-
continue;
|
|
37074
|
-
}
|
|
37075
|
-
const eq = tok.startsWith("--") ? tok.indexOf("=") : -1;
|
|
37076
|
-
const flag = eq === -1 ? tok : tok.slice(0, eq);
|
|
37077
|
-
const inlineValue = eq === -1 ? void 0 : tok.slice(eq + 1);
|
|
37078
|
-
const name = resolveName(flag, specs);
|
|
37079
|
-
if (name === null) throw new UsageError(`Unknown flag: ${tok}`);
|
|
37080
|
-
const spec = specs[name];
|
|
37081
|
-
const display = `--${name}`;
|
|
37082
|
-
if (spec.kind === "boolean") {
|
|
37083
|
-
if (inlineValue !== void 0) throw new UsageError(`${display} does not take a value`);
|
|
37084
|
-
const next = argv[i2 + 1]?.trim().toLowerCase();
|
|
37085
|
-
if (next === "true" || next === "false") {
|
|
37086
|
-
throw new UsageError(
|
|
37087
|
-
`${display} does not take a value \u2014 it is a switch; omit it to leave the option off`
|
|
37088
|
-
);
|
|
37089
|
-
}
|
|
37090
|
-
options[name] = true;
|
|
37091
|
-
continue;
|
|
37092
|
-
}
|
|
37093
|
-
let value = inlineValue;
|
|
37094
|
-
if (value === void 0) {
|
|
37095
|
-
const next = argv[i2 + 1];
|
|
37096
|
-
if (next !== void 0 && (!next.startsWith("-") || next === "-")) {
|
|
37097
|
-
value = next;
|
|
37098
|
-
i2 += 1;
|
|
37099
|
-
}
|
|
37100
|
-
} else if (value === "") {
|
|
37101
|
-
value = void 0;
|
|
37102
|
-
}
|
|
37103
|
-
if (value === void 0) throw new UsageError(`${display} requires a value`);
|
|
37104
|
-
if (spec.choices && !spec.choices.includes(value)) {
|
|
37105
|
-
throw new UsageError(`${display} must be ${listChoices(spec.choices)}, got "${value}"`);
|
|
37106
|
-
}
|
|
37107
|
-
options[name] = value;
|
|
37108
|
-
}
|
|
37109
|
-
return { positionals, options };
|
|
37110
|
-
}
|
|
37111
|
-
|
|
37112
|
-
// ../argent-cli/src/e2e.ts
|
|
37113
|
-
var STATUS_GLYPH = {
|
|
37114
|
-
pass: "\u2713",
|
|
37115
|
-
fail: "\u2717",
|
|
37116
|
-
error: "\u2717",
|
|
37117
|
-
skip: "\xB7"
|
|
37118
|
-
};
|
|
37119
|
-
var MAX_RENDER_DEPTH = 20;
|
|
37120
|
-
function stepIndent(depth) {
|
|
37121
|
-
if (typeof depth !== "number" || !Number.isInteger(depth) || depth <= 0) return "";
|
|
37122
|
-
return " ".repeat(Math.min(depth, MAX_RENDER_DEPTH));
|
|
37123
|
-
}
|
|
37124
|
-
function durationSuffix(ms) {
|
|
37125
|
-
if (typeof ms !== "number" || !Number.isFinite(ms) || ms < 0) return "";
|
|
37126
|
-
const tenths = Math.round(ms / 100);
|
|
37127
|
-
if (tenths < 600) return ` (${(tenths / 10).toFixed(1)}s)`;
|
|
37128
|
-
const seconds = Math.round(ms / 1e3);
|
|
37129
|
-
return ` (${Math.floor(seconds / 60)}m ${seconds % 60}s)`;
|
|
37130
|
-
}
|
|
37131
|
-
function printHelp(toStderr = false) {
|
|
37132
|
-
const print = toStderr ? console.error : console.log;
|
|
37133
|
-
print(`Usage: argent e2e <subcommand> [options]
|
|
37134
|
-
|
|
37135
|
-
Run a YAML e2e test without an LLM in the loop. \`run\` takes any of these forms:
|
|
36912
|
+
Run a YAML e2e test without an LLM in the loop. \`run\` takes any of these forms:
|
|
37136
36913
|
|
|
37137
36914
|
a name An e2e test saved under .argent/e2e or .argent/flows, resolved
|
|
37138
36915
|
from the current directory. "checkout" runs
|
|
@@ -37150,8 +36927,9 @@ contain only letters, numbers, "_", or "-" \u2014 the same charset a name must
|
|
|
37150
36927
|
match. A test is standalone when its first non-\`echo\`/\`script\` step is \`launch\`.
|
|
37151
36928
|
Other tests are fragments and use the device's current state. Exception: a fragment whose first step \`run:\`s a chromium standalone
|
|
37152
36929
|
test boots that test's app before step 1 \u2014 when that launch is unambiguously
|
|
37153
|
-
chromium (a lone \`{ chromium: ... }\` target,
|
|
37154
|
-
|
|
36930
|
+
chromium (a lone \`{ chromium: ... }\` target, --platform chromium, or a
|
|
36931
|
+
\`requires:\` block that allows only chromium); a multi-platform launch
|
|
36932
|
+
auto-detects a device instead. Pass --device to attach to
|
|
37155
36933
|
a running instance.
|
|
37156
36934
|
|
|
37157
36935
|
A directory run prints only the steps that need attention (each failure, each
|
|
@@ -37164,6 +36942,12 @@ file, or a device it cannot resolve. A transport failure, a rejection the server
|
|
|
37164
36942
|
does not mark as validation, or a reply that is not a report stops the batch and
|
|
37165
36943
|
counts the remaining tests skipped.
|
|
37166
36944
|
|
|
36945
|
+
A test can declare a \`requires:\` block (platform, runtimeKind) that names the
|
|
36946
|
+
targets it supports. A directory run skips each test whose requirements the
|
|
36947
|
+
target does not meet, so the same directory runs on each platform without a
|
|
36948
|
+
separate list of tests. A single-test run fails instead. A directory run where
|
|
36949
|
+
no test ran exits 2.
|
|
36950
|
+
|
|
37167
36951
|
The CLI sends a run to its tool-server: the local one that starts
|
|
37168
36952
|
automatically, or the one that \`argent link\` or ARGENT_TOOLS_URL names. Over
|
|
37169
36953
|
a link, the CLI uploads these files and writes the new baselines that the run
|
|
@@ -37193,7 +36977,7 @@ Subcommands:
|
|
|
37193
36977
|
|
|
37194
36978
|
Options (run):
|
|
37195
36979
|
--device <id> Device id to run against (auto-detected when omitted)
|
|
37196
|
-
--platform <p> ios | android | chromium | vega | ios-remote \u2014 narrow
|
|
36980
|
+
--platform <p> ios | android | chromium | vega |${isFlagEnabled("macos-apps") ? " macos |" : ""} ios-remote \u2014 narrow
|
|
37197
36981
|
auto-detection (ios never picks a remote simulator)
|
|
37198
36982
|
--update-baselines Write/refresh screenshot baselines instead of diffing,
|
|
37199
36983
|
also those of tests that tool: e2e-execute steps run,
|
|
@@ -37346,7 +37130,8 @@ function renderFailedSteps(report) {
|
|
|
37346
37130
|
return lines;
|
|
37347
37131
|
}
|
|
37348
37132
|
function renderBatchSummary(counts, durationMs) {
|
|
37349
|
-
|
|
37133
|
+
const verdict = counts.failed > 0 ? "FAIL" : counts.passed === 0 ? "NONE RAN" : "PASS";
|
|
37134
|
+
return `${verdict} \u2014 ${counts.total} e2e test${counts.total === 1 ? "" : "s"}: ${counts.passed} passed, ${counts.failed} failed, ${counts.skipped} skipped${durationSuffix(durationMs)}`;
|
|
37350
37135
|
}
|
|
37351
37136
|
function summarizeFailure(report) {
|
|
37352
37137
|
let n3 = 0;
|
|
@@ -37385,14 +37170,14 @@ function shellQuoteArg(arg) {
|
|
|
37385
37170
|
return `'${arg.replaceAll("'", "'\\''")}'`;
|
|
37386
37171
|
}
|
|
37387
37172
|
function rerunCommand(flowPath, rel, projectRoot, args) {
|
|
37388
|
-
const pathArg = (p) => shellQuoteArg(p.startsWith("-") ? `.${
|
|
37389
|
-
const fromCwd =
|
|
37390
|
-
const shown =
|
|
37173
|
+
const pathArg = (p) => shellQuoteArg(p.startsWith("-") ? `.${path17.sep}${p}` : p);
|
|
37174
|
+
const fromCwd = path17.relative(projectRoot, flowPath);
|
|
37175
|
+
const shown = path17.isAbsolute(fromCwd) || fromCwd.split(/[\\/]+/).includes("..") ? flowPath : fromCwd;
|
|
37391
37176
|
const parts = ["argent e2e run", pathArg(shown)];
|
|
37392
37177
|
if (args.device) parts.push("--device", shellQuoteArg(args.device));
|
|
37393
37178
|
if (args.platform) parts.push("--platform", shellQuoteArg(args.platform));
|
|
37394
37179
|
if (args.updateBaselines) parts.push("--update-baselines");
|
|
37395
|
-
if (args.output) parts.push("--output", pathArg(
|
|
37180
|
+
if (args.output) parts.push("--output", pathArg(path17.join(args.output, path17.dirname(rel))));
|
|
37396
37181
|
return parts.join(" ");
|
|
37397
37182
|
}
|
|
37398
37183
|
var EXPORT_SOURCE_MARKER = ".argent-e2e-source";
|
|
@@ -37400,8 +37185,8 @@ var LEGACY_EXPORT_SOURCE_MARKER = ".argent-flow-source";
|
|
|
37400
37185
|
var MARKER_READ_RETRIES = 4;
|
|
37401
37186
|
var MARKER_READ_DELAY_MS = 5;
|
|
37402
37187
|
async function readExportMarker(dir) {
|
|
37403
|
-
const owner = await readMarkerFile(
|
|
37404
|
-
return owner !== void 0 ? owner : await readMarkerFile(
|
|
37188
|
+
const owner = await readMarkerFile(path17.join(dir, EXPORT_SOURCE_MARKER));
|
|
37189
|
+
return owner !== void 0 ? owner : await readMarkerFile(path17.join(dir, LEGACY_EXPORT_SOURCE_MARKER));
|
|
37405
37190
|
}
|
|
37406
37191
|
async function readMarkerFile(marker) {
|
|
37407
37192
|
for (let attempt = 0; ; attempt++) {
|
|
@@ -37438,7 +37223,7 @@ function occupiedBy(owner) {
|
|
|
37438
37223
|
async function takeExportDir(dir, flowPath) {
|
|
37439
37224
|
try {
|
|
37440
37225
|
await fsp.mkdir(dir, { recursive: true });
|
|
37441
|
-
await fsp.writeFile(
|
|
37226
|
+
await fsp.writeFile(path17.join(dir, EXPORT_SOURCE_MARKER), `${flowPath}
|
|
37442
37227
|
`, { flag: "wx" });
|
|
37443
37228
|
return null;
|
|
37444
37229
|
} catch (err) {
|
|
@@ -37457,7 +37242,7 @@ async function claimExportDirName(outputDir, flowPath, stem) {
|
|
|
37457
37242
|
}
|
|
37458
37243
|
const avoided = [];
|
|
37459
37244
|
for (const name of candidates) {
|
|
37460
|
-
const dir =
|
|
37245
|
+
const dir = path17.join(outputDir, name);
|
|
37461
37246
|
const claim2 = await classifyExportDir(dir, flowPath);
|
|
37462
37247
|
const reason = claim2.state === "foreign" ? occupiedBy(claim2.owner) : await takeExportDir(dir, flowPath);
|
|
37463
37248
|
if (reason !== null) {
|
|
@@ -37477,7 +37262,7 @@ async function claimExportDirName(outputDir, flowPath, stem) {
|
|
|
37477
37262
|
return null;
|
|
37478
37263
|
}
|
|
37479
37264
|
async function exportFailureArtifacts(report, outputDir, flowPath, ctx) {
|
|
37480
|
-
const stem =
|
|
37265
|
+
const stem = path17.basename(flowPath, ".yaml");
|
|
37481
37266
|
if (!SAFE_ARTIFACT_NAME.test(stem)) {
|
|
37482
37267
|
console.error(
|
|
37483
37268
|
`warning: skipping artifact export for unsafe e2e test filename ${JSON.stringify(stem)}`
|
|
@@ -37510,11 +37295,11 @@ async function exportFailureArtifacts(report, outputDir, flowPath, ctx) {
|
|
|
37510
37295
|
if (dir === null) {
|
|
37511
37296
|
const dirName = await claimExportDirName(outputDir, flowPath, stem);
|
|
37512
37297
|
if (dirName === null) return;
|
|
37513
|
-
dir =
|
|
37298
|
+
dir = path17.join(outputDir, dirName);
|
|
37514
37299
|
}
|
|
37515
|
-
const dest =
|
|
37516
|
-
const rel =
|
|
37517
|
-
if (rel.startsWith("..") ||
|
|
37300
|
+
const dest = path17.join(dir, fileName(role));
|
|
37301
|
+
const rel = path17.relative(outputDir, dest);
|
|
37302
|
+
if (rel.startsWith("..") || path17.isAbsolute(rel)) continue;
|
|
37518
37303
|
try {
|
|
37519
37304
|
await fsp.copyFile(value, dest);
|
|
37520
37305
|
s.artifacts[role] = dest;
|
|
@@ -37529,7 +37314,7 @@ async function exportFailureArtifacts(report, outputDir, flowPath, ctx) {
|
|
|
37529
37314
|
function keyFromBaselinePath(artifacts) {
|
|
37530
37315
|
const baseline = artifacts.baseline;
|
|
37531
37316
|
if (typeof baseline !== "string") return null;
|
|
37532
|
-
return
|
|
37317
|
+
return path17.basename(baseline).replace(/\.png$/, "");
|
|
37533
37318
|
}
|
|
37534
37319
|
function resolveArtifactDisplayPaths(report) {
|
|
37535
37320
|
for (const s of report.steps) {
|
|
@@ -37586,17 +37371,17 @@ async function collectRunnableFlowPaths(dir, relDir = "") {
|
|
|
37586
37371
|
const found = [];
|
|
37587
37372
|
const entries = await fsp.readdir(dir, { withFileTypes: true });
|
|
37588
37373
|
for (const entry of entries) {
|
|
37589
|
-
const rel = relDir ?
|
|
37374
|
+
const rel = relDir ? path17.join(relDir, entry.name) : entry.name;
|
|
37590
37375
|
if (entry.isDirectory()) {
|
|
37591
37376
|
if (entry.name === "__baselines__") continue;
|
|
37592
37377
|
found.push(
|
|
37593
|
-
...await collectRunnableFlowPaths(
|
|
37378
|
+
...await collectRunnableFlowPaths(path17.join(dir, entry.name), rel).catch(() => [])
|
|
37594
37379
|
);
|
|
37595
37380
|
continue;
|
|
37596
37381
|
}
|
|
37597
37382
|
if (!entry.name.endsWith(".yaml")) continue;
|
|
37598
|
-
if (!SAFE_FLOW_NAME.test(
|
|
37599
|
-
if (await isRunnableFlowFile(
|
|
37383
|
+
if (!SAFE_FLOW_NAME.test(path17.basename(entry.name, ".yaml"))) continue;
|
|
37384
|
+
if (await isRunnableFlowFile(path17.join(dir, entry.name))) found.push(rel);
|
|
37600
37385
|
}
|
|
37601
37386
|
return found;
|
|
37602
37387
|
}
|
|
@@ -37604,26 +37389,26 @@ async function resolveFlowRef(ref, projectRoot) {
|
|
|
37604
37389
|
if (!SAFE_FLOW_NAME.test(ref)) return { suppliedPath: ref, fromName: false };
|
|
37605
37390
|
const picked = await resolveE2eFile(projectRoot, ref);
|
|
37606
37391
|
return {
|
|
37607
|
-
suppliedPath:
|
|
37392
|
+
suppliedPath: path17.relative(projectRoot, picked.path),
|
|
37608
37393
|
fromName: true,
|
|
37609
|
-
...picked.shadowed === void 0 ? {} : { shadowed:
|
|
37394
|
+
...picked.shadowed === void 0 ? {} : { shadowed: path17.relative(projectRoot, picked.shadowed) }
|
|
37610
37395
|
};
|
|
37611
37396
|
}
|
|
37612
37397
|
async function savedFlowHint(projectRoot, missingPath) {
|
|
37613
|
-
const dirs = E2E_DIRS.map((rel) => ({ rel, abs:
|
|
37398
|
+
const dirs = E2E_DIRS.map((rel) => ({ rel, abs: path17.resolve(projectRoot, rel) }));
|
|
37614
37399
|
for (const { abs } of dirs) {
|
|
37615
|
-
const within =
|
|
37616
|
-
if (!within.startsWith("..") && !
|
|
37400
|
+
const within = path17.relative(abs, missingPath);
|
|
37401
|
+
if (!within.startsWith("..") && !path17.isAbsolute(within)) return "";
|
|
37617
37402
|
}
|
|
37618
|
-
const wanted = `${
|
|
37403
|
+
const wanted = `${path17.basename(missingPath, ".yaml")}.yaml`;
|
|
37619
37404
|
for (const { rel, abs } of dirs) {
|
|
37620
37405
|
const entries = await fsp.readdir(abs).catch(() => null);
|
|
37621
37406
|
if (entries === null) continue;
|
|
37622
37407
|
const actual = entries.includes(wanted) ? wanted : entries.find((name2) => name2.toLowerCase() === wanted.toLowerCase());
|
|
37623
37408
|
if (actual === void 0) continue;
|
|
37624
|
-
const name =
|
|
37409
|
+
const name = path17.basename(actual, ".yaml");
|
|
37625
37410
|
if (!SAFE_FLOW_NAME.test(name)) return "";
|
|
37626
|
-
if (!await isRunnableFlowFile(
|
|
37411
|
+
if (!await isRunnableFlowFile(path17.join(abs, actual))) return "";
|
|
37627
37412
|
return `
|
|
37628
37413
|
An e2e test named "${name}" is saved under ${rel} \u2014 did you mean: argent e2e run ${name}`;
|
|
37629
37414
|
}
|
|
@@ -37633,17 +37418,17 @@ async function collectFlowFiles(dir, recursive2) {
|
|
|
37633
37418
|
const found = [];
|
|
37634
37419
|
const walk = async (current, rel) => {
|
|
37635
37420
|
for (const entry of await fsp.readdir(current, { withFileTypes: true })) {
|
|
37636
|
-
const entryRel = rel ?
|
|
37421
|
+
const entryRel = rel ? path17.join(rel, entry.name) : entry.name;
|
|
37637
37422
|
if (entry.isDirectory()) {
|
|
37638
37423
|
if (recursive2 && !entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
37639
|
-
await walk(
|
|
37424
|
+
await walk(path17.join(current, entry.name), entryRel).catch(() => {
|
|
37640
37425
|
});
|
|
37641
37426
|
}
|
|
37642
37427
|
continue;
|
|
37643
37428
|
}
|
|
37644
37429
|
if (!entry.name.endsWith(".yaml")) continue;
|
|
37645
|
-
if (!SAFE_FLOW_NAME.test(
|
|
37646
|
-
if (await isRunnableFlowFile(
|
|
37430
|
+
if (!SAFE_FLOW_NAME.test(path17.basename(entry.name, ".yaml"))) continue;
|
|
37431
|
+
if (await isRunnableFlowFile(path17.join(current, entry.name))) found.push(entryRel);
|
|
37647
37432
|
}
|
|
37648
37433
|
};
|
|
37649
37434
|
await walk(dir, "");
|
|
@@ -37732,8 +37517,12 @@ function rejectionVerdict(code) {
|
|
|
37732
37517
|
case FAILURE_CODES.FLOW_ENTRY_UNRECOGNIZED:
|
|
37733
37518
|
case FAILURE_CODES.FLOW_E2E_HAS_PREREQUISITE:
|
|
37734
37519
|
return "not run (invalid e2e test)";
|
|
37520
|
+
case FAILURE_CODES.FLOW_FILE_NEWER_VERSION:
|
|
37521
|
+
return "not run (needs a newer Argent)";
|
|
37735
37522
|
case FAILURE_CODES.FLOW_DEVICE_RESOLUTION:
|
|
37736
37523
|
return "not run (no device resolved)";
|
|
37524
|
+
case FAILURE_CODES.FLOW_REQUIREMENTS_UNMET:
|
|
37525
|
+
return "not run (requires not met)";
|
|
37737
37526
|
case FAILURE_CODES.FILE_INPUT_UPLOAD_FAILED:
|
|
37738
37527
|
return "not run (upload failed)";
|
|
37739
37528
|
default:
|
|
@@ -37786,7 +37575,7 @@ async function runFlowDirectory(dir, args, projectRoot, options) {
|
|
|
37786
37575
|
);
|
|
37787
37576
|
}
|
|
37788
37577
|
const { callTool, baseUrl } = runToolsClient(args, options);
|
|
37789
|
-
const outputBase = args.output ?
|
|
37578
|
+
const outputBase = args.output ? path17.resolve(args.output) : void 0;
|
|
37790
37579
|
const results = [];
|
|
37791
37580
|
const failures = [];
|
|
37792
37581
|
const batchStartedAt = Date.now();
|
|
@@ -37799,7 +37588,7 @@ async function runFlowDirectory(dir, args, projectRoot, options) {
|
|
|
37799
37588
|
if (!args.json) console.log(` ${STATUS_GLYPH.skip} not run (batch stopped)`);
|
|
37800
37589
|
continue;
|
|
37801
37590
|
}
|
|
37802
|
-
const flowPath =
|
|
37591
|
+
const flowPath = path17.join(dir, rel);
|
|
37803
37592
|
const rerun = rerunCommand(flowPath, rel, projectRoot, args);
|
|
37804
37593
|
let report;
|
|
37805
37594
|
try {
|
|
@@ -37810,6 +37599,14 @@ async function runFlowDirectory(dir, args, projectRoot, options) {
|
|
|
37810
37599
|
const err = unreachableErr ?? thrown;
|
|
37811
37600
|
const message = err instanceof Error ? err.message : String(err);
|
|
37812
37601
|
const toolErr = err instanceof ToolInvocationError ? err : void 0;
|
|
37602
|
+
if (toolErr?.errorCode === FAILURE_CODES.FLOW_REQUIREMENTS_UNMET) {
|
|
37603
|
+
const reason = message.replace(/^\[Tool:[^\]]+\] /, "");
|
|
37604
|
+
results.push({ path: rel, status: "skip", reason });
|
|
37605
|
+
if (!args.json)
|
|
37606
|
+
console.log(` ${STATUS_GLYPH.skip} skipped (requires not met)
|
|
37607
|
+
${reason}`);
|
|
37608
|
+
continue;
|
|
37609
|
+
}
|
|
37813
37610
|
const rejectedThisFlowOnly = toolErr?.errorKind === "validation";
|
|
37814
37611
|
const verdict = unreachableErr ? UNREACHABLE_VERDICT : rejectedThisFlowOnly ? rejectionVerdict(toolErr?.errorCode) : "did not finish (run error)";
|
|
37815
37612
|
if (!args.json) console.log(` ${STATUS_GLYPH.error} ${verdict}`);
|
|
@@ -37833,7 +37630,7 @@ async function runFlowDirectory(dir, args, projectRoot, options) {
|
|
|
37833
37630
|
printWarnings(nestedStepWarnings(report.steps), args.json);
|
|
37834
37631
|
await exportAndResolveArtifacts(
|
|
37835
37632
|
report,
|
|
37836
|
-
outputBase ?
|
|
37633
|
+
outputBase ? path17.join(outputBase, path17.dirname(rel)) : void 0,
|
|
37837
37634
|
flowPath,
|
|
37838
37635
|
baseUrl
|
|
37839
37636
|
);
|
|
@@ -37860,11 +37657,18 @@ async function runFlowDirectory(dir, args, projectRoot, options) {
|
|
|
37860
37657
|
skipped: results.filter((r2) => r2.status === "skip").length
|
|
37861
37658
|
};
|
|
37862
37659
|
const durationMs = Date.now() - batchStartedAt;
|
|
37660
|
+
const noneRan = counts.passed === 0 && counts.failed === 0;
|
|
37863
37661
|
if (args.json) {
|
|
37864
37662
|
console.log(
|
|
37865
37663
|
JSON.stringify(
|
|
37866
37664
|
// `flows` is the deprecated spelling of `e2eTests`.
|
|
37867
|
-
{
|
|
37665
|
+
{
|
|
37666
|
+
ok: counts.failed === 0 && !noneRan,
|
|
37667
|
+
...counts,
|
|
37668
|
+
durationMs,
|
|
37669
|
+
e2eTests: results,
|
|
37670
|
+
flows: results
|
|
37671
|
+
},
|
|
37868
37672
|
null,
|
|
37869
37673
|
2
|
|
37870
37674
|
)
|
|
@@ -37873,8 +37677,9 @@ async function runFlowDirectory(dir, args, projectRoot, options) {
|
|
|
37873
37677
|
for (const line of renderFailedFlows(failures)) console.log(line);
|
|
37874
37678
|
console.log(`
|
|
37875
37679
|
${renderBatchSummary(counts, durationMs)}`);
|
|
37680
|
+
if (noneRan) console.error(`No e2e test in ${dir} ran on the selected target.`);
|
|
37876
37681
|
}
|
|
37877
|
-
return exitAfterFlush(unreachable ? 2 : counts.failed === 0 ? 0 : 1);
|
|
37682
|
+
return exitAfterFlush(unreachable || noneRan ? 2 : counts.failed === 0 ? 0 : 1);
|
|
37878
37683
|
}
|
|
37879
37684
|
async function e2e(argv, options) {
|
|
37880
37685
|
const [sub, ...rest] = argv;
|
|
@@ -37891,14 +37696,14 @@ async function e2e(argv, options) {
|
|
|
37891
37696
|
for (const dir of E2E_DIRS) {
|
|
37892
37697
|
let rels;
|
|
37893
37698
|
try {
|
|
37894
|
-
rels = (await collectRunnableFlowPaths(
|
|
37699
|
+
rels = (await collectRunnableFlowPaths(path17.join(process.cwd(), dir))).sort();
|
|
37895
37700
|
} catch {
|
|
37896
37701
|
continue;
|
|
37897
37702
|
}
|
|
37898
37703
|
anyDir = true;
|
|
37899
37704
|
for (const rel of rels) {
|
|
37900
|
-
const shown =
|
|
37901
|
-
const name =
|
|
37705
|
+
const shown = path17.join(dir, rel);
|
|
37706
|
+
const name = path17.dirname(rel) === "." ? path17.basename(rel, ".yaml") : void 0;
|
|
37902
37707
|
const usedByName = name === void 0 ? void 0 : byName.get(name);
|
|
37903
37708
|
if (name !== void 0 && usedByName === void 0) byName.set(name, shown);
|
|
37904
37709
|
lines.push(shown);
|
|
@@ -37969,10 +37774,10 @@ async function e2e(argv, options) {
|
|
|
37969
37774
|
}
|
|
37970
37775
|
if (suppliedPath.split(/[\\/]+/).includes("..")) {
|
|
37971
37776
|
let recovery = "Pass the fully resolved path to the e2e test's YAML.";
|
|
37972
|
-
const suppliedBase2 =
|
|
37777
|
+
const suppliedBase2 = path17.basename(suppliedPath);
|
|
37973
37778
|
if (suppliedBase2 !== ".." && suppliedBase2 !== ".") {
|
|
37974
37779
|
try {
|
|
37975
|
-
const resolved =
|
|
37780
|
+
const resolved = path17.join(await fsp.realpath(path17.dirname(suppliedPath)), suppliedBase2);
|
|
37976
37781
|
await fsp.stat(resolved);
|
|
37977
37782
|
recovery = `Did you mean: argent e2e run ${shellQuoteArg(resolved)}`;
|
|
37978
37783
|
} catch {
|
|
@@ -37984,7 +37789,7 @@ async function e2e(argv, options) {
|
|
|
37984
37789
|
2
|
|
37985
37790
|
);
|
|
37986
37791
|
}
|
|
37987
|
-
const resolvedPath =
|
|
37792
|
+
const resolvedPath = path17.resolve(projectRoot, suppliedPath);
|
|
37988
37793
|
let isDirectory = false;
|
|
37989
37794
|
try {
|
|
37990
37795
|
isDirectory = (await fsp.stat(resolvedPath)).isDirectory();
|
|
@@ -38007,16 +37812,16 @@ async function e2e(argv, options) {
|
|
|
38007
37812
|
}
|
|
38008
37813
|
const separatorTrimmedPath = suppliedPath.replace(/[\\/]+$/, "");
|
|
38009
37814
|
if (separatorTrimmedPath !== suppliedPath && separatorTrimmedPath !== "") {
|
|
38010
|
-
const hint = SAFE_FLOW_NAME.test(separatorTrimmedPath) ? `.${
|
|
37815
|
+
const hint = SAFE_FLOW_NAME.test(separatorTrimmedPath) ? `.${path17.sep}${separatorTrimmedPath}` : separatorTrimmedPath;
|
|
38011
37816
|
return fail(
|
|
38012
37817
|
`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}
|
|
38013
37818
|
Did you mean: argent e2e run ${shellQuoteArg(hint)}`,
|
|
38014
37819
|
2
|
|
38015
37820
|
);
|
|
38016
37821
|
}
|
|
38017
|
-
if (
|
|
38018
|
-
const looksLikeName = !suppliedPath.includes("/") && !suppliedPath.includes("\\") &&
|
|
38019
|
-
if (
|
|
37822
|
+
if (path17.extname(suppliedPath) !== ".yaml") {
|
|
37823
|
+
const looksLikeName = !suppliedPath.includes("/") && !suppliedPath.includes("\\") && path17.extname(suppliedPath) === "";
|
|
37824
|
+
if (path17.basename(suppliedPath).toLowerCase() === ".yaml") {
|
|
38020
37825
|
return fail(
|
|
38021
37826
|
`E2E test filename must have a non-empty name containing only letters, numbers, "_", or "-": ${suppliedPath}`,
|
|
38022
37827
|
2
|
|
@@ -38029,15 +37834,15 @@ Names run \`${E2E_DIRS.map((dir) => `${dir}/<name>.yaml`).join("` or `")}\`; pas
|
|
|
38029
37834
|
2
|
|
38030
37835
|
);
|
|
38031
37836
|
}
|
|
38032
|
-
if (
|
|
37837
|
+
if (path17.extname(suppliedPath).toLowerCase() === ".yaml") {
|
|
38033
37838
|
return fail(
|
|
38034
|
-
`E2E test extension must be lowercase .yaml, not ${
|
|
37839
|
+
`E2E test extension must be lowercase .yaml, not ${path17.extname(suppliedPath)}: ${suppliedPath}`,
|
|
38035
37840
|
2
|
|
38036
37841
|
);
|
|
38037
37842
|
}
|
|
38038
37843
|
return fail(`E2E test path must end in .yaml: ${suppliedPath}`, 2);
|
|
38039
37844
|
}
|
|
38040
|
-
const flowName =
|
|
37845
|
+
const flowName = path17.basename(suppliedPath, ".yaml");
|
|
38041
37846
|
if (!SAFE_FLOW_NAME.test(flowName)) {
|
|
38042
37847
|
return fail(
|
|
38043
37848
|
`E2E test filename must have a non-empty name containing only letters, numbers, "_", or "-": ${suppliedPath}`,
|
|
@@ -38061,12 +37866,12 @@ No e2e test named "${args.flowRef}" is saved in ${E2E_DIRS.join(" or ")} \u2014
|
|
|
38061
37866
|
}
|
|
38062
37867
|
return fail(`${detail}: ${flowPath}${recovery}`, 2);
|
|
38063
37868
|
}
|
|
38064
|
-
const suppliedBase =
|
|
38065
|
-
const siblings = await fsp.readdir(
|
|
37869
|
+
const suppliedBase = path17.basename(flowPath);
|
|
37870
|
+
const siblings = await fsp.readdir(path17.dirname(flowPath)).catch(() => null);
|
|
38066
37871
|
if (siblings !== null && !siblings.includes(suppliedBase)) {
|
|
38067
37872
|
const actual = siblings.find((name) => name.toLowerCase() === suppliedBase.toLowerCase());
|
|
38068
|
-
const actualRunnable = actual !== void 0 &&
|
|
38069
|
-
const recovery = actualRunnable ? fromName ? `Did you mean: argent e2e run ${
|
|
37873
|
+
const actualRunnable = actual !== void 0 && path17.extname(actual) === ".yaml" && SAFE_FLOW_NAME.test(path17.basename(actual, ".yaml"));
|
|
37874
|
+
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.";
|
|
38070
37875
|
return fail(
|
|
38071
37876
|
`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}
|
|
38072
37877
|
${recovery}`,
|
|
@@ -38125,7 +37930,7 @@ ${recovery}`,
|
|
|
38125
37930
|
try {
|
|
38126
37931
|
await exportAndResolveArtifacts(
|
|
38127
37932
|
report,
|
|
38128
|
-
args.output ?
|
|
37933
|
+
args.output ? path17.resolve(args.output) : void 0,
|
|
38129
37934
|
flowPath,
|
|
38130
37935
|
baseUrl
|
|
38131
37936
|
);
|
|
@@ -38154,6 +37959,313 @@ ${renderSummary(report, { withDevice: true })}`);
|
|
|
38154
37959
|
return exitAfterFlush(report.ok && unwritten.length === 0 ? 0 : 1);
|
|
38155
37960
|
}
|
|
38156
37961
|
|
|
37962
|
+
// ../argent-cli/src/run.ts
|
|
37963
|
+
function splitOptions(argv) {
|
|
37964
|
+
let json2 = false;
|
|
37965
|
+
let outPath = null;
|
|
37966
|
+
const rest = [];
|
|
37967
|
+
for (let i2 = 0; i2 < argv.length; i2++) {
|
|
37968
|
+
const tok = argv[i2];
|
|
37969
|
+
if (tok === "--json") {
|
|
37970
|
+
json2 = true;
|
|
37971
|
+
continue;
|
|
37972
|
+
}
|
|
37973
|
+
if (tok === "--out") {
|
|
37974
|
+
const v = argv[i2 + 1];
|
|
37975
|
+
if (!v) throw new FlagParseException("--out requires a path");
|
|
37976
|
+
outPath = v;
|
|
37977
|
+
i2 += 1;
|
|
37978
|
+
continue;
|
|
37979
|
+
}
|
|
37980
|
+
if (tok.startsWith("--out=")) {
|
|
37981
|
+
outPath = tok.slice("--out=".length);
|
|
37982
|
+
continue;
|
|
37983
|
+
}
|
|
37984
|
+
rest.push(tok);
|
|
37985
|
+
}
|
|
37986
|
+
return { json: json2, outPath, argvForFlags: rest };
|
|
37987
|
+
}
|
|
37988
|
+
async function readStdin() {
|
|
37989
|
+
return new Promise((resolve13, reject) => {
|
|
37990
|
+
let data = "";
|
|
37991
|
+
process.stdin.setEncoding("utf8");
|
|
37992
|
+
process.stdin.on("data", (chunk) => {
|
|
37993
|
+
data += chunk;
|
|
37994
|
+
});
|
|
37995
|
+
process.stdin.on("end", () => resolve13(data));
|
|
37996
|
+
process.stdin.on("error", reject);
|
|
37997
|
+
});
|
|
37998
|
+
}
|
|
37999
|
+
function printToolHelp(meta3) {
|
|
38000
|
+
const description = meta3.description?.trim() ?? "";
|
|
38001
|
+
const schema = meta3.inputSchema;
|
|
38002
|
+
const hasOwnArgsField = schema?.properties?.args !== void 0;
|
|
38003
|
+
console.log(`argent run ${meta3.name} [flags]`);
|
|
38004
|
+
if (description) console.log(`
|
|
38005
|
+
${description}
|
|
38006
|
+
`);
|
|
38007
|
+
console.log("Flags:");
|
|
38008
|
+
console.log(formatSchemaUsage(schema));
|
|
38009
|
+
console.log("\nGlobal flags:");
|
|
38010
|
+
if (!hasOwnArgsField) {
|
|
38011
|
+
console.log(" --args <json> Pass the entire payload as JSON (overrides flags)");
|
|
38012
|
+
console.log(" --args - Read the entire payload as JSON from stdin");
|
|
38013
|
+
}
|
|
38014
|
+
console.log(" --<field>-json <json> Pass a single field as JSON (objects/nested arrays)");
|
|
38015
|
+
console.log(" --json Print the raw JSON result");
|
|
38016
|
+
console.log(" --out <path> For image results, save to <path> instead of fetching URL");
|
|
38017
|
+
console.log(" --help, -h Show this help");
|
|
38018
|
+
}
|
|
38019
|
+
async function fetchImageToFile(result, outPath) {
|
|
38020
|
+
const url2 = result.url;
|
|
38021
|
+
if (!url2) {
|
|
38022
|
+
throw new Error("Tool result did not include a `url`; cannot save image");
|
|
38023
|
+
}
|
|
38024
|
+
const res = await fetch(url2);
|
|
38025
|
+
if (!res.ok) throw new Error(`Failed to download image: ${res.status} ${res.statusText}`);
|
|
38026
|
+
const buf = Buffer.from(await res.arrayBuffer());
|
|
38027
|
+
fs12.mkdirSync(path18.dirname(path18.resolve(outPath)), { recursive: true });
|
|
38028
|
+
fs12.writeFileSync(outPath, buf);
|
|
38029
|
+
}
|
|
38030
|
+
function renderResult(result, outputHint, images, json2) {
|
|
38031
|
+
if (json2) return JSON.stringify(result, null, 2);
|
|
38032
|
+
if (outputHint === "image") {
|
|
38033
|
+
if (images.length > 0) return `Saved screenshot: ${images[0].localPath}`;
|
|
38034
|
+
if (result && typeof result === "object" && "path" in result && typeof result.path === "string") {
|
|
38035
|
+
return `Saved screenshot: ${result.path}`;
|
|
38036
|
+
}
|
|
38037
|
+
}
|
|
38038
|
+
if (typeof result === "string") return result;
|
|
38039
|
+
return JSON.stringify(result, null, 2);
|
|
38040
|
+
}
|
|
38041
|
+
var SAFE_TOOL_RE = /^[a-z][a-z0-9_-]{0,63}$/;
|
|
38042
|
+
function safeToolName(toolName) {
|
|
38043
|
+
return toolName && SAFE_TOOL_RE.test(toolName) ? toolName : "unknown";
|
|
38044
|
+
}
|
|
38045
|
+
async function trackRunFailure(toolName, startedAt, signal) {
|
|
38046
|
+
const tool = toolName ? canonicalToolId(toolName) : toolName;
|
|
38047
|
+
track("cli:run_fail", {
|
|
38048
|
+
tool: safeToolName(tool),
|
|
38049
|
+
...tool !== toolName ? { alias_used: true } : {},
|
|
38050
|
+
duration_ms: performance.now() - startedAt,
|
|
38051
|
+
...signal
|
|
38052
|
+
});
|
|
38053
|
+
await shutdown();
|
|
38054
|
+
}
|
|
38055
|
+
async function run(argv, options) {
|
|
38056
|
+
init("cli");
|
|
38057
|
+
const startedAt = performance.now();
|
|
38058
|
+
const { fetchTool, callTool, baseUrl } = createToolsClient({ paths: options.paths });
|
|
38059
|
+
const [toolName, ...rest] = argv;
|
|
38060
|
+
if (!toolName || toolName === "--help" || toolName === "-h") {
|
|
38061
|
+
console.log(`Usage: argent run <tool> [flags]
|
|
38062
|
+
|
|
38063
|
+
Invoke a tool exposed by the argent tool-server. Run \`argent tools\` to list
|
|
38064
|
+
available tools, or \`argent tools describe <name>\` to see one tool's flags.
|
|
38065
|
+
|
|
38066
|
+
Examples:
|
|
38067
|
+
argent run list-devices
|
|
38068
|
+
argent run gesture-tap --udid <UDID> --x 0.5 --y 0.5
|
|
38069
|
+
argent run screenshot --udid <UDID> --out ./screen.png
|
|
38070
|
+
argent run run-sequence --udid <UDID> --steps-json '[{"tool":"button","args":{"button":"home"}}]'
|
|
38071
|
+
argent run gesture-tap --args '{"udid":"<UDID>","x":0.5,"y":0.5}'
|
|
38072
|
+
|
|
38073
|
+
Exits 1 when the tool fails. Also exits 1 when the result reports that the
|
|
38074
|
+
call did not do its job: an e2e test that does not pass, an await-ui-element
|
|
38075
|
+
wait with success=false, a run-sequence that a step stopped, a debugger tool
|
|
38076
|
+
with no connection or an error, a native-devtools precheck that stopped the
|
|
38077
|
+
tool, a native-profiler-analyze with status analysis_failed, an e2e recording
|
|
38078
|
+
call that recorded nothing, or a baseline that was not written on this client.
|
|
38079
|
+
Other results exit 0, also a negative answer such as await-screen-idle's
|
|
38080
|
+
settled=false or debugger-status's not_connected.
|
|
38081
|
+
`);
|
|
38082
|
+
return;
|
|
38083
|
+
}
|
|
38084
|
+
let cliOptions;
|
|
38085
|
+
try {
|
|
38086
|
+
cliOptions = splitOptions(rest);
|
|
38087
|
+
} catch (err) {
|
|
38088
|
+
if (err instanceof FlagParseException) {
|
|
38089
|
+
console.error(`Error: ${err.message}
|
|
38090
|
+
`);
|
|
38091
|
+
console.error(`Run \`argent run ${toolName} --help\` to see this tool's flags.`);
|
|
38092
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38093
|
+
error_code: FAILURE_CODES.CLI_RUN_FLAG_PARSE_FAILED,
|
|
38094
|
+
failure_stage: "cli_run_split_options",
|
|
38095
|
+
failure_area: "cli",
|
|
38096
|
+
error_kind: "validation"
|
|
38097
|
+
});
|
|
38098
|
+
process.exit(2);
|
|
38099
|
+
}
|
|
38100
|
+
throw err;
|
|
38101
|
+
}
|
|
38102
|
+
const { json: json2, outPath, argvForFlags } = cliOptions;
|
|
38103
|
+
const meta3 = await fetchTool(toolName);
|
|
38104
|
+
if (!meta3) {
|
|
38105
|
+
console.error(`Tool "${toolName}" not found. Run \`argent tools\` to list available tools.`);
|
|
38106
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38107
|
+
error_code: FAILURE_CODES.CLI_RUN_TOOL_NOT_FOUND,
|
|
38108
|
+
failure_stage: "cli_run_fetch_tool",
|
|
38109
|
+
failure_area: "cli",
|
|
38110
|
+
error_kind: "not_found"
|
|
38111
|
+
});
|
|
38112
|
+
process.exit(1);
|
|
38113
|
+
}
|
|
38114
|
+
const schema = meta3.inputSchema;
|
|
38115
|
+
const failInvocation = async (summary, report, failure3) => {
|
|
38116
|
+
if (json2) {
|
|
38117
|
+
console.error(
|
|
38118
|
+
JSON.stringify(
|
|
38119
|
+
{
|
|
38120
|
+
error: summary,
|
|
38121
|
+
missing: report ? missingFlagNames(report, schema) : [],
|
|
38122
|
+
issues: report?.rawIssues ?? []
|
|
38123
|
+
},
|
|
38124
|
+
null,
|
|
38125
|
+
2
|
|
38126
|
+
)
|
|
38127
|
+
);
|
|
38128
|
+
} else {
|
|
38129
|
+
console.error(`Error: ${summary}
|
|
38130
|
+
`);
|
|
38131
|
+
printToolHelp(meta3);
|
|
38132
|
+
}
|
|
38133
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38134
|
+
...failure3,
|
|
38135
|
+
failure_area: "cli",
|
|
38136
|
+
error_kind: "validation"
|
|
38137
|
+
});
|
|
38138
|
+
process.exit(2);
|
|
38139
|
+
};
|
|
38140
|
+
const failValidation = (report, stage) => failInvocation(formatValidationError(report, schema), report, {
|
|
38141
|
+
error_code: FAILURE_CODES.CLI_RUN_INPUT_VALIDATION_FAILED,
|
|
38142
|
+
failure_stage: stage
|
|
38143
|
+
});
|
|
38144
|
+
let parsed;
|
|
38145
|
+
try {
|
|
38146
|
+
parsed = parseFlags(argvForFlags, schema);
|
|
38147
|
+
} catch (err) {
|
|
38148
|
+
if (err instanceof FlagParseException) {
|
|
38149
|
+
await failInvocation(err.message, null, {
|
|
38150
|
+
error_code: FAILURE_CODES.CLI_RUN_FLAG_PARSE_FAILED,
|
|
38151
|
+
failure_stage: "cli_run_parse_flags"
|
|
38152
|
+
});
|
|
38153
|
+
}
|
|
38154
|
+
throw err;
|
|
38155
|
+
}
|
|
38156
|
+
if (parsed.helpRequested) {
|
|
38157
|
+
printToolHelp(meta3);
|
|
38158
|
+
return;
|
|
38159
|
+
}
|
|
38160
|
+
if (parsed.positional.length > 0) {
|
|
38161
|
+
console.error(
|
|
38162
|
+
`Note: ignoring unused argument(s): ${parsed.positional.join(", ")}. Pass values as --flag <value> or --flag=<value>.`
|
|
38163
|
+
);
|
|
38164
|
+
}
|
|
38165
|
+
let payload = {};
|
|
38166
|
+
if (parsed.rawArgs !== null) {
|
|
38167
|
+
let rawJson = parsed.rawArgs;
|
|
38168
|
+
if (rawJson === "-") {
|
|
38169
|
+
rawJson = await readStdin();
|
|
38170
|
+
}
|
|
38171
|
+
try {
|
|
38172
|
+
const parsedRaw = JSON.parse(rawJson);
|
|
38173
|
+
if (parsedRaw === null || typeof parsedRaw !== "object" || Array.isArray(parsedRaw)) {
|
|
38174
|
+
console.error("--args must be a JSON object");
|
|
38175
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38176
|
+
error_code: FAILURE_CODES.CLI_RUN_ARGS_NOT_OBJECT,
|
|
38177
|
+
failure_stage: "cli_run_parse_raw_args",
|
|
38178
|
+
failure_area: "cli",
|
|
38179
|
+
error_kind: "validation"
|
|
38180
|
+
});
|
|
38181
|
+
process.exit(2);
|
|
38182
|
+
}
|
|
38183
|
+
payload = parsedRaw;
|
|
38184
|
+
} catch (err) {
|
|
38185
|
+
console.error(`--args is not valid JSON: ${err instanceof Error ? err.message : err}`);
|
|
38186
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38187
|
+
error_code: FAILURE_CODES.CLI_RUN_ARGS_JSON_INVALID,
|
|
38188
|
+
failure_stage: "cli_run_parse_raw_args",
|
|
38189
|
+
failure_area: "cli",
|
|
38190
|
+
error_kind: "validation"
|
|
38191
|
+
});
|
|
38192
|
+
process.exit(2);
|
|
38193
|
+
}
|
|
38194
|
+
}
|
|
38195
|
+
for (const [k, v] of Object.entries(parsed.args)) {
|
|
38196
|
+
payload[k] = v;
|
|
38197
|
+
}
|
|
38198
|
+
const missing = findMissingRequired(payload, schema);
|
|
38199
|
+
if (missing.length > 0) {
|
|
38200
|
+
await failValidation({ missing, invalid: [], rawIssues: null }, "cli_run_required_flags");
|
|
38201
|
+
}
|
|
38202
|
+
let result;
|
|
38203
|
+
let note;
|
|
38204
|
+
let failure2;
|
|
38205
|
+
let images = [];
|
|
38206
|
+
try {
|
|
38207
|
+
const resp = await callTool(toolName, payload);
|
|
38208
|
+
const { url: url2, token } = await baseUrl();
|
|
38209
|
+
const materialized = await materializeArtifacts(resp.data, {
|
|
38210
|
+
toolsUrl: url2,
|
|
38211
|
+
authToken: token,
|
|
38212
|
+
deviceId: getDeviceIdFromArgs(payload)
|
|
38213
|
+
});
|
|
38214
|
+
result = materialized.result;
|
|
38215
|
+
images = materialized.images;
|
|
38216
|
+
note = resp.note;
|
|
38217
|
+
failure2 = resp.failure;
|
|
38218
|
+
} catch (err) {
|
|
38219
|
+
const report = describeServerValidationFailure(err, payload, schema);
|
|
38220
|
+
if (report) {
|
|
38221
|
+
await failValidation(report, "cli_run_server_validation");
|
|
38222
|
+
}
|
|
38223
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
38224
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38225
|
+
error_code: FAILURE_CODES.CLI_RUN_TOOL_CALL_FAILED,
|
|
38226
|
+
failure_stage: "cli_run_call_tool",
|
|
38227
|
+
failure_area: "cli",
|
|
38228
|
+
error_kind: "unknown"
|
|
38229
|
+
});
|
|
38230
|
+
process.exit(1);
|
|
38231
|
+
}
|
|
38232
|
+
if (outPath && meta3.outputHint === "image") {
|
|
38233
|
+
try {
|
|
38234
|
+
if (images.length > 0) {
|
|
38235
|
+
fs12.mkdirSync(path18.dirname(path18.resolve(outPath)), { recursive: true });
|
|
38236
|
+
fs12.writeFileSync(outPath, images[0].data);
|
|
38237
|
+
} else if (result && typeof result === "object") {
|
|
38238
|
+
await fetchImageToFile(result, outPath);
|
|
38239
|
+
}
|
|
38240
|
+
} catch (err) {
|
|
38241
|
+
console.error(`Failed to save image: ${err instanceof Error ? err.message : err}`);
|
|
38242
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38243
|
+
error_code: FAILURE_CODES.CLI_RUN_SAVE_IMAGE_FAILED,
|
|
38244
|
+
failure_stage: "cli_run_save_image",
|
|
38245
|
+
failure_area: "cli",
|
|
38246
|
+
error_kind: "unknown"
|
|
38247
|
+
});
|
|
38248
|
+
process.exit(1);
|
|
38249
|
+
}
|
|
38250
|
+
}
|
|
38251
|
+
if (note) console.error(note);
|
|
38252
|
+
console.log(renderResult(result, meta3.outputHint, images, json2));
|
|
38253
|
+
if (outPath && meta3.outputHint === "image" && !json2) {
|
|
38254
|
+
console.log(`Wrote: ${outPath}`);
|
|
38255
|
+
}
|
|
38256
|
+
if (failure2) {
|
|
38257
|
+
await new Promise((resolve13) => process.stdout.write("", () => resolve13()));
|
|
38258
|
+
console.error(failure2);
|
|
38259
|
+
await trackRunFailure(toolName, startedAt, {
|
|
38260
|
+
error_code: FAILURE_CODES.CLI_RUN_TOOL_RESULT_FAILED,
|
|
38261
|
+
failure_stage: "cli_run_tool_result",
|
|
38262
|
+
failure_area: "cli",
|
|
38263
|
+
error_kind: "unknown"
|
|
38264
|
+
});
|
|
38265
|
+
await exitAfterFlush(1, [process.stderr]);
|
|
38266
|
+
}
|
|
38267
|
+
}
|
|
38268
|
+
|
|
38157
38269
|
// ../argent-cli/src/tools.ts
|
|
38158
38270
|
function summarize(description, max = 80) {
|
|
38159
38271
|
if (!description) return "";
|