@swmansion/argent 0.31.2-next.1 → 0.31.2-next.3
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/bin/argent-android-devtools-0.3.0.apk +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/tcp/ax-service +0 -0
- package/dist/cli-cmds.mjs +94 -24
- package/dist/client.js +71 -14
- package/dist/installer.mjs +13 -1
- package/dist/mcp-server.mjs +75 -17
- package/dist/tool-args.generated.d.ts +15 -7
- package/dist/tool-server.cjs +183 -85
- package/dylibs/libArgentInjectionBootstrap.dylib +0 -0
- package/dylibs/libKeyboardPatch.dylib +0 -0
- package/dylibs/libNativeDevtoolsIos.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 +1 -1
- package/skills/argent-create-e2e/references/live-authoring.md +3 -3
package/dist/mcp-server.mjs
CHANGED
|
@@ -25593,6 +25593,36 @@ var TOOL_ID_ALIASES = Object.freeze({
|
|
|
25593
25593
|
function canonicalToolId(id) {
|
|
25594
25594
|
return Object.hasOwn(TOOL_ID_ALIASES, id) ? TOOL_ID_ALIASES[id] : id;
|
|
25595
25595
|
}
|
|
25596
|
+
var TOOL_PARAM_ALIASES = Object.freeze({
|
|
25597
|
+
"e2e-execute": Object.freeze({ flow_path: "e2e_test_path", flow_file: "e2e_test_file" }),
|
|
25598
|
+
"e2e-read-prerequisite": Object.freeze({
|
|
25599
|
+
flow_path: "e2e_test_path",
|
|
25600
|
+
flow_file: "e2e_test_file"
|
|
25601
|
+
})
|
|
25602
|
+
});
|
|
25603
|
+
var ToolParamAliasError = class extends Error {
|
|
25604
|
+
constructor(former, current) {
|
|
25605
|
+
super(`Pass ${current} or its former name ${former}, not both.`);
|
|
25606
|
+
this.name = "ToolParamAliasError";
|
|
25607
|
+
}
|
|
25608
|
+
};
|
|
25609
|
+
function toolParamAliases(tool) {
|
|
25610
|
+
const id = canonicalToolId(tool);
|
|
25611
|
+
return Object.hasOwn(TOOL_PARAM_ALIASES, id) ? TOOL_PARAM_ALIASES[id] : {};
|
|
25612
|
+
}
|
|
25613
|
+
function canonicalToolArgs(tool, args) {
|
|
25614
|
+
if (typeof args !== "object" || args === null || Array.isArray(args)) return args;
|
|
25615
|
+
const record2 = args;
|
|
25616
|
+
let out;
|
|
25617
|
+
for (const [former, current] of Object.entries(toolParamAliases(tool))) {
|
|
25618
|
+
if (record2[former] === void 0) continue;
|
|
25619
|
+
if (record2[current] !== void 0) throw new ToolParamAliasError(former, current);
|
|
25620
|
+
out ??= { ...record2 };
|
|
25621
|
+
out[current] = out[former];
|
|
25622
|
+
delete out[former];
|
|
25623
|
+
}
|
|
25624
|
+
return out ?? args;
|
|
25625
|
+
}
|
|
25596
25626
|
|
|
25597
25627
|
// ../registry/src/flow-file-refs.ts
|
|
25598
25628
|
async function canonicalFlowPath(p) {
|
|
@@ -25662,7 +25692,13 @@ async function classifyOnDiskSpelling(dir, base, addressable = FLOW_FILE_NAME_PA
|
|
|
25662
25692
|
}
|
|
25663
25693
|
function nestedFlowTarget(args) {
|
|
25664
25694
|
if (typeof args !== "object" || args === null || Array.isArray(args)) return void 0;
|
|
25665
|
-
|
|
25695
|
+
let canonical;
|
|
25696
|
+
try {
|
|
25697
|
+
canonical = canonicalToolArgs("e2e-execute", args);
|
|
25698
|
+
} catch {
|
|
25699
|
+
return void 0;
|
|
25700
|
+
}
|
|
25701
|
+
const { name, project_root: projectRoot, e2e_test_path: flowPath } = canonical;
|
|
25666
25702
|
if (flowPath === void 0) {
|
|
25667
25703
|
if (typeof name !== "string" || !FLOW_NAME_PATTERN.test(name)) return void 0;
|
|
25668
25704
|
if (!isResolvedAbsolute(projectRoot)) return void 0;
|
|
@@ -25671,7 +25707,7 @@ function nestedFlowTarget(args) {
|
|
|
25671
25707
|
}
|
|
25672
25708
|
if (name !== void 0 || !isResolvedAbsolute(flowPath)) return void 0;
|
|
25673
25709
|
if (!FLOW_FILE_NAME_PATTERN.test(path8.basename(flowPath))) return void 0;
|
|
25674
|
-
return { kind: "
|
|
25710
|
+
return { kind: "e2e_test_path", path: flowPath };
|
|
25675
25711
|
}
|
|
25676
25712
|
function isResolvedAbsolute(value) {
|
|
25677
25713
|
return typeof value === "string" && path8.isAbsolute(value) && !value.split(/[\\/]+/).includes("..");
|
|
@@ -26611,12 +26647,18 @@ function isResolvedAbsolute2(value) {
|
|
|
26611
26647
|
return typeof value === "string" && path11.isAbsolute(value) && !value.split(/[\\/]+/).includes("..");
|
|
26612
26648
|
}
|
|
26613
26649
|
function namesValidFlow(args) {
|
|
26614
|
-
|
|
26650
|
+
let canonical;
|
|
26651
|
+
try {
|
|
26652
|
+
canonical = canonicalToolArgs("e2e-execute", args);
|
|
26653
|
+
} catch {
|
|
26654
|
+
return false;
|
|
26655
|
+
}
|
|
26656
|
+
const { project_root, e2e_test_path: testPath, name } = canonical;
|
|
26615
26657
|
if (!isResolvedAbsolute2(project_root)) return false;
|
|
26616
26658
|
if (name === void 0) {
|
|
26617
|
-
return isResolvedAbsolute2(
|
|
26659
|
+
return isResolvedAbsolute2(testPath) && FLOW_FILE_NAME_PATTERN.test(path11.basename(testPath));
|
|
26618
26660
|
}
|
|
26619
|
-
return
|
|
26661
|
+
return testPath === void 0 && typeof name === "string" && FLOW_NAME_PATTERN.test(name);
|
|
26620
26662
|
}
|
|
26621
26663
|
function savedFlowProject(file) {
|
|
26622
26664
|
if (!path11.isAbsolute(file)) return null;
|
|
@@ -26790,8 +26832,8 @@ function memberCollector(roots, opts) {
|
|
|
26790
26832
|
`));
|
|
26791
26833
|
const emit = (member, sent) => {
|
|
26792
26834
|
members2.push(member);
|
|
26793
|
-
const subject = member.role === "flow" ? member.canonical : member.key;
|
|
26794
|
-
if (logging) log(printable(`[
|
|
26835
|
+
const [label, subject] = member.role === "flow" ? ["e2e test", member.canonical] : [member.role, member.key];
|
|
26836
|
+
if (logging) log(printable(`[e2e-files] ${label} ${subject}: ${sent}`));
|
|
26795
26837
|
};
|
|
26796
26838
|
async function flow(anchorDir, target, onlyPresent) {
|
|
26797
26839
|
const key = flowMemberKey(anchorDir, target);
|
|
@@ -26957,7 +26999,7 @@ function recordedStep(args) {
|
|
|
26957
26999
|
if (typeof text !== "string") return void 0;
|
|
26958
27000
|
let parsed;
|
|
26959
27001
|
try {
|
|
26960
|
-
parsed = JSON.parse(text);
|
|
27002
|
+
parsed = canonicalToolArgs(command, JSON.parse(text));
|
|
26961
27003
|
} catch {
|
|
26962
27004
|
return void 0;
|
|
26963
27005
|
}
|
|
@@ -26980,7 +27022,7 @@ async function collectStepMembers(args, opts, recordingDirFor = e2eDirFor) {
|
|
|
26980
27022
|
const self = await collector.flow(path11.dirname(recording), path11.basename(recording));
|
|
26981
27023
|
let runArgs = step.args;
|
|
26982
27024
|
const named = nestedFlowTarget(runArgs);
|
|
26983
|
-
if (named?.kind === "
|
|
27025
|
+
if (named?.kind === "e2e_test_path") {
|
|
26984
27026
|
const stem = path11.basename(named.path, ".yaml");
|
|
26985
27027
|
const base = path11.basename(named.path);
|
|
26986
27028
|
const dir = path11.resolve(path11.dirname(named.path));
|
|
@@ -26989,7 +27031,7 @@ async function collectStepMembers(args, opts, recordingDirFor = e2eDirFor) {
|
|
|
26989
27031
|
if (dirs.some((d) => path11.resolve(d) === dir)) {
|
|
26990
27032
|
await collector.flow(path11.dirname(named.path), base);
|
|
26991
27033
|
runArgs = { ...runArgs, name: stem };
|
|
26992
|
-
delete runArgs.
|
|
27034
|
+
delete runArgs.e2e_test_path;
|
|
26993
27035
|
}
|
|
26994
27036
|
}
|
|
26995
27037
|
const target = nestedFlowTarget(runArgs);
|
|
@@ -27017,7 +27059,21 @@ async function nameToE2ePathForOlderServer(tool, fileInputs, args) {
|
|
|
27017
27059
|
const picked = await pickE2eFile(target.paths);
|
|
27018
27060
|
if (!picked.exists || picked.legacy) return args;
|
|
27019
27061
|
const { name: _name, ...rest } = args;
|
|
27020
|
-
return { ...rest,
|
|
27062
|
+
return { ...rest, e2e_test_path: picked.path };
|
|
27063
|
+
}
|
|
27064
|
+
function formerParamsForOlderServer(meta2, args) {
|
|
27065
|
+
const listed = meta2.inputSchema.properties;
|
|
27066
|
+
if (typeof args !== "object" || args === null || Array.isArray(args)) return args;
|
|
27067
|
+
if (typeof listed !== "object" || listed === null) return args;
|
|
27068
|
+
const record2 = args;
|
|
27069
|
+
let out;
|
|
27070
|
+
for (const [former, current] of Object.entries(toolParamAliases(meta2.name))) {
|
|
27071
|
+
if (record2[current] === void 0 || current in listed || !(former in listed)) continue;
|
|
27072
|
+
out ??= { ...record2 };
|
|
27073
|
+
out[former] = out[current];
|
|
27074
|
+
delete out[current];
|
|
27075
|
+
}
|
|
27076
|
+
return out ?? args;
|
|
27021
27077
|
}
|
|
27022
27078
|
async function stepForOlderServer(args, listedId) {
|
|
27023
27079
|
if (typeof args !== "object" || args === null || Array.isArray(args)) return args;
|
|
@@ -27275,12 +27331,13 @@ function createToolsClient(options = {}) {
|
|
|
27275
27331
|
async function callTool(name, args, opts) {
|
|
27276
27332
|
opts?.signal?.throwIfAborted();
|
|
27277
27333
|
const { url, token, remote } = await route();
|
|
27278
|
-
let finalArgs = args;
|
|
27334
|
+
let finalArgs = canonicalToolArgs(name, args);
|
|
27279
27335
|
const tools = await fetchTools({ signal: opts?.signal });
|
|
27280
27336
|
const meta2 = findTool(tools, name);
|
|
27281
27337
|
const olderServer = meta2 !== null && !tools.some((t) => t.name === canonicalToolId(meta2.name));
|
|
27282
27338
|
if (meta2) {
|
|
27283
|
-
finalArgs = await nameToE2ePathForOlderServer(meta2.name, meta2.fileInputs,
|
|
27339
|
+
finalArgs = await nameToE2ePathForOlderServer(meta2.name, meta2.fileInputs, finalArgs);
|
|
27340
|
+
finalArgs = formerParamsForOlderServer(meta2, finalArgs);
|
|
27284
27341
|
}
|
|
27285
27342
|
if (olderServer && canonicalToolId(meta2.name) === "e2e-add-step") {
|
|
27286
27343
|
finalArgs = await stepForOlderServer(finalArgs, (tool) => findTool(tools, tool)?.name);
|
|
@@ -27308,7 +27365,7 @@ function createToolsClient(options = {}) {
|
|
|
27308
27365
|
if (filesLogEnabled()) {
|
|
27309
27366
|
for (const file of applied.written) {
|
|
27310
27367
|
if (baselineDirs.includes(path12.dirname(file))) {
|
|
27311
|
-
diagnose(`[
|
|
27368
|
+
diagnose(`[e2e-files] baseline ${file}: written`);
|
|
27312
27369
|
}
|
|
27313
27370
|
}
|
|
27314
27371
|
}
|
|
@@ -28678,12 +28735,13 @@ function stepLabel(step) {
|
|
|
28678
28735
|
}
|
|
28679
28736
|
async function flowRunToMcpContent(result, ctx) {
|
|
28680
28737
|
const blocks = [];
|
|
28738
|
+
const name = result.e2eTest ?? result.flow;
|
|
28681
28739
|
if (result.executionPrerequisite) {
|
|
28682
28740
|
blocks.push({ type: "text", text: `Prerequisite: ${result.executionPrerequisite}` });
|
|
28683
28741
|
}
|
|
28684
28742
|
blocks.push({
|
|
28685
28743
|
type: "text",
|
|
28686
|
-
text: `Running e2e test "${
|
|
28744
|
+
text: `Running e2e test "${name}"${result.device ? ` on ${result.device}` : ""} (${result.steps.length} steps)`
|
|
28687
28745
|
});
|
|
28688
28746
|
if (typeof result.warning === "string")
|
|
28689
28747
|
blocks.push({ type: "text", text: `\u26A0 ${result.warning}` });
|
|
@@ -28728,7 +28786,7 @@ async function flowRunToMcpContent(result, ctx) {
|
|
|
28728
28786
|
text: `${result.ok ? "PASS" : "FAIL"} \u2014 ${result.passed ?? 0} passed, ${result.failed ?? 0} failed, ${result.errored ?? 0} errored, ${result.skipped ?? 0} skipped${note}${durationSuffix(result.durationMs)}`
|
|
28729
28787
|
});
|
|
28730
28788
|
} else {
|
|
28731
|
-
blocks.push({ type: "text", text: `E2E test "${
|
|
28789
|
+
blocks.push({ type: "text", text: `E2E test "${name}" complete.` });
|
|
28732
28790
|
}
|
|
28733
28791
|
return blocks;
|
|
28734
28792
|
}
|
|
@@ -29339,7 +29397,7 @@ ${desc}` }];
|
|
|
29339
29397
|
deviceId: getDeviceIdFromArgs(params.arguments)
|
|
29340
29398
|
};
|
|
29341
29399
|
let content;
|
|
29342
|
-
if (canonicalToolId(params.name) === "e2e-execute" && result && typeof result === "object" && "flow" in result && "steps" in result) {
|
|
29400
|
+
if (canonicalToolId(params.name) === "e2e-execute" && result && typeof result === "object" && ("e2eTest" in result || "flow" in result) && "steps" in result) {
|
|
29343
29401
|
content = await flowRunToMcpContent(result, ctx);
|
|
29344
29402
|
} else if (params.name === "screenshot-diff" && isScreenshotDiffResult(result)) {
|
|
29345
29403
|
content = await screenshotDiffToMcpContent(result, ctx);
|
|
@@ -223,14 +223,14 @@ export interface ArgentToolArgs {
|
|
|
223
223
|
delayMs?: number;
|
|
224
224
|
};
|
|
225
225
|
"e2e-execute": {
|
|
226
|
-
/** Name of a saved e2e test to run from `.argent/e2e`, or `.argent/flows` when it is not there (e.g. "settings-explore"). Omit when
|
|
226
|
+
/** Name of a saved e2e test to run from `.argent/e2e`, or `.argent/flows` when it is not there (e.g. "settings-explore"). Omit when e2e_test_path is set. */
|
|
227
227
|
name?: string;
|
|
228
|
-
/** Absolute path to the calling agent's project root: the cwd it is working in. With name, the saved e2e test is read from `.argent/e2e/<name>.yaml`, else `.argent/flows/<name>.yaml`, under this root; with
|
|
228
|
+
/** Absolute path to the calling agent's project root: the cwd it is working in. With name, the saved e2e test is read from `.argent/e2e/<name>.yaml`, else `.argent/flows/<name>.yaml`, under this root; with e2e_test_path, the e2e test, its run: siblings, its script: paths and baselines all resolve beside the YAML instead, so pass the agent's cwd. A script still RUNS in this root whichever source was used. */
|
|
229
229
|
project_root: string;
|
|
230
230
|
/** Path to the e2e test .yaml as readable by the tool-server. Internal: the argent client derives it from project_root and name automatically; leave unset. */
|
|
231
|
-
|
|
231
|
+
e2e_test_file?: string;
|
|
232
232
|
/** Omit when name is set. Absolute path to an e2e test .yaml on the client. Over a link (argent link or ARGENT_TOOLS_URL), the argent client uploads the file, its run: fragments and the snapshot baselines of each run, and the tool-server runs those copies. Keep run: fragments under project_root or beside the e2e test file. With updateBaselines, the client writes the new baselines when the run ends. The client also uploads each absolute .png or .yaml path that a tool: step takes as a file argument, when the file is under project_root or beside the e2e test file. A tool: e2e-execute step that names an e2e test with name and an absolute project_root without a .. segment runs: the client also uploads that e2e test and its own files. Over a link, the uploaded e2e tests must not have: script: steps; tool: steps that run an e2e test another way or record an e2e test; tool: steps that take a directory, an app or an output directory; tool: steps whose tool builds a file path from several arguments; tool: steps that name a relative path or a file other than .png or .yaml. Without a link, the tool-server reads the files in place and all step kinds run. */
|
|
233
|
-
|
|
233
|
+
e2e_test_path?: string;
|
|
234
234
|
/** Device id to run against (iOS UDID, Android/Vega serial, Chromium id), as list-devices reports it. Auto-detected when omitted, but only when exactly one booted device matches (optionally narrowed by `platform`); with several booted the run fails and lists them, so pass this explicitly whenever more than one device is up. */
|
|
235
235
|
device?: string;
|
|
236
236
|
/** Restrict auto-detection to this platform when several devices are booted. `ios` selects local simulators only; pass `ios-remote` to select a remote one. `chromium` does more than filter: with no `device` it SELECTS the self-boot branch for a standalone e2e test - the runner boots an Electron instance from the `launch` step's chromium value and tears it down after the run (a single-key `launch: { chromium: … }` map selects it on its own, without this parameter). When it selects that branch it never falls back to device auto-detection (a fragment, or a standalone e2e test's launch map with no `chromium` key, still does), and the launch value must be a real Electron app path on the tool-server host: a bare-string `launch:` - what the recorder writes - holds an installed-app bundle id, so passing `chromium` for one fails the whole run with `Electron boot: path does not exist`. Edit the launch to `{ chromium: <app path> }` first. */
|
|
@@ -239,6 +239,10 @@ export interface ArgentToolArgs {
|
|
|
239
239
|
updateBaselines?: boolean;
|
|
240
240
|
/** Set to true to confirm the execution prerequisite has been met. Required (LLM path) when a fragment defines an executionPrerequisite. */
|
|
241
241
|
prerequisiteAcknowledged?: boolean;
|
|
242
|
+
/** @deprecated Renamed to `e2e_test_path`. */
|
|
243
|
+
flow_path?: string;
|
|
244
|
+
/** @deprecated Renamed to `e2e_test_file`. */
|
|
245
|
+
flow_file?: string;
|
|
242
246
|
};
|
|
243
247
|
"e2e-finish-recording": {
|
|
244
248
|
/** Name of the e2e test being recorded: the one passed to e2e-start-recording. */
|
|
@@ -247,14 +251,18 @@ export interface ArgentToolArgs {
|
|
|
247
251
|
project_root: string;
|
|
248
252
|
};
|
|
249
253
|
"e2e-read-prerequisite": {
|
|
250
|
-
/** Name of a saved e2e test to inspect from `.argent/e2e`, or `.argent/flows` when it is not there (e.g. "settings-explore"). Omit when
|
|
254
|
+
/** Name of a saved e2e test to inspect from `.argent/e2e`, or `.argent/flows` when it is not there (e.g. "settings-explore"). Omit when e2e_test_path is set. */
|
|
251
255
|
name?: string;
|
|
252
|
-
/** Absolute path to the calling agent's project root: the cwd it is working in. With name, the saved e2e test is read from `.argent/e2e/<name>.yaml`, else `.argent/flows/<name>.yaml`, under this root; with
|
|
256
|
+
/** Absolute path to the calling agent's project root: the cwd it is working in. With name, the saved e2e test is read from `.argent/e2e/<name>.yaml`, else `.argent/flows/<name>.yaml`, under this root; with e2e_test_path, the prerequisite is read from that YAML instead, so pass the agent's cwd. */
|
|
253
257
|
project_root: string;
|
|
254
258
|
/** Path to the e2e test .yaml as readable by the tool-server. Internal: the argent client derives it from project_root and name automatically; leave unset. */
|
|
255
|
-
|
|
259
|
+
e2e_test_file?: string;
|
|
256
260
|
/** Omit when name is set. Absolute path to an e2e test .yaml on the client. Over a link (argent link or ARGENT_TOOLS_URL), the argent client uploads the file and the tool-server reads the uploaded copy; without a link, the tool-server reads the file in place. Pass the path through the argent client; a raw path that the file-input boundary did not verify is rejected. Pass the same e2e test source here as to e2e-execute, so the prerequisite you read belongs to the e2e test that will run. */
|
|
261
|
+
e2e_test_path?: string;
|
|
262
|
+
/** @deprecated Renamed to `e2e_test_path`. */
|
|
257
263
|
flow_path?: string;
|
|
264
|
+
/** @deprecated Renamed to `e2e_test_file`. */
|
|
265
|
+
flow_file?: string;
|
|
258
266
|
};
|
|
259
267
|
"e2e-start-recording": {
|
|
260
268
|
/** Name for this e2e test (e.g. "settings-explore"): letters, digits, underscore and hyphen only. */
|