@swmansion/argent 0.16.2-next.10 → 0.16.2-next.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-cmds.mjs +1709 -1594
- package/dist/installer.mjs +66 -63
- package/dist/mcp-server.mjs +305 -188
- package/dist/tool-server.cjs +44 -33
- package/package.json +1 -1
- package/skills/argent-screen-recording/SKILL.md +3 -1
package/dist/tool-server.cjs
CHANGED
|
@@ -109,7 +109,9 @@ var init_artifacts = __esm({
|
|
|
109
109
|
".xml": "application/xml",
|
|
110
110
|
".txt": "text/plain",
|
|
111
111
|
".md": "text/markdown",
|
|
112
|
-
".html": "text/html"
|
|
112
|
+
".html": "text/html",
|
|
113
|
+
".mp4": "video/mp4",
|
|
114
|
+
".mov": "video/quicktime"
|
|
113
115
|
};
|
|
114
116
|
ArtifactStore = class {
|
|
115
117
|
entries = /* @__PURE__ */ new Map();
|
|
@@ -138,6 +140,7 @@ var init_artifacts = __esm({
|
|
|
138
140
|
};
|
|
139
141
|
if (mtimeMs != null) handle.mtimeMs = mtimeMs;
|
|
140
142
|
if (isDirectory2) handle.archive = "tar.gz";
|
|
143
|
+
if (opts?.saveDir) handle.saveDir = opts.saveDir;
|
|
141
144
|
return handle;
|
|
142
145
|
}
|
|
143
146
|
get(id) {
|
|
@@ -34932,7 +34935,7 @@ var require_view = __commonJS({
|
|
|
34932
34935
|
var path38 = require("node:path");
|
|
34933
34936
|
var fs50 = require("node:fs");
|
|
34934
34937
|
var dirname14 = path38.dirname;
|
|
34935
|
-
var
|
|
34938
|
+
var basename10 = path38.basename;
|
|
34936
34939
|
var extname4 = path38.extname;
|
|
34937
34940
|
var join46 = path38.join;
|
|
34938
34941
|
var resolve7 = path38.resolve;
|
|
@@ -34971,7 +34974,7 @@ var require_view = __commonJS({
|
|
|
34971
34974
|
var root2 = roots[i];
|
|
34972
34975
|
var loc = resolve7(root2, name);
|
|
34973
34976
|
var dir = dirname14(loc);
|
|
34974
|
-
var file2 =
|
|
34977
|
+
var file2 = basename10(loc);
|
|
34975
34978
|
path39 = this.resolve(dir, file2);
|
|
34976
34979
|
}
|
|
34977
34980
|
return path39;
|
|
@@ -35001,7 +35004,7 @@ var require_view = __commonJS({
|
|
|
35001
35004
|
if (stat4 && stat4.isFile()) {
|
|
35002
35005
|
return path39;
|
|
35003
35006
|
}
|
|
35004
|
-
path39 = join46(dir,
|
|
35007
|
+
path39 = join46(dir, basename10(file2, ext), "index" + ext);
|
|
35005
35008
|
stat4 = tryStat(path39);
|
|
35006
35009
|
if (stat4 && stat4.isFile()) {
|
|
35007
35010
|
return path39;
|
|
@@ -57446,9 +57449,9 @@ var require_content_disposition = __commonJS({
|
|
|
57446
57449
|
if (typeof fallback === "string" && NON_LATIN1_REGEXP.test(fallback)) {
|
|
57447
57450
|
throw new TypeError("fallback must be ISO-8859-1 string");
|
|
57448
57451
|
}
|
|
57449
|
-
var name =
|
|
57452
|
+
var name = basename10(filename);
|
|
57450
57453
|
var isQuotedString = TEXT_REGEXP.test(name);
|
|
57451
|
-
var fallbackName = typeof fallback !== "string" ? fallback && getlatin1(name) :
|
|
57454
|
+
var fallbackName = typeof fallback !== "string" ? fallback && getlatin1(name) : basename10(fallback);
|
|
57452
57455
|
var hasFallback = typeof fallbackName === "string" && fallbackName !== name;
|
|
57453
57456
|
if (hasFallback || !isQuotedString || hasHexEscape(name)) {
|
|
57454
57457
|
params["filename*"] = name;
|
|
@@ -57568,7 +57571,7 @@ var require_content_disposition = __commonJS({
|
|
|
57568
57571
|
this.type = type;
|
|
57569
57572
|
this.parameters = parameters;
|
|
57570
57573
|
}
|
|
57571
|
-
function
|
|
57574
|
+
function basename10(path38) {
|
|
57572
57575
|
const normalized = path38.replaceAll("\\", "/");
|
|
57573
57576
|
let end = normalized.length;
|
|
57574
57577
|
while (end > 0 && normalized[end - 1] === "/") {
|
|
@@ -104490,7 +104493,7 @@ var _CI_VENDOR_COUNT_FOR_TEST = vendors_default.length;
|
|
|
104490
104493
|
var SESSION_ID = (0, import_node_crypto3.randomUUID)();
|
|
104491
104494
|
function readCliVersion() {
|
|
104492
104495
|
if (true) {
|
|
104493
|
-
return "0.
|
|
104496
|
+
return "0.17.0";
|
|
104494
104497
|
}
|
|
104495
104498
|
return "0.0.0";
|
|
104496
104499
|
}
|
|
@@ -105878,7 +105881,7 @@ var import_node_path5 = __toESM(require("node:path"));
|
|
|
105878
105881
|
var import_semver = __toESM(require_semver2());
|
|
105879
105882
|
|
|
105880
105883
|
// ../tool-server/package.json
|
|
105881
|
-
var version3 = "0.
|
|
105884
|
+
var version3 = "0.17.0";
|
|
105882
105885
|
|
|
105883
105886
|
// ../tool-server/src/utils/update-checker.ts
|
|
105884
105887
|
var import_update_core = __toESM(require_dist4());
|
|
@@ -144035,10 +144038,12 @@ function makePointerControl(simulator) {
|
|
|
144035
144038
|
}
|
|
144036
144039
|
|
|
144037
144040
|
// ../tool-server/src/tools/screen-recording/screen-recording-stop.ts
|
|
144041
|
+
var import_node_path20 = require("node:path");
|
|
144038
144042
|
init_zod();
|
|
144039
144043
|
var zodSchema52 = external_exports.object({
|
|
144040
144044
|
udid: external_exports.string().describe("Target device id from `list-devices` (iOS Simulator UDID or Android serial).")
|
|
144041
144045
|
});
|
|
144046
|
+
var RECORDINGS_DIR = ".argent/recordings";
|
|
144042
144047
|
var capability27 = {
|
|
144043
144048
|
apple: { simulator: true },
|
|
144044
144049
|
android: { emulator: true, device: true, unknown: true }
|
|
@@ -144062,7 +144067,13 @@ Fails if no recording (running or finished-but-unretrieved) exists for the given
|
|
|
144062
144067
|
assertSupported("screen-recording-stop", capability27, device);
|
|
144063
144068
|
const stopped = await stopCapture(api);
|
|
144064
144069
|
const artifacts = requireArtifacts(ctx);
|
|
144065
|
-
const video = await artifacts.register(stopped.outputFile, {
|
|
144070
|
+
const video = await artifacts.register(stopped.outputFile, {
|
|
144071
|
+
mimeType: "video/mp4",
|
|
144072
|
+
// Drop the internal `argent-` temp prefix so the saved file reads cleanly
|
|
144073
|
+
// as `.argent/recordings/screen-recording-<device>-<ts>.mp4`.
|
|
144074
|
+
filename: (0, import_node_path20.basename)(stopped.outputFile).replace(/^argent-/, ""),
|
|
144075
|
+
saveDir: RECORDINGS_DIR
|
|
144076
|
+
});
|
|
144066
144077
|
const result = { video, durationMs: stopped.durationMs };
|
|
144067
144078
|
if (stopped.wallClockMs !== void 0) result.wallClockMs = stopped.wallClockMs;
|
|
144068
144079
|
if (stopped.trimmedMs !== void 0) result.trimmedMs = stopped.trimmedMs;
|
|
@@ -151084,7 +151095,7 @@ init_zod();
|
|
|
151084
151095
|
|
|
151085
151096
|
// ../tool-server/src/utils/workspace-reader.ts
|
|
151086
151097
|
var import_promises12 = require("node:fs/promises");
|
|
151087
|
-
var
|
|
151098
|
+
var import_node_path21 = require("node:path");
|
|
151088
151099
|
var import_node_child_process27 = require("node:child_process");
|
|
151089
151100
|
var import_dotenv = __toESM(require_main());
|
|
151090
151101
|
async function exists(path38) {
|
|
@@ -151172,7 +151183,7 @@ async function detectLockfile(workspacePath) {
|
|
|
151172
151183
|
const checks = await Promise.all(
|
|
151173
151184
|
LOCKFILES.map(async (name) => ({
|
|
151174
151185
|
name,
|
|
151175
|
-
exists: await exists((0,
|
|
151186
|
+
exists: await exists((0, import_node_path21.join)(workspacePath, name))
|
|
151176
151187
|
}))
|
|
151177
151188
|
);
|
|
151178
151189
|
return checks.find((c) => c.exists)?.name ?? null;
|
|
@@ -151191,7 +151202,7 @@ var CI_CONFIGS = [
|
|
|
151191
151202
|
];
|
|
151192
151203
|
async function detectCiConfig(workspacePath) {
|
|
151193
151204
|
for (const ci of CI_CONFIGS) {
|
|
151194
|
-
if (await exists((0,
|
|
151205
|
+
if (await exists((0, import_node_path21.join)(workspacePath, ci.path))) return ci.label;
|
|
151195
151206
|
}
|
|
151196
151207
|
return null;
|
|
151197
151208
|
}
|
|
@@ -151212,7 +151223,7 @@ async function detectLintStagedConfig(workspacePath, packageJson) {
|
|
|
151212
151223
|
return packageJson["lint-staged"];
|
|
151213
151224
|
}
|
|
151214
151225
|
for (const file2 of LINT_STAGED_FILES) {
|
|
151215
|
-
const full = (0,
|
|
151226
|
+
const full = (0, import_node_path21.join)(workspacePath, file2);
|
|
151216
151227
|
if (await exists(full)) {
|
|
151217
151228
|
if (file2.endsWith(".json") || file2 === ".lintstagedrc") {
|
|
151218
151229
|
return readJsonFile(full);
|
|
@@ -151254,7 +151265,7 @@ var CONFIG_FILES = [
|
|
|
151254
151265
|
async function detectConfigFiles(workspacePath) {
|
|
151255
151266
|
const results = await Promise.allSettled(
|
|
151256
151267
|
CONFIG_FILES.map(async (file2) => {
|
|
151257
|
-
if (await exists((0,
|
|
151268
|
+
if (await exists((0, import_node_path21.join)(workspacePath, file2))) return file2;
|
|
151258
151269
|
return null;
|
|
151259
151270
|
})
|
|
151260
151271
|
);
|
|
@@ -151293,7 +151304,7 @@ async function detectEnvFiles(workspacePath) {
|
|
|
151293
151304
|
const envFileNames = entries.filter((e) => e === ".env" || e.startsWith(".env."));
|
|
151294
151305
|
const results = await Promise.all(
|
|
151295
151306
|
envFileNames.map(async (name) => {
|
|
151296
|
-
const content = await readTextFile((0,
|
|
151307
|
+
const content = await readTextFile((0, import_node_path21.join)(workspacePath, name));
|
|
151297
151308
|
return {
|
|
151298
151309
|
name,
|
|
151299
151310
|
keys: content ? extractEnvKeys(content) : []
|
|
@@ -151320,34 +151331,34 @@ async function readWorkspaceSnapshot(workspacePath) {
|
|
|
151320
151331
|
ciConfig,
|
|
151321
151332
|
configFilesFound
|
|
151322
151333
|
] = await Promise.all([
|
|
151323
|
-
readJsonFile((0,
|
|
151324
|
-
readJsonFile((0,
|
|
151325
|
-
readJsonFile((0,
|
|
151326
|
-
readJsonFile((0,
|
|
151327
|
-
readTextFile((0,
|
|
151328
|
-
(r) => r ?? readTextFile((0,
|
|
151334
|
+
readJsonFile((0, import_node_path21.join)(workspacePath, "package.json")),
|
|
151335
|
+
readJsonFile((0, import_node_path21.join)(workspacePath, "app.json")),
|
|
151336
|
+
readJsonFile((0, import_node_path21.join)(workspacePath, "eas.json")),
|
|
151337
|
+
readJsonFile((0, import_node_path21.join)(workspacePath, "tsconfig.json")),
|
|
151338
|
+
readTextFile((0, import_node_path21.join)(workspacePath, "metro.config.js")).then(
|
|
151339
|
+
(r) => r ?? readTextFile((0, import_node_path21.join)(workspacePath, "metro.config.ts"))
|
|
151329
151340
|
),
|
|
151330
|
-
readTextFile((0,
|
|
151331
|
-
(r) => r ?? readTextFile((0,
|
|
151341
|
+
readTextFile((0, import_node_path21.join)(workspacePath, "babel.config.js")).then(
|
|
151342
|
+
(r) => r ?? readTextFile((0, import_node_path21.join)(workspacePath, "babel.config.cjs"))
|
|
151332
151343
|
),
|
|
151333
|
-
isDirectory((0,
|
|
151334
|
-
isDirectory((0,
|
|
151344
|
+
isDirectory((0, import_node_path21.join)(workspacePath, "ios")),
|
|
151345
|
+
isDirectory((0, import_node_path21.join)(workspacePath, "android")),
|
|
151335
151346
|
detectLockfile(workspacePath),
|
|
151336
151347
|
detectEnvFiles(workspacePath),
|
|
151337
151348
|
detectToolVersions(workspacePath),
|
|
151338
|
-
listDir((0,
|
|
151339
|
-
listDir((0,
|
|
151349
|
+
listDir((0, import_node_path21.join)(workspacePath, "scripts")),
|
|
151350
|
+
listDir((0, import_node_path21.join)(workspacePath, ".husky")),
|
|
151340
151351
|
detectCiConfig(workspacePath),
|
|
151341
151352
|
detectConfigFiles(workspacePath)
|
|
151342
151353
|
]);
|
|
151343
|
-
const iosDir = (0,
|
|
151344
|
-
const androidDir = (0,
|
|
151354
|
+
const iosDir = (0, import_node_path21.join)(workspacePath, "ios");
|
|
151355
|
+
const androidDir = (0, import_node_path21.join)(workspacePath, "android");
|
|
151345
151356
|
const [iosWorkspace, iosHasPodfile, makefileText, lintStagedConfig, androidHasGradle] = await Promise.all([
|
|
151346
151357
|
hasIosDir ? findIosWorkspace(iosDir) : Promise.resolve(null),
|
|
151347
|
-
exists((0,
|
|
151348
|
-
readTextFile((0,
|
|
151358
|
+
exists((0, import_node_path21.join)(workspacePath, "ios", "Podfile")),
|
|
151359
|
+
readTextFile((0, import_node_path21.join)(workspacePath, "Makefile")),
|
|
151349
151360
|
detectLintStagedConfig(workspacePath, packageJson),
|
|
151350
|
-
hasAndroidDir ? exists((0,
|
|
151361
|
+
hasAndroidDir ? exists((0, import_node_path21.join)(androidDir, "gradlew")) : Promise.resolve(false)
|
|
151351
151362
|
]);
|
|
151352
151363
|
const metroPort = metroConfigRaw ? extractMetroPort(metroConfigRaw) : null;
|
|
151353
151364
|
const makefileTargets = makefileText ? extractMakefileTargets(makefileText) : null;
|
package/package.json
CHANGED
|
@@ -27,9 +27,11 @@ A recording does not stop itself before its `timeLimitSeconds` cap, so a forgott
|
|
|
27
27
|
2. Call `screen-recording-start` with `udid` and a `timeLimitSeconds` slightly above the expected interaction length (default 180, max 600). Taps and swipes are drawn into the video by default (see the touch-visualizer note below); pass `showTouches: false` for a clean raw-screen capture.
|
|
28
28
|
3. Set the end-of-recording reminder described in §2 — this step is not optional.
|
|
29
29
|
4. Drive the interaction to capture: gestures, navigation, typing (`argent-device-interact`). Prefer `run-sequence` for tight multi-step interactions so tool-call latency does not pad the video.
|
|
30
|
-
5. Call `screen-recording-stop` with the same `udid`. It returns `{ video, durationMs, wallClockMs?, trimmedMs?, warning? }`; `video` is an artifact
|
|
30
|
+
5. Call `screen-recording-stop` with the same `udid`. It returns `{ video, durationMs, wallClockMs?, trimmedMs?, warning? }`; `video` is an artifact whose resolved path points at the durably-saved file (see below). The video is already final when stop returns (the watermark is stamped during capture, not in a second pass), so stop takes well under a second.
|
|
31
31
|
6. Check `warning`: it reports cap-triggered stops, early encoder exits, a dropped frame stream, and possibly-truncated containers. Verify the file plays (or at least has a sane size) before presenting it to the user.
|
|
32
32
|
|
|
33
|
+
**Where the file lands (durable, not scratch).** Unlike most argent artifacts (which live in a disposable temp cache the OS reclaims), a finished recording is saved durably on the **client** into `<project>/.argent/recordings/` — the project being the nearest ancestor of the client's working directory with a `.git`/`package.json`/`.argent`, or `~/.argent/recordings/` when the client isn't inside a project. This holds even for a remote `argent link` tool-server: the mp4 is written on the client host, not the server. The saved name is `screen-recording-<device>-<timestamp>.mp4`; if that name is already taken the new file lands beside it as `… (2).mp4` rather than overwriting. Because these files persist in the working tree, mention the path to the user (and note that they are untracked — add them to `.gitignore` or clean them up if they shouldn't be committed).
|
|
34
|
+
|
|
33
35
|
**Static-frame trimming (on by default).** Stretches where the screen does not change are collapsed: the first second of each still stretch is kept so pauses read naturally, then unchanged frames are dropped until something moves again (a change of even a couple of pixels counts). So you can leave a recording running across slow steps, waits, or thinking time without padding the clip with dead air — a 40-second session with 5 seconds of real activity comes back as a ~5-7 second video. When trimming removed anything, stop also returns `wallClockMs` (real elapsed time) and `trimmedMs` (how much was cut); `durationMs` is always the length of the video you actually get. Pass `trimStatic: false` to `screen-recording-start` when you want a faithful real-time recording (e.g. to measure how long something took on screen).
|
|
34
36
|
|
|
35
37
|
**Touch visualizer (on by default).** Every interaction argent drives is drawn straight into the video: a pulse marks each tap, a fading comet trail follows swipes and drags, and paired markers show the two contact points of a pinch or rotate. This makes a recording self-explanatory — a viewer can see _where_ each gesture landed rather than watching the UI react to an invisible finger. It is rendered by simulator-server into the frame stream (nothing is composited host-side), so it costs nothing extra and never appears in a `screenshot`. Pass `showTouches: false` to `screen-recording-start` to record the raw screen with no overlay (e.g. when capturing exactly what the user would see). If simulator-server cannot enable it, the recording still succeeds and stop returns a `warning` saying touches are not shown.
|