@swmansion/argent 0.18.0 → 0.18.1-next.1

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.
@@ -2984,7 +2984,7 @@ var require_compile = __commonJS({
2984
2984
  const schOrFunc = root.refs[ref];
2985
2985
  if (schOrFunc)
2986
2986
  return schOrFunc;
2987
- let _sch = resolve5.call(this, root, ref);
2987
+ let _sch = resolve7.call(this, root, ref);
2988
2988
  if (_sch === void 0) {
2989
2989
  const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
2990
2990
  const { schemaId } = this.opts;
@@ -3011,7 +3011,7 @@ var require_compile = __commonJS({
3011
3011
  function sameSchemaEnv(s1, s2) {
3012
3012
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
3013
3013
  }
3014
- function resolve5(root, ref) {
3014
+ function resolve7(root, ref) {
3015
3015
  let sch;
3016
3016
  while (typeof (sch = this.refs[ref]) == "string")
3017
3017
  ref = sch;
@@ -3229,8 +3229,8 @@ var require_utils = __commonJS({
3229
3229
  }
3230
3230
  return ind;
3231
3231
  }
3232
- function removeDotSegments(path11) {
3233
- let input = path11;
3232
+ function removeDotSegments(path12) {
3233
+ let input = path12;
3234
3234
  const output = [];
3235
3235
  let nextSlash = -1;
3236
3236
  let len = 0;
@@ -3482,8 +3482,8 @@ var require_schemes = __commonJS({
3482
3482
  wsComponent.secure = void 0;
3483
3483
  }
3484
3484
  if (wsComponent.resourceName) {
3485
- const [path11, query] = wsComponent.resourceName.split("?");
3486
- wsComponent.path = path11 && path11 !== "/" ? path11 : void 0;
3485
+ const [path12, query] = wsComponent.resourceName.split("?");
3486
+ wsComponent.path = path12 && path12 !== "/" ? path12 : void 0;
3487
3487
  wsComponent.query = query;
3488
3488
  wsComponent.resourceName = void 0;
3489
3489
  }
@@ -3642,7 +3642,7 @@ var require_fast_uri = __commonJS({
3642
3642
  }
3643
3643
  return uri;
3644
3644
  }
3645
- function resolve5(baseURI, relativeURI, options) {
3645
+ function resolve7(baseURI, relativeURI, options) {
3646
3646
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
3647
3647
  const resolved = resolveComponent(parse3(baseURI, schemelessOptions), parse3(relativeURI, schemelessOptions), schemelessOptions, true);
3648
3648
  schemelessOptions.skipEscape = true;
@@ -3900,7 +3900,7 @@ var require_fast_uri = __commonJS({
3900
3900
  var fastUri = {
3901
3901
  SCHEMES,
3902
3902
  normalize: normalize2,
3903
- resolve: resolve5,
3903
+ resolve: resolve7,
3904
3904
  resolveComponent,
3905
3905
  equal,
3906
3906
  serialize,
@@ -7137,10 +7137,10 @@ function mergeDefs(...defs) {
7137
7137
  function cloneDef(schema) {
7138
7138
  return mergeDefs(schema._zod.def);
7139
7139
  }
7140
- function getElementAtPath(obj, path11) {
7141
- if (!path11)
7140
+ function getElementAtPath(obj, path12) {
7141
+ if (!path12)
7142
7142
  return obj;
7143
- return path11.reduce((acc, key) => acc?.[key], obj);
7143
+ return path12.reduce((acc, key) => acc?.[key], obj);
7144
7144
  }
7145
7145
  function promiseAllObject(promisesObj) {
7146
7146
  const keys = Object.keys(promisesObj);
@@ -7549,11 +7549,11 @@ function explicitlyAborted(x, startIndex = 0) {
7549
7549
  }
7550
7550
  return false;
7551
7551
  }
7552
- function prefixIssues(path11, issues) {
7552
+ function prefixIssues(path12, issues) {
7553
7553
  return issues.map((iss) => {
7554
7554
  var _a3;
7555
7555
  (_a3 = iss).path ?? (_a3.path = []);
7556
- iss.path.unshift(path11);
7556
+ iss.path.unshift(path12);
7557
7557
  return iss;
7558
7558
  });
7559
7559
  }
@@ -7700,16 +7700,16 @@ function flattenError(error2, mapper = (issue2) => issue2.message) {
7700
7700
  }
7701
7701
  function formatError(error2, mapper = (issue2) => issue2.message) {
7702
7702
  const fieldErrors = { _errors: [] };
7703
- const processError = (error3, path11 = []) => {
7703
+ const processError = (error3, path12 = []) => {
7704
7704
  for (const issue2 of error3.issues) {
7705
7705
  if (issue2.code === "invalid_union" && issue2.errors.length) {
7706
- issue2.errors.map((issues) => processError({ issues }, [...path11, ...issue2.path]));
7706
+ issue2.errors.map((issues) => processError({ issues }, [...path12, ...issue2.path]));
7707
7707
  } else if (issue2.code === "invalid_key") {
7708
- processError({ issues: issue2.issues }, [...path11, ...issue2.path]);
7708
+ processError({ issues: issue2.issues }, [...path12, ...issue2.path]);
7709
7709
  } else if (issue2.code === "invalid_element") {
7710
- processError({ issues: issue2.issues }, [...path11, ...issue2.path]);
7710
+ processError({ issues: issue2.issues }, [...path12, ...issue2.path]);
7711
7711
  } else {
7712
- const fullpath = [...path11, ...issue2.path];
7712
+ const fullpath = [...path12, ...issue2.path];
7713
7713
  if (fullpath.length === 0) {
7714
7714
  fieldErrors._errors.push(mapper(issue2));
7715
7715
  } else {
@@ -13701,12 +13701,12 @@ var StdioServerTransport = class {
13701
13701
  this.onclose?.();
13702
13702
  }
13703
13703
  send(message) {
13704
- return new Promise((resolve5) => {
13704
+ return new Promise((resolve7) => {
13705
13705
  const json = serializeMessage(message);
13706
13706
  if (this._stdout.write(json)) {
13707
- resolve5();
13707
+ resolve7();
13708
13708
  } else {
13709
- this._stdout.once("drain", resolve5);
13709
+ this._stdout.once("drain", resolve7);
13710
13710
  }
13711
13711
  });
13712
13712
  }
@@ -14304,7 +14304,7 @@ var Protocol = class {
14304
14304
  return;
14305
14305
  }
14306
14306
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
14307
- await new Promise((resolve5) => setTimeout(resolve5, pollInterval));
14307
+ await new Promise((resolve7) => setTimeout(resolve7, pollInterval));
14308
14308
  options?.signal?.throwIfAborted();
14309
14309
  }
14310
14310
  } catch (error2) {
@@ -14321,7 +14321,7 @@ var Protocol = class {
14321
14321
  */
14322
14322
  request(request, resultSchema, options) {
14323
14323
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
14324
- return new Promise((resolve5, reject) => {
14324
+ return new Promise((resolve7, reject) => {
14325
14325
  const earlyReject = (error2) => {
14326
14326
  reject(error2);
14327
14327
  };
@@ -14399,7 +14399,7 @@ var Protocol = class {
14399
14399
  if (!parseResult.success) {
14400
14400
  reject(parseResult.error);
14401
14401
  } else {
14402
- resolve5(parseResult.data);
14402
+ resolve7(parseResult.data);
14403
14403
  }
14404
14404
  } catch (error2) {
14405
14405
  reject(error2);
@@ -14660,12 +14660,12 @@ var Protocol = class {
14660
14660
  }
14661
14661
  } catch {
14662
14662
  }
14663
- return new Promise((resolve5, reject) => {
14663
+ return new Promise((resolve7, reject) => {
14664
14664
  if (signal.aborted) {
14665
14665
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
14666
14666
  return;
14667
14667
  }
14668
- const timeoutId = setTimeout(resolve5, interval);
14668
+ const timeoutId = setTimeout(resolve7, interval);
14669
14669
  signal.addEventListener("abort", () => {
14670
14670
  clearTimeout(timeoutId);
14671
14671
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -15490,7 +15490,7 @@ function generateToken() {
15490
15490
  return randomBytes(AUTH_TOKEN_BYTES).toString("hex");
15491
15491
  }
15492
15492
  function findFreePort() {
15493
- return new Promise((resolve5, reject) => {
15493
+ return new Promise((resolve7, reject) => {
15494
15494
  const srv = net.createServer();
15495
15495
  srv.listen(0, "127.0.0.1", () => {
15496
15496
  const addr = srv.address();
@@ -15501,7 +15501,7 @@ function findFreePort() {
15501
15501
  const port = addr.port;
15502
15502
  srv.close((err) => {
15503
15503
  if (err) reject(err);
15504
- else resolve5(port);
15504
+ else resolve7(port);
15505
15505
  });
15506
15506
  });
15507
15507
  srv.on("error", reject);
@@ -15599,7 +15599,7 @@ function killSpawnedChild(child, pid) {
15599
15599
  }
15600
15600
  }
15601
15601
  function spawnToolsServer(paths, port, options = {}) {
15602
- return new Promise((resolve5, reject) => {
15602
+ return new Promise((resolve7, reject) => {
15603
15603
  let logFd;
15604
15604
  try {
15605
15605
  fs.mkdirSync(STATE_DIR, { recursive: true });
@@ -15636,7 +15636,7 @@ function spawnToolsServer(paths, port, options = {}) {
15636
15636
  rl.close();
15637
15637
  child.stdout?.resume();
15638
15638
  child.stdout?.unref?.();
15639
- settle(() => resolve5({ port: actualPort, pid }));
15639
+ settle(() => resolve7({ port: actualPort, pid }));
15640
15640
  }
15641
15641
  });
15642
15642
  child.on("error", (err) => {
@@ -16085,9 +16085,9 @@ async function tarball(sourcePath) {
16085
16085
  return tarPath;
16086
16086
  }
16087
16087
  function sha256File(filePath) {
16088
- return new Promise((resolve5, reject) => {
16088
+ return new Promise((resolve7, reject) => {
16089
16089
  const hash = createHash2("sha256");
16090
- createReadStream(filePath).on("data", (chunk) => hash.update(chunk)).on("end", () => resolve5(hash.digest("hex"))).on("error", reject);
16090
+ createReadStream(filePath).on("data", (chunk) => hash.update(chunk)).on("end", () => resolve7(hash.digest("hex"))).on("error", reject);
16091
16091
  });
16092
16092
  }
16093
16093
  async function uploadTar(tarPath, endpoint) {
@@ -16206,7 +16206,7 @@ async function applyClientFileDirectives(result) {
16206
16206
  import { copyFile, mkdir as mkdir4, readFile as readFile4, realpath, rm as rm3, stat as stat2, writeFile as writeFile4 } from "node:fs/promises";
16207
16207
  import { constants as fsConstants } from "node:fs";
16208
16208
  import { tmpdir as tmpdir2 } from "node:os";
16209
- import { basename as basename3, dirname as dirname5, extname, isAbsolute as isAbsolute3, join as join8, normalize, sep as sep2 } from "node:path";
16209
+ import { basename as basename3, dirname as dirname5, extname, isAbsolute as isAbsolute3, join as join8, normalize, resolve as resolve5, sep as sep2 } from "node:path";
16210
16210
  import { createHash as createHash3 } from "node:crypto";
16211
16211
 
16212
16212
  // ../configuration-core/src/flags.ts
@@ -16277,13 +16277,16 @@ function nonEmpty(value) {
16277
16277
  const trimmed = value.trim();
16278
16278
  return trimmed === "" ? null : value;
16279
16279
  }
16280
+ function resolveHomeDir(options = {}) {
16281
+ if (options.homeDir) return options.homeDir;
16282
+ return process.platform === "win32" ? nonEmpty(process.env.USERPROFILE) ?? os.homedir() : nonEmpty(process.env.HOME) ?? os.homedir();
16283
+ }
16280
16284
  function argentHomeDir() {
16281
- const home = process.platform === "win32" ? nonEmpty(process.env.USERPROFILE) ?? os.homedir() : nonEmpty(process.env.HOME) ?? os.homedir();
16282
- return path5.join(home, ".argent");
16285
+ return path5.join(resolveHomeDir(), ".argent");
16283
16286
  }
16284
16287
  function configDir(scope = "global", options = {}) {
16285
16288
  if (scope === "global") {
16286
- return options.homeDir ? path5.join(options.homeDir, ".argent") : argentHomeDir();
16289
+ return path5.join(resolveHomeDir(options), ".argent");
16287
16290
  }
16288
16291
  const cwd = options.cwd ?? process.cwd();
16289
16292
  return path5.join(resolveProjectRoot(cwd), ".argent");
@@ -16307,6 +16310,31 @@ function readConfigObject(scope = "global", options = {}) {
16307
16310
  }
16308
16311
  return {};
16309
16312
  }
16313
+ var FORBIDDEN_SEGMENTS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
16314
+ function splitKey(dottedKey) {
16315
+ const parts = dottedKey.split(".");
16316
+ if (parts.length === 0 || parts.some((p) => p === "")) {
16317
+ throw new Error(`Invalid config key "${dottedKey}": empty path segment`);
16318
+ }
16319
+ for (const p of parts) {
16320
+ if (FORBIDDEN_SEGMENTS.has(p)) {
16321
+ throw new Error(`Invalid config key "${dottedKey}": forbidden segment "${p}"`);
16322
+ }
16323
+ }
16324
+ return parts;
16325
+ }
16326
+ function isPlainObject3(value) {
16327
+ return !!value && typeof value === "object" && !Array.isArray(value);
16328
+ }
16329
+ function getAtPath(obj, dottedKey) {
16330
+ const parts = splitKey(dottedKey);
16331
+ let cur = obj;
16332
+ for (const part of parts) {
16333
+ if (!isPlainObject3(cur)) return void 0;
16334
+ cur = cur[part];
16335
+ }
16336
+ return cur;
16337
+ }
16310
16338
  var LOCK_STALE_MS2 = 1e4;
16311
16339
  var LOCK_MAX_WAIT_MS = 2e3;
16312
16340
  var LOCK_RETRY_MS = 25;
@@ -16379,6 +16407,163 @@ function updateConfig(mutate, scope = "global", options = {}) {
16379
16407
  }
16380
16408
  }
16381
16409
 
16410
+ // ../configuration-core/src/merge.ts
16411
+ function mergeRestrictive(local, global2) {
16412
+ if (local === void 0) return global2;
16413
+ if (global2 === void 0) return local;
16414
+ if (typeof local === "boolean" && typeof global2 === "boolean") {
16415
+ return local && global2;
16416
+ }
16417
+ if (typeof local === "number" && typeof global2 === "number") {
16418
+ return Math.min(local, global2);
16419
+ }
16420
+ return local;
16421
+ }
16422
+ function toArray(value) {
16423
+ return Array.isArray(value) ? value : null;
16424
+ }
16425
+ function mergeUnion(local, global2) {
16426
+ const l = toArray(local);
16427
+ const g = toArray(global2);
16428
+ if (l === null && g === null) return local ?? global2;
16429
+ const merged = [...g ?? [], ...l ?? []];
16430
+ return Array.from(new Set(merged));
16431
+ }
16432
+ function mergeIntersection(local, global2) {
16433
+ const l = toArray(local);
16434
+ const g = toArray(global2);
16435
+ if (l === null && g === null) return local ?? global2;
16436
+ if (l === null) return global2;
16437
+ if (g === null) return local;
16438
+ const globalSet = new Set(g);
16439
+ return l.filter((item) => globalSet.has(item));
16440
+ }
16441
+ function applyMergePolicy(policy, local, global2) {
16442
+ if (typeof policy === "function") return policy({ local, global: global2 });
16443
+ switch (policy) {
16444
+ case "prioritize-local":
16445
+ return local ?? global2;
16446
+ case "prioritize-global":
16447
+ return global2 ?? local;
16448
+ case "prioritize-restrictive":
16449
+ return mergeRestrictive(local, global2);
16450
+ case "union":
16451
+ return mergeUnion(local, global2);
16452
+ case "intersection":
16453
+ return mergeIntersection(local, global2);
16454
+ default: {
16455
+ const _exhaustive = policy;
16456
+ return _exhaustive;
16457
+ }
16458
+ }
16459
+ }
16460
+
16461
+ // ../configuration-core/src/config-schema.ts
16462
+ function asBoolean(raw) {
16463
+ return typeof raw === "boolean" ? raw : void 0;
16464
+ }
16465
+ function asString(raw) {
16466
+ if (typeof raw !== "string") return void 0;
16467
+ const trimmed = raw.trim();
16468
+ return trimmed === "" ? void 0 : trimmed;
16469
+ }
16470
+ function asStringArray(raw) {
16471
+ if (!Array.isArray(raw)) return void 0;
16472
+ const out = [];
16473
+ for (const item of raw) {
16474
+ if (typeof item === "string" && item.trim() !== "") out.push(item.trim());
16475
+ }
16476
+ return out;
16477
+ }
16478
+ var CONFIG_SCHEMA = [
16479
+ {
16480
+ key: "telemetry.enabled",
16481
+ description: "Whether anonymous opt-out telemetry is enabled (on by default; environment opt-outs like DO_NOT_TRACK are not reflected here \u2014 `argent telemetry status` shows effective consent).",
16482
+ scopes: ["global"],
16483
+ parse: asBoolean,
16484
+ // A committed project file must never re-enable telemetry a user disabled
16485
+ // globally, so the more-restrictive (opt-out) value always wins.
16486
+ merge: "prioritize-restrictive",
16487
+ // Telemetry is opt-out: with nothing stored, consent.ts treats it as
16488
+ // enabled, and the config surface must report the same instead of "(unset)".
16489
+ default: true,
16490
+ // Read-only under `argent config`: opt-in/out goes through the dedicated
16491
+ // command so the live client is drained/reset, not just the file rewritten.
16492
+ manageCommand: "argent telemetry"
16493
+ },
16494
+ {
16495
+ key: "lens.agent",
16496
+ description: "Coding-agent id remembered by `argent lens` to skip the picker.",
16497
+ scopes: ["project", "global"],
16498
+ parse: asString,
16499
+ // A repo can pin the agent its screenshots should use; falls back to the
16500
+ // user's global remembered choice.
16501
+ merge: "prioritize-local",
16502
+ example: "claude"
16503
+ },
16504
+ {
16505
+ key: "ios.additionalDeviceSets",
16506
+ description: "Additional CoreSimulator device-set directories whose simulators argent should see alongside the default set. Absolute paths (or ~/\u2026); relative entries resolve against the project root (project scope) or home (global scope).",
16507
+ scopes: ["project", "global"],
16508
+ parse: asStringArray,
16509
+ // Additive: the scopes extend each other rather than shadow — a repo's
16510
+ // committed device sets are appended to the user's global ones (global
16511
+ // baseline first, project extras after, deduplicated). Note that
16512
+ // `getAdditionalIosDeviceSets` re-implements this union (path resolution
16513
+ // must precede dedup) and guards on the preset staying "union".
16514
+ merge: "union",
16515
+ example: '["~/DeviceSets/ci"]'
16516
+ },
16517
+ {
16518
+ key: "recordings.directory",
16519
+ description: "Directory where finished screen recordings (mp4) are saved on the client host. Absolute, `~`-prefixed, or relative to the project root (home dir when not in a project). Unset \u21D2 `.argent/recordings` under the project root.",
16520
+ scopes: ["project", "global"],
16521
+ parse: asString,
16522
+ // A repo can pin where its recordings land; falls back to the user's global
16523
+ // preference. Resolution happens on the client (the machine the mp4 is
16524
+ // persisted to), so with a remote `argent link` tool-server it is the
16525
+ // *client's* config that decides.
16526
+ merge: "prioritize-local",
16527
+ example: "~/Movies/argent"
16528
+ }
16529
+ ];
16530
+ function getConfigDefinition(key, registry2 = CONFIG_SCHEMA) {
16531
+ return registry2.find((def) => def.key === key);
16532
+ }
16533
+
16534
+ // ../configuration-core/src/config-access.ts
16535
+ import * as path7 from "node:path";
16536
+ function readScopeValue(def, scope, options) {
16537
+ if (!def.scopes.includes(scope)) return void 0;
16538
+ const raw = getAtPath(readConfigObject(scope, options), def.key);
16539
+ return raw === void 0 ? void 0 : def.parse(raw);
16540
+ }
16541
+ function getConfigValue(def, options = {}) {
16542
+ const local = readScopeValue(def, "project", options);
16543
+ const global2 = readScopeValue(def, "global", options);
16544
+ const merged = applyMergePolicy(def.merge, local, global2);
16545
+ return merged ?? def.default;
16546
+ }
16547
+ function getConfigValueByKey(key, options = {}, registry2 = CONFIG_SCHEMA) {
16548
+ const def = requireDefinition(key, registry2);
16549
+ return getConfigValue(def, options);
16550
+ }
16551
+ function requireDefinition(key, registry2 = CONFIG_SCHEMA) {
16552
+ const def = getConfigDefinition(key, registry2);
16553
+ if (!def) {
16554
+ throw new UnknownConfigKeyError(key);
16555
+ }
16556
+ return def;
16557
+ }
16558
+ var UnknownConfigKeyError = class extends Error {
16559
+ constructor(key) {
16560
+ super(`Unknown configuration key "${key}".`);
16561
+ this.key = key;
16562
+ this.name = "UnknownConfigKeyError";
16563
+ }
16564
+ key;
16565
+ };
16566
+
16382
16567
  // ../argent-tools-client/src/artifacts.ts
16383
16568
  var ARTIFACT_MARKER = "__argentArtifact";
16384
16569
  function isArtifactHandle(value) {
@@ -16414,6 +16599,21 @@ function durableBaseDir() {
16414
16599
  return projectRoot ?? dirname5(argentHomeDir());
16415
16600
  }
16416
16601
  var ALLOWED_SAVE_DIRS = /* @__PURE__ */ new Set([normalize(".argent/recordings")]);
16602
+ var RECORDINGS_SAVE_DIR = normalize(".argent/recordings");
16603
+ function configuredRecordingsDir() {
16604
+ let value;
16605
+ try {
16606
+ value = getConfigValueByKey("recordings.directory");
16607
+ } catch {
16608
+ return null;
16609
+ }
16610
+ if (typeof value !== "string") return null;
16611
+ const trimmed = value.trim();
16612
+ if (trimmed === "") return null;
16613
+ const home = dirname5(argentHomeDir());
16614
+ const expanded = trimmed === "~" ? home : trimmed.startsWith("~/") || trimmed.startsWith(`~${sep2}`) ? join8(home, trimmed.slice(2)) : trimmed;
16615
+ return resolve5(durableBaseDir(), expanded);
16616
+ }
16417
16617
  var MAX_DURABLE_BYTES = 2 * 1024 * 1024 * 1024;
16418
16618
  async function readCapped(res, cap) {
16419
16619
  const headers = res.headers;
@@ -16445,10 +16645,10 @@ async function writeDurableUnique(dir, filename, write) {
16445
16645
  const stem = filename.slice(0, filename.length - ext.length);
16446
16646
  for (let i = 1; i <= 1e3; i++) {
16447
16647
  const candidate = i === 1 ? filename : `${stem} (${i})${ext}`;
16448
- const path11 = join8(dir, candidate);
16648
+ const path12 = join8(dir, candidate);
16449
16649
  try {
16450
- await write(path11);
16451
- return path11;
16650
+ await write(path12);
16651
+ return path12;
16452
16652
  } catch (err) {
16453
16653
  if (err?.code === "EEXIST") continue;
16454
16654
  throw err;
@@ -16463,6 +16663,17 @@ function durableSaveTarget(handle) {
16463
16663
  return null;
16464
16664
  }
16465
16665
  if (!ALLOWED_SAVE_DIRS.has(rel)) return null;
16666
+ if (rel === RECORDINGS_SAVE_DIR) {
16667
+ const configured = configuredRecordingsDir();
16668
+ if (configured) {
16669
+ return {
16670
+ dir: configured,
16671
+ path: join8(configured, sanitizeSegment(handle.filename)),
16672
+ base: configured,
16673
+ rel: ""
16674
+ };
16675
+ }
16676
+ }
16466
16677
  const base = durableBaseDir();
16467
16678
  const dir = join8(base, rel);
16468
16679
  return { dir, path: join8(dir, sanitizeSegment(handle.filename)), base, rel };
@@ -18794,21 +19005,21 @@ var SESSION_ID2 = randomUUID5();
18794
19005
  // ../telemetry/src/identity.ts
18795
19006
  import * as crypto2 from "node:crypto";
18796
19007
  import * as fs4 from "node:fs";
18797
- import * as path8 from "node:path";
19008
+ import * as path9 from "node:path";
18798
19009
 
18799
19010
  // ../telemetry/src/paths.ts
18800
- import * as path7 from "node:path";
19011
+ import * as path8 from "node:path";
18801
19012
 
18802
19013
  // ../telemetry/src/fingerprint.ts
18803
19014
  import { execFileSync as execFileSync2, spawn as spawn2 } from "node:child_process";
18804
19015
 
18805
19016
  // ../native-devtools-ios/src/index.ts
18806
- import * as path9 from "node:path";
19017
+ import * as path10 from "node:path";
18807
19018
  import * as fs5 from "node:fs";
18808
- var DYLIB_DIR = process.env.ARGENT_NATIVE_DEVTOOLS_DIR ?? path9.join(__dirname, "..", "dylibs");
18809
- var BIN_DIR = process.env.ARGENT_SIMULATOR_SERVER_DIR ?? path9.join(__dirname, "..", "bin");
18810
- var DYLIB_TCP_DIR = process.env.ARGENT_NATIVE_DEVTOOLS_TCP_DIR ?? path9.join(DYLIB_DIR, "tcp");
18811
- var DYLIB_TVOS_DIR = path9.join(DYLIB_DIR, "tvos");
19019
+ var DYLIB_DIR = process.env.ARGENT_NATIVE_DEVTOOLS_DIR ?? path10.join(__dirname, "..", "dylibs");
19020
+ var BIN_DIR = process.env.ARGENT_SIMULATOR_SERVER_DIR ?? path10.join(__dirname, "..", "bin");
19021
+ var DYLIB_TCP_DIR = process.env.ARGENT_NATIVE_DEVTOOLS_TCP_DIR ?? path10.join(DYLIB_DIR, "tcp");
19022
+ var DYLIB_TVOS_DIR = path10.join(DYLIB_DIR, "tvos");
18812
19023
 
18813
19024
  // ../telemetry/src/consent.ts
18814
19025
  import * as fs6 from "node:fs";
@@ -19198,10 +19409,10 @@ function toMcpTool(t) {
19198
19409
 
19199
19410
  // ../argent-mcp/src/installed-version.ts
19200
19411
  import * as fs8 from "node:fs";
19201
- import * as path10 from "node:path";
19412
+ import * as path11 from "node:path";
19202
19413
  function getInstalledVersion() {
19203
19414
  try {
19204
- const pkgPath = path10.resolve(import.meta.dirname, "..", "package.json");
19415
+ const pkgPath = path11.resolve(import.meta.dirname, "..", "package.json");
19205
19416
  const pkg = JSON.parse(fs8.readFileSync(pkgPath, "utf8"));
19206
19417
  return pkg.version ?? "unknown";
19207
19418
  } catch {
@@ -98853,13 +98853,16 @@ function nonEmpty(value) {
98853
98853
  const trimmed = value.trim();
98854
98854
  return trimmed === "" ? null : value;
98855
98855
  }
98856
+ function resolveHomeDir(options = {}) {
98857
+ if (options.homeDir) return options.homeDir;
98858
+ return process.platform === "win32" ? nonEmpty(process.env.USERPROFILE) ?? os.homedir() : nonEmpty(process.env.HOME) ?? os.homedir();
98859
+ }
98856
98860
  function argentHomeDir() {
98857
- const home = process.platform === "win32" ? nonEmpty(process.env.USERPROFILE) ?? os.homedir() : nonEmpty(process.env.HOME) ?? os.homedir();
98858
- return path2.join(home, ".argent");
98861
+ return path2.join(resolveHomeDir(), ".argent");
98859
98862
  }
98860
98863
  function configDir(scope = "global", options = {}) {
98861
98864
  if (scope === "global") {
98862
- return options.homeDir ? path2.join(options.homeDir, ".argent") : argentHomeDir();
98865
+ return path2.join(resolveHomeDir(options), ".argent");
98863
98866
  }
98864
98867
  const cwd = options.cwd ?? process.cwd();
98865
98868
  return path2.join(resolveProjectRoot(cwd), ".argent");
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swmansion/argent",
3
- "version": "0.18.0",
3
+ "version": "0.18.1-next.1",
4
4
  "description": "MCP server for iOS Simulator and Android Emulator control",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -30,7 +30,7 @@ A recording does not stop itself before its `timeLimitSeconds` cap, so a forgott
30
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).
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 destination can be changed with the `recordings.directory` configuration (`argent config set recordings.directory <dir>`, global by default, `--scope project` for a per-repo choice; project wins when both are set) — the value may be absolute, `~`-prefixed, or relative to the project root, and is always resolved on the client host. 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
34
 
35
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).
36
36