@mnemonik/cli 7.109.2 → 7.110.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/dist/auth/credentials.js +297 -36
  2. package/dist/auth/index.d.ts +2 -0
  3. package/dist/auth/index.d.ts.map +1 -1
  4. package/dist/auth/index.js +1914 -19
  5. package/dist/auth/index.js.map +1 -1
  6. package/dist/auth/machineName.d.ts +8 -0
  7. package/dist/auth/machineName.d.ts.map +1 -0
  8. package/dist/auth/machineName.js +23 -0
  9. package/dist/auth/machineName.js.map +1 -0
  10. package/dist/consent.d.ts +29 -0
  11. package/dist/consent.d.ts.map +1 -0
  12. package/dist/consent.js +87 -0
  13. package/dist/consent.js.map +1 -0
  14. package/dist/diagnostics.js +301 -40
  15. package/dist/digests.json +102 -90
  16. package/dist/help.d.ts.map +1 -1
  17. package/dist/help.js +59 -44
  18. package/dist/help.js.map +1 -1
  19. package/dist/humanReason.d.ts +8 -0
  20. package/dist/humanReason.d.ts.map +1 -1
  21. package/dist/humanReason.js +44 -16
  22. package/dist/humanReason.js.map +1 -1
  23. package/dist/identity/migrate.js +1835 -44
  24. package/dist/install/hosts.d.ts +2 -0
  25. package/dist/install/hosts.d.ts.map +1 -1
  26. package/dist/install/hosts.js +23 -14
  27. package/dist/install/hosts.js.map +1 -1
  28. package/dist/install/journal.js +124 -11
  29. package/dist/install/journey.d.ts +20 -0
  30. package/dist/install/journey.d.ts.map +1 -1
  31. package/dist/install/journey.js +1913 -82
  32. package/dist/install/journey.js.map +1 -1
  33. package/dist/install/ownership.d.ts.map +1 -1
  34. package/dist/install/ownership.js +1818 -10
  35. package/dist/install/ownership.js.map +1 -1
  36. package/dist/install/transaction.js +1913 -19
  37. package/dist/install/ui.js +1910 -15
  38. package/dist/installation.js +133 -10
  39. package/dist/launcher.js +108 -4
  40. package/dist/output.d.ts +3 -0
  41. package/dist/output.d.ts.map +1 -1
  42. package/dist/output.js +11 -1
  43. package/dist/output.js.map +1 -1
  44. package/dist/preflight.d.ts +5 -0
  45. package/dist/preflight.d.ts.map +1 -1
  46. package/dist/preflight.js +14 -12
  47. package/dist/preflight.js.map +1 -1
  48. package/dist/project/eligibility.js +1917 -22
  49. package/dist/project/records.js +121 -8
  50. package/dist/project.d.ts +15 -0
  51. package/dist/project.d.ts.map +1 -1
  52. package/dist/project.js +229 -15
  53. package/dist/project.js.map +1 -1
  54. package/dist/router.d.ts +2 -0
  55. package/dist/router.d.ts.map +1 -1
  56. package/dist/router.js +2164 -122
  57. package/dist/router.js.map +1 -1
  58. package/dist/runtime/releaseSource.d.ts +6 -0
  59. package/dist/runtime/releaseSource.d.ts.map +1 -1
  60. package/dist/runtime/releaseSource.js +1933 -32
  61. package/dist/runtime/releaseSource.js.map +1 -1
  62. package/dist/runtime/selfUpdate.js +1809 -8
  63. package/dist/runtime/signers.js +28 -9
  64. package/dist/runtime/store.js +18 -6
  65. package/dist/runtime/updateCheck.d.ts +4 -0
  66. package/dist/runtime/updateCheck.d.ts.map +1 -0
  67. package/dist/runtime/updateCheck.js +6695 -0
  68. package/dist/runtime/updateCheck.js.map +1 -0
  69. package/dist/sbom.json +21 -21
  70. package/dist/scanner/control.d.ts +27 -1
  71. package/dist/scanner/control.d.ts.map +1 -1
  72. package/dist/scanner/control.js +207 -36
  73. package/dist/scanner/control.js.map +1 -1
  74. package/dist/scanner/discover.d.ts +5 -0
  75. package/dist/scanner/discover.d.ts.map +1 -1
  76. package/dist/scanner/discover.js +16 -6
  77. package/dist/scanner/discover.js.map +1 -1
  78. package/dist/scanner/enable.d.ts +2 -0
  79. package/dist/scanner/enable.d.ts.map +1 -1
  80. package/dist/scanner/enable.js +152 -14
  81. package/dist/scanner/enable.js.map +1 -1
  82. package/dist/scanner/picker.d.ts.map +1 -1
  83. package/dist/scanner/picker.js +5 -6
  84. package/dist/scanner/picker.js.map +1 -1
  85. package/dist/scanner/service.d.ts +2 -0
  86. package/dist/scanner/service.d.ts.map +1 -1
  87. package/dist/scanner/service.js +279 -54
  88. package/dist/scanner/service.js.map +1 -1
  89. package/dist/scanner/update.d.ts +8 -0
  90. package/dist/scanner/update.d.ts.map +1 -1
  91. package/dist/scanner/update.js +254 -20
  92. package/dist/scanner/update.js.map +1 -1
  93. package/dist/scanner-release.json +35 -30
  94. package/dist/screens/journey.d.ts +6 -1
  95. package/dist/screens/journey.d.ts.map +1 -1
  96. package/dist/screens/journey.js +29 -8
  97. package/dist/screens/journey.js.map +1 -1
  98. package/dist/status.d.ts +21 -0
  99. package/dist/status.d.ts.map +1 -1
  100. package/dist/status.js +1993 -39
  101. package/dist/status.js.map +1 -1
  102. package/dist/vendor/local-setup.js +256 -29
  103. package/dist/vendor/shared/runtimeSigners.js +38 -11
  104. package/package.json +31 -31
@@ -502,11 +502,73 @@ var require_ignore = __commonJS({
502
502
  });
503
503
 
504
504
  // packages/shared/dist/runtimeSigners.js
505
- var ttl;
505
+ import { basename, dirname as dirname2, join as join2, resolve, sep, win32 } from "node:path";
506
+ import { execFile, execFileSync } from "node:child_process";
507
+ function windowsCommand(file) {
508
+ const root = process.env.SystemRoot;
509
+ if (!root || !win32.isAbsolute(root))
510
+ throw new Error("acl_system_root_unavailable");
511
+ return win32.join(root, "System32", file);
512
+ }
513
+ function readIdentity(stdout) {
514
+ const match = /^"([^"\r\n]+)","(S-1-(?:\d+-)+\d+)"$/.exec(stdout.trim());
515
+ if (!match?.[1] || !match[2] || stdout.includes("\uFFFD"))
516
+ throw new Error("acl_identity_unavailable");
517
+ return { name: match[1], sid: match[2] };
518
+ }
519
+ function* readWindowsIdentity() {
520
+ const user = readIdentity(yield [windowsCommand("whoami.exe"), identityArgs]);
521
+ if (!ADMINISTRATOR_RID.test(user.sid))
522
+ return user;
523
+ const groups = yield [windowsCommand("whoami.exe"), groupArgs];
524
+ const local = /^"[^"\r\n]*","[^"\r\n]*","S-1-5-113",/m.test(groups);
525
+ return {
526
+ ...user,
527
+ localAdministratorSid: local ? `${user.sid.slice(0, user.sid.lastIndexOf("-"))}-500` : null
528
+ };
529
+ }
530
+ function windowsCurrentAccountSync() {
531
+ if (currentIdentity)
532
+ return currentIdentity;
533
+ const commands = readWindowsIdentity();
534
+ let step = commands.next();
535
+ while (!step.done)
536
+ step = commands.next(hookExecuteSync(...step.value));
537
+ return currentIdentity = step.value;
538
+ }
539
+ function hookInvocation(file, args2) {
540
+ if (win32.basename(file) === "whoami.exe") {
541
+ if ([file, ...args2].some((arg) => /[%!"\r\n]/.test(arg)))
542
+ throw new Error("acl_path_unavailable");
543
+ const command = args2.map((arg) => /^(?:[a-z0-9]+|\/[a-z]+)$/i.test(arg) ? arg : `"${arg}"`).join(" ");
544
+ return [
545
+ windowsCommand("cmd.exe"),
546
+ ["/d", "/v:off", "/s", "/c", `"chcp 65001>nul & "${file}" ${command}"`]
547
+ ];
548
+ }
549
+ if (win32.basename(file) === "cmd.exe")
550
+ return [file, ["/u", ...args2]];
551
+ return [file, args2];
552
+ }
553
+ function hookExecuteSync(file, args2, input) {
554
+ [file, args2] = hookInvocation(file, args2);
555
+ return execFileSync(file, args2, { ...hookOptions(file, args2), input });
556
+ }
557
+ var identityArgs, groupArgs, ADMINISTRATOR_RID, currentIdentity, ttl, hookOptions;
506
558
  var init_runtimeSigners = __esm({
507
559
  "packages/shared/dist/runtimeSigners.js"() {
508
560
  "use strict";
561
+ identityArgs = ["/user", "/fo", "csv", "/nh"];
562
+ groupArgs = ["/groups", "/fo", "csv", "/nh"];
563
+ ADMINISTRATOR_RID = /^S-1-5-21-\d+-\d+-\d+-500$/;
509
564
  ttl = 10 * 6e4;
565
+ hookOptions = (file, args2) => ({
566
+ encoding: args2.includes("/u") ? "utf16le" : "utf8",
567
+ timeout: win32.basename(file) === "powershell.exe" ? 3e4 : 5e3,
568
+ windowsHide: true,
569
+ maxBuffer: 16 * 1024 * 1024,
570
+ windowsVerbatimArguments: win32.basename(file) === "cmd.exe"
571
+ });
510
572
  }
511
573
  });
512
574
 
@@ -2075,12 +2137,12 @@ var require_adapter = __commonJS({
2075
2137
  return newFs;
2076
2138
  }
2077
2139
  function toPromise(method) {
2078
- return (...args2) => new Promise((resolve, reject) => {
2140
+ return (...args2) => new Promise((resolve2, reject) => {
2079
2141
  args2.push((err2, result) => {
2080
2142
  if (err2) {
2081
2143
  reject(err2);
2082
2144
  } else {
2083
- resolve(result);
2145
+ resolve2(result);
2084
2146
  }
2085
2147
  });
2086
2148
  method(...args2);
@@ -3763,13 +3825,13 @@ async function Module2(moduleArg = {}) {
3763
3825
  }
3764
3826
  readAsync = /* @__PURE__ */ __name(async (url) => {
3765
3827
  if (isFileURI(url)) {
3766
- return new Promise((resolve, reject) => {
3828
+ return new Promise((resolve2, reject) => {
3767
3829
  var xhr = new XMLHttpRequest();
3768
3830
  xhr.open("GET", url, true);
3769
3831
  xhr.responseType = "arraybuffer";
3770
3832
  xhr.onload = () => {
3771
3833
  if (xhr.status == 200 || xhr.status == 0 && xhr.response) {
3772
- resolve(xhr.response);
3834
+ resolve2(xhr.response);
3773
3835
  return;
3774
3836
  }
3775
3837
  reject(xhr.status);
@@ -3965,9 +4027,9 @@ async function Module2(moduleArg = {}) {
3965
4027
  __name(receiveInstantiationResult, "receiveInstantiationResult");
3966
4028
  var info22 = getWasmImports();
3967
4029
  if (Module["instantiateWasm"]) {
3968
- return new Promise((resolve, reject) => {
4030
+ return new Promise((resolve2, reject) => {
3969
4031
  Module["instantiateWasm"](info22, (mod, inst) => {
3970
- resolve(receiveInstance(mod, inst));
4032
+ resolve2(receiveInstance(mod, inst));
3971
4033
  });
3972
4034
  });
3973
4035
  }
@@ -5298,8 +5360,8 @@ async function Module2(moduleArg = {}) {
5298
5360
  if (runtimeInitialized) {
5299
5361
  moduleRtn = Module;
5300
5362
  } else {
5301
- moduleRtn = new Promise((resolve, reject) => {
5302
- readyPromiseResolve = resolve;
5363
+ moduleRtn = new Promise((resolve2, reject) => {
5364
+ readyPromiseResolve = resolve2;
5303
5365
  readyPromiseReject = reject;
5304
5366
  });
5305
5367
  }
@@ -6361,7 +6423,7 @@ function scannerAttemptHealthy(receipt, attempt, paused = false) {
6361
6423
  // packages/shared/dist/launchdControl.js
6362
6424
  import { setTimeout as delay } from "node:timers/promises";
6363
6425
  import { mkdir, readFile, rm, writeFile, lstat } from "node:fs/promises";
6364
- import { join as join2 } from "node:path";
6426
+ import { join as join3 } from "node:path";
6365
6427
  async function printLaunchdRegistration(domain, label, run2) {
6366
6428
  try {
6367
6429
  return await run2("launchctl", ["print", `${domain}/${label}`]);
@@ -6410,7 +6472,7 @@ async function removeMacScanner(state, home, uid, run2, options = {}) {
6410
6472
  return false;
6411
6473
  throw error;
6412
6474
  });
6413
- const receipt = await readFile(join2(state, "scanner/status.json"), "utf8").catch((error) => {
6475
+ const receipt = await readFile(join3(state, "scanner/status.json"), "utf8").catch((error) => {
6414
6476
  if (error.code === "ENOENT")
6415
6477
  return null;
6416
6478
  throw error;
@@ -6430,20 +6492,20 @@ async function removeMacScanner(state, home, uid, run2, options = {}) {
6430
6492
  const legacy = [`user/${uid}`, `gui/${uid}`];
6431
6493
  await stopLaunchdRegistrations(legacy, "ai.mnemonik.scanner.replacement", run2, options);
6432
6494
  await stopLaunchdRegistrations(legacy, "ai.mnemonik.scanner", run2, { ...options, recordedPid });
6433
- await rm(join2(state, "scanner/service-replacement"), { recursive: true, force: true });
6495
+ await rm(join3(state, "scanner/service-replacement"), { recursive: true, force: true });
6434
6496
  if (options.remove === false) {
6435
- await mkdir(join2(state, "scanner/service-replacement"), { recursive: true });
6436
- await writeFile(join2(state, "scanner/service-replacement/result.json"), JSON.stringify({ stopped: true }));
6497
+ await mkdir(join3(state, "scanner/service-replacement"), { recursive: true });
6498
+ await writeFile(join3(state, "scanner/service-replacement/result.json"), JSON.stringify({ stopped: true }));
6437
6499
  return;
6438
6500
  }
6439
6501
  if (present || launcherPresent)
6440
6502
  await run2("sudo", ["-n", "/bin/rm", "-f", plist, launcher]);
6441
6503
  for (const label of ["ai.mnemonik.scanner", "ai.mnemonik.scanner.replacement"])
6442
- await rm(join2(home, "Library/LaunchAgents", `${label}.plist`), { force: true });
6443
- await rm(join2(state, "scanner/assets"), { recursive: true, force: true });
6444
- await rm(join2(state, "scanner/service-supervisor.json"), { force: true });
6445
- await rm(join2(state, "scanner/service-migrated"), { force: true });
6446
- await rm(join2(state, "scanner/system-service.plist"), { force: true });
6504
+ await rm(join3(home, "Library/LaunchAgents", `${label}.plist`), { force: true });
6505
+ await rm(join3(state, "scanner/assets"), { recursive: true, force: true });
6506
+ await rm(join3(state, "scanner/service-supervisor.json"), { force: true });
6507
+ await rm(join3(state, "scanner/service-migrated"), { force: true });
6508
+ await rm(join3(state, "scanner/system-service.plist"), { force: true });
6447
6509
  }
6448
6510
  async function stopLaunchdRegistrations(domains, label, run2, options = {}) {
6449
6511
  const now = options.now ?? Date.now;
@@ -6487,11 +6549,11 @@ async function stopLaunchdRegistrations(domains, label, run2, options = {}) {
6487
6549
  // packages/shared/dist/systemdControl.js
6488
6550
  import { existsSync } from "node:fs";
6489
6551
  import { rm as rm2 } from "node:fs/promises";
6490
- import { basename, dirname as dirname2, join as join3 } from "node:path";
6552
+ import { basename as basename2, dirname as dirname3, join as join4 } from "node:path";
6491
6553
  import { setTimeout as delay2 } from "node:timers/promises";
6492
6554
  async function uninstallSystemdUnit(unitPath, run2, options = {}) {
6493
6555
  try {
6494
- const unit = basename(unitPath);
6556
+ const unit = basename2(unitPath);
6495
6557
  if (!/^mnemonik-scanner(?:-test-[0-9]+)?\.service$/.test(unit))
6496
6558
  throw new Error("invalid_test_unit");
6497
6559
  const command = (args2) => run2("systemctl", ["--user", ...args2]);
@@ -6523,7 +6585,7 @@ async function uninstallSystemdUnit(unitPath, run2, options = {}) {
6523
6585
  } catch (error) {
6524
6586
  if (existsSync(unitPath) || !new RegExp(`Unit file ${unit.replaceAll(".", "\\.")} does not exist\\.?\\s*$`).test(error.message))
6525
6587
  throw error;
6526
- await rm2(join3(dirname2(unitPath), "default.target.wants", unit), { force: true });
6588
+ await rm2(join4(dirname3(unitPath), "default.target.wants", unit), { force: true });
6527
6589
  await command(["daemon-reload"]);
6528
6590
  }
6529
6591
  if ((await inspect()).ActiveState === "failed")
@@ -6552,7 +6614,7 @@ async function uninstallSystemdUnit(unitPath, run2, options = {}) {
6552
6614
  }
6553
6615
 
6554
6616
  // packages/shared/dist/scannerPid.js
6555
- import { execFileSync } from "node:child_process";
6617
+ import { execFileSync as execFileSync2 } from "node:child_process";
6556
6618
  import { readFileSync } from "node:fs";
6557
6619
  var SCANNER_CMD_PATTERN = /(mnemonik-scanner|scanner[\\/]dist[\\/]index\.js)/;
6558
6620
  var capture = {
@@ -6560,7 +6622,7 @@ var capture = {
6560
6622
  stdio: ["ignore", "pipe", "ignore"],
6561
6623
  timeout: 5e3
6562
6624
  };
6563
- function processCmdline(pid, platform, exec = execFileSync) {
6625
+ function processCmdline(pid, platform, exec = execFileSync2) {
6564
6626
  if (!Number.isSafeInteger(pid) || pid <= 0)
6565
6627
  return null;
6566
6628
  if (platform === "win32") {
@@ -6587,7 +6649,7 @@ function processCmdline(pid, platform, exec = execFileSync) {
6587
6649
  return null;
6588
6650
  }
6589
6651
  }
6590
- function pidIsScanner(pid, platform = process.platform, exec = execFileSync, identity) {
6652
+ function pidIsScanner(pid, platform = process.platform, exec = execFileSync2, identity) {
6591
6653
  const cmdline = processCmdline(pid, platform, exec);
6592
6654
  if (cmdline === null)
6593
6655
  return false;
@@ -6604,11 +6666,13 @@ function pidIsScanner(pid, platform = process.platform, exec = execFileSync, ide
6604
6666
 
6605
6667
  // packages/local-setup/dist/storage.js
6606
6668
  init_hookRuntime();
6669
+ init_hookRuntime();
6607
6670
  import { createHash, randomUUID } from "node:crypto";
6671
+ import { execFile as nodeExecFile } from "node:child_process";
6608
6672
  import fs2 from "node:fs";
6609
6673
  import { open, rename, readFile as readFile2, mkdir as mkdir2, lstat as lstat2, chmod, writeFile as writeFile2, unlink, rmdir } from "node:fs/promises";
6610
- init_hookRuntime();
6611
- import { dirname as dirname3, join as join4, win32, posix } from "node:path";
6674
+ import { homedir } from "node:os";
6675
+ import { dirname as dirname4, join as join5, win32 as win322, posix } from "node:path";
6612
6676
  import { setTimeout as delay3 } from "node:timers/promises";
6613
6677
  var lockfileKey = /* @__PURE__ */ Symbol.for("mnemonik.proper-lockfile");
6614
6678
  function sharedLockfile() {
@@ -6616,6 +6680,15 @@ function sharedLockfile() {
6616
6680
  return shared[lockfileKey] ??= Promise.resolve().then(() => __toESM(require_proper_lockfile(), 1)).then((module2) => module2.default);
6617
6681
  }
6618
6682
  var codeIs = (error, code) => error.code === code;
6683
+ function stateDirectory(platform = process.platform, env = process.env, home = homedir()) {
6684
+ if (env.MNEMONIK_STATE_DIR)
6685
+ return env.MNEMONIK_STATE_DIR;
6686
+ if (platform === "win32")
6687
+ return win322.join(env.LOCALAPPDATA || win322.join(home, "AppData", "Local"), "Mnemonik");
6688
+ if (platform === "darwin")
6689
+ return posix.join(home, "Library", "Application Support", "Mnemonik");
6690
+ return posix.join(env.XDG_STATE_HOME || posix.join(home, ".local", "state"), "mnemonik");
6691
+ }
6619
6692
  async function readBytes(path) {
6620
6693
  try {
6621
6694
  if (!(await lstat2(path)).isFile())
@@ -6627,11 +6700,69 @@ async function readBytes(path) {
6627
6700
  throw error;
6628
6701
  }
6629
6702
  }
6703
+ async function syncDirectory(path) {
6704
+ if (process.platform === "win32")
6705
+ return;
6706
+ const fd = await open(path, "r");
6707
+ try {
6708
+ await fd.sync();
6709
+ } finally {
6710
+ await fd.close();
6711
+ }
6712
+ }
6713
+ var windowsCurrentAccount = windowsCurrentAccountSync;
6714
+ async function windowsCurrentUserAcl(path, directory = false, options = {}, created = false) {
6715
+ const username = options.username ?? `*${windowsCurrentAccount().sid}`;
6716
+ const grant = `${username}:${directory ? "(OI)(CI)F" : "F"}`;
6717
+ const execFile3 = options.execFile ?? nodeExecFile;
6718
+ await new Promise((resolve2, reject) => {
6719
+ execFile3("icacls.exe", [
6720
+ path,
6721
+ "/inheritance:r",
6722
+ "/grant:r",
6723
+ grant,
6724
+ ...created ? ["/remove:g", "*S-1-5-32-544", "*S-1-5-18"] : []
6725
+ ], (error) => {
6726
+ if (error)
6727
+ reject(error);
6728
+ else
6729
+ resolve2();
6730
+ });
6731
+ });
6732
+ }
6733
+ async function protectStateFile(path, platform = process.platform, aclOptions) {
6734
+ if (platform === "win32")
6735
+ await windowsCurrentUserAcl(path, false, aclOptions);
6736
+ else
6737
+ await chmod(path, 384);
6738
+ return "private";
6739
+ }
6740
+ async function atomicWrite(path, bytes, fault, assertOwned) {
6741
+ await assertOwned?.();
6742
+ const temp = `${path}.${randomUUID()}.tmp`;
6743
+ const fd = await open(temp, "wx", 384);
6744
+ let permissionStatus;
6745
+ try {
6746
+ permissionStatus = await protectStateFile(temp);
6747
+ const split = Math.ceil(bytes.length / 2);
6748
+ await fd.writeFile(bytes.subarray(0, split));
6749
+ await fault?.("mid_write");
6750
+ await assertOwned?.();
6751
+ await fd.writeFile(bytes.subarray(split));
6752
+ await fd.sync();
6753
+ } finally {
6754
+ await fd.close();
6755
+ }
6756
+ await assertOwned?.();
6757
+ await rename(temp, path);
6758
+ await syncDirectory(dirname4(path));
6759
+ return permissionStatus;
6760
+ }
6630
6761
  async function withLock(path, waitMs, work) {
6631
6762
  const lockfile = await sharedLockfile();
6632
- await mkdir2(dirname3(path), { recursive: true, mode: 448 });
6763
+ await mkdir2(dirname4(path), { recursive: true, mode: 448 });
6633
6764
  const generation = randomUUID();
6634
- const owner = join4(`${path}.lock`, "owner");
6765
+ const owner = join5(`${path}.lock`, "owner");
6635
6766
  let compromised = false;
6636
6767
  let acquired = false;
6637
6768
  const assertOwned = async () => {
@@ -6646,14 +6777,14 @@ async function withLock(path, waitMs, work) {
6646
6777
  void mkdir2(dir).then(() => writeFile2(owner, generation, { mode: 384, flag: "wx" })).then(() => callback(), callback);
6647
6778
  },
6648
6779
  rmdir: (dir, callback) => {
6649
- void unlink(join4(dir, "owner")).catch((error) => {
6780
+ void unlink(join5(dir, "owner")).catch((error) => {
6650
6781
  if (!codeIs(error, "ENOENT"))
6651
6782
  throw error;
6652
6783
  }).then(() => rmdir(dir)).then(() => callback(), callback);
6653
6784
  },
6654
6785
  rmdirSync: (dir) => {
6655
6786
  try {
6656
- fs2.unlinkSync(join4(dir, "owner"));
6787
+ fs2.unlinkSync(join5(dir, "owner"));
6657
6788
  } catch (error) {
6658
6789
  if (!codeIs(error, "ENOENT"))
6659
6790
  throw error;
@@ -6695,14 +6826,108 @@ async function withLock(path, waitMs, work) {
6695
6826
  }
6696
6827
  }
6697
6828
 
6829
+ // packages/local-setup/dist/automaticUpdate.js
6830
+ import { spawn as nodeSpawn } from "node:child_process";
6831
+ import { realpathSync } from "node:fs";
6832
+ import { stat as nodeStat, utimes } from "node:fs/promises";
6833
+ import { homedir as homedir2 } from "node:os";
6834
+ import { join as join6 } from "node:path";
6835
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
6836
+ var DAY_MS = 864e5;
6837
+ var statePath = (stateDir) => join6(stateDir, "automatic-update.json");
6838
+ function cliLauncherPath(options = {}) {
6839
+ const platform = options.platform ?? process.platform;
6840
+ const home = options.home ?? homedir2();
6841
+ return platform === "win32" ? join6(options.env?.LOCALAPPDATA || join6(home, "AppData", "Local"), "Mnemonik", "bin", "mnemonik.cmd") : join6(home, ".local", "bin", "mnemonik");
6842
+ }
6843
+ async function readState(path) {
6844
+ const bytes = await readBytes(path);
6845
+ if (!bytes)
6846
+ return {};
6847
+ const value = JSON.parse(bytes.toString());
6848
+ if (!value || typeof value !== "object" || value.lastAttempt !== void 0 && (!Number.isFinite(value.lastAttempt) || value.lastAttempt < 0))
6849
+ throw new Error("automatic_update_state_invalid");
6850
+ return value.lastAttempt === void 0 ? {} : { lastAttempt: value.lastAttempt };
6851
+ }
6852
+ async function maybeStartAutomaticUpdate(options = {}) {
6853
+ const stateDir = options.stateDir ?? stateDirectory(options.platform, options.env, options.home);
6854
+ const path = statePath(stateDir);
6855
+ try {
6856
+ const now = (options.now ?? Date.now)();
6857
+ const stat = options.stat ?? nodeStat;
6858
+ try {
6859
+ if (now - (await stat(path)).mtimeMs < DAY_MS)
6860
+ return false;
6861
+ } catch (error) {
6862
+ if (error.code !== "ENOENT")
6863
+ throw error;
6864
+ }
6865
+ if (!options.spawn && !(await stat(cliLauncherPath(options))).isFile())
6866
+ return false;
6867
+ return await withLock(path, 0, async (assertOwned) => {
6868
+ const state = await readState(path);
6869
+ if (state.lastAttempt !== void 0 && now - state.lastAttempt < DAY_MS)
6870
+ return false;
6871
+ await atomicWrite(path, Buffer.from(`${JSON.stringify({ lastAttempt: now })}
6872
+ `), void 0, assertOwned);
6873
+ await utimes(path, now / 1e3, now / 1e3);
6874
+ const platform = options.platform ?? process.platform;
6875
+ const launcher = cliLauncherPath(options);
6876
+ const command = platform === "win32" ? {
6877
+ file: options.env?.ComSpec || "cmd.exe",
6878
+ args: ["/d", "/s", "/c", `""${launcher}" update --automatic"`],
6879
+ windowsVerbatimArguments: true
6880
+ } : platform === "linux" && (options.env ?? process.env).INVOCATION_ID ? {
6881
+ // detached creates a process group, not a new systemd cgroup. An
6882
+ // updater spawned by the scanner must survive stopping that service.
6883
+ file: "systemd-run",
6884
+ args: [
6885
+ "--user",
6886
+ "--collect",
6887
+ "--quiet",
6888
+ `--setenv=MNEMONIK_STATE_DIR=${stateDir}`,
6889
+ "--",
6890
+ launcher,
6891
+ "update",
6892
+ "--automatic"
6893
+ ]
6894
+ } : { file: launcher, args: ["update", "--automatic"] };
6895
+ const child = (options.spawn ?? nodeSpawn)(command.file, command.args, {
6896
+ detached: true,
6897
+ stdio: "ignore",
6898
+ windowsHide: true,
6899
+ ..."windowsVerbatimArguments" in command ? { windowsVerbatimArguments: command.windowsVerbatimArguments } : {}
6900
+ });
6901
+ child.once("error", () => {
6902
+ });
6903
+ child.unref();
6904
+ return true;
6905
+ });
6906
+ } catch {
6907
+ return false;
6908
+ }
6909
+ }
6910
+ var HELPER_FLAG = "--mnemonik-automatic-update";
6911
+ function isHelperInvocation() {
6912
+ if (process.argv[2] !== HELPER_FLAG || !process.argv[3] || !process.argv[1])
6913
+ return false;
6914
+ try {
6915
+ return realpathSync(process.argv[1]) === realpathSync(fileURLToPath2(import.meta.url));
6916
+ } catch {
6917
+ return false;
6918
+ }
6919
+ }
6920
+ if (isHelperInvocation())
6921
+ void maybeStartAutomaticUpdate({ stateDir: process.argv[3] });
6922
+
6698
6923
  // packages/local-setup/dist/index.js
6699
6924
  var MAX_ORIGINAL_BYTES = 64 * 1024;
6700
6925
 
6701
6926
  // packages/cli/src/scanner/service.ts
6702
- import { execFile } from "node:child_process";
6927
+ import { execFile as execFile2 } from "node:child_process";
6703
6928
  import { readFile as readFile3, rm as rm3, lstat as lstat3 } from "node:fs/promises";
6704
- import { join as join5, dirname as dirname4 } from "node:path";
6705
- import { homedir } from "node:os";
6929
+ import { join as join7, dirname as dirname5 } from "node:path";
6930
+ import { homedir as homedir3 } from "node:os";
6706
6931
  import { promisify } from "node:util";
6707
6932
  import { setTimeout as delay4 } from "node:timers/promises";
6708
6933
  import { RuntimeStore } from "../runtime/store.js";
@@ -6778,7 +7003,7 @@ function scannerService(options) {
6778
7003
  const configureStore = async () => {
6779
7004
  if (!options.store) {
6780
7005
  const saved = JSON.parse(
6781
- await new RuntimeStore(options.stateDir).bytes(join5(options.stateDir, "scanner/state.json")).then((bytes) => bytes.toString()).catch((error) => {
7006
+ await new RuntimeStore(options.stateDir).bytes(join7(options.stateDir, "scanner/state.json")).then((bytes) => bytes.toString()).catch((error) => {
6782
7007
  if (error.code === "ENOENT") return "null";
6783
7008
  throw error;
6784
7009
  })
@@ -6805,8 +7030,8 @@ function scannerService(options) {
6805
7030
  if (fixed && (!fixed.isFile() || fixed.uid !== 0 || fixed.mode & 18))
6806
7031
  throw new Error("service_runtime_permission");
6807
7032
  const entry = fixed ? macScannerLauncher : (retained ? await store.verifyRetainedRuntime("scanner", retained.reference) : await verify()).entry;
6808
- return new Promise((resolve, reject) => {
6809
- const child = execFile(
7033
+ return new Promise((resolve2, reject) => {
7034
+ const child = execFile2(
6810
7035
  entry,
6811
7036
  ["service", operation, "--json"],
6812
7037
  {
@@ -6829,7 +7054,7 @@ function scannerService(options) {
6829
7054
  return;
6830
7055
  }
6831
7056
  try {
6832
- resolve(JSON.parse(stdout));
7057
+ resolve2(JSON.parse(stdout));
6833
7058
  } catch (error2) {
6834
7059
  reject(error2);
6835
7060
  }
@@ -6883,7 +7108,7 @@ function scannerService(options) {
6883
7108
  const describe = async () => {
6884
7109
  const runtime = await verify();
6885
7110
  return options.describe ? await options.describe() : JSON.parse(
6886
- (await promisify(execFile)(runtime.entry, ["service", "describe", "--json"], {
7111
+ (await promisify(execFile2)(runtime.entry, ["service", "describe", "--json"], {
6887
7112
  env: {
6888
7113
  ...process.env,
6889
7114
  MNEMONIK_STATE_DIR: options.stateDir,
@@ -6898,13 +7123,13 @@ function scannerService(options) {
6898
7123
  async recover() {
6899
7124
  if ((options.platform ?? process.platform) !== "darwin") return false;
6900
7125
  return withLock(
6901
- join5(options.stateDir, "scanner/launchd-replacement-control"),
7126
+ join7(options.stateDir, "scanner/launchd-replacement-control"),
6902
7127
  5e3,
6903
7128
  async () => {
6904
7129
  const receipt = await scannerReceipt(options.stateDir);
6905
7130
  const snapshot = receipt?.snapshot;
6906
7131
  const attempt = await readFile3(
6907
- join5(options.stateDir, "scanner/service-replacement/result.json"),
7132
+ join7(options.stateDir, "scanner/service-replacement/result.json"),
6908
7133
  "utf8"
6909
7134
  ).then((text) => JSON.parse(text)).catch(() => null);
6910
7135
  const age = now() - Number(attempt?.startedAt);
@@ -6916,7 +7141,7 @@ function scannerService(options) {
6916
7141
  if (receipt && snapshot?.lifecycle.pid === pid && (snapshot.lifecycle.state === "paused" || now() - receipt.recordedAt <= SCANNER_RECEIPT_STALE_MS))
6917
7142
  return false;
6918
7143
  const state = JSON.parse(
6919
- await readFile3(join5(options.stateDir, "scanner/state.json"), "utf8")
7144
+ await readFile3(join7(options.stateDir, "scanner/state.json"), "utf8")
6920
7145
  );
6921
7146
  if (state.paused) return false;
6922
7147
  let runtime = await verify();
@@ -6985,7 +7210,7 @@ function scannerService(options) {
6985
7210
  },
6986
7211
  async exportPreview(out2) {
6987
7212
  const runtime = await verify();
6988
- return promisify(execFile)(runtime.entry, ["export-preview", "--out", out2], {
7213
+ return promisify(execFile2)(runtime.entry, ["export-preview", "--out", out2], {
6989
7214
  env: {
6990
7215
  ...process.env,
6991
7216
  MNEMONIK_STATE_DIR: options.stateDir,
@@ -6998,7 +7223,7 @@ function scannerService(options) {
6998
7223
  replacementRuntime = runtime;
6999
7224
  verified = false;
7000
7225
  const saved = JSON.parse(
7001
- replacement.state?.after ?? await readFile3(join5(options.stateDir, "scanner/state.json"), "utf8")
7226
+ replacement.state?.after ?? await readFile3(join7(options.stateDir, "scanner/state.json"), "utf8")
7002
7227
  );
7003
7228
  const startedAt = now();
7004
7229
  await invoke("install", {
@@ -7009,13 +7234,13 @@ function scannerService(options) {
7009
7234
  credentialFamilyId: saved.config?.credentialFamilyId,
7010
7235
  runAtLogin: true,
7011
7236
  restart: { policy: "on-failure", delayMs: 3e3 },
7012
- logDestination: join5(options.stateDir, "scanner/scanner.log"),
7237
+ logDestination: join7(options.stateDir, "scanner/scanner.log"),
7013
7238
  replacement
7014
7239
  });
7015
7240
  const deadline = now() + SCANNER_HANDOFF_BUDGET_MS;
7016
7241
  while (now() < deadline) {
7017
7242
  const attempt = await readFile3(
7018
- join5(options.stateDir, "scanner/service-replacement/result.json"),
7243
+ join7(options.stateDir, "scanner/service-replacement/result.json"),
7019
7244
  "utf8"
7020
7245
  ).then(JSON.parse).catch(() => null);
7021
7246
  if (attempt && attempt.startedAt >= startedAt) {
@@ -7051,34 +7276,34 @@ function scannerService(options) {
7051
7276
  await invoke("stop");
7052
7277
  },
7053
7278
  async uninstall() {
7054
- const native = (timeout) => options.supervisorRun ?? (async (file, args2) => (await promisify(execFile)(file, args2, { encoding: "utf8", timeout })).stdout);
7279
+ const native = (timeout) => options.supervisorRun ?? (async (file, args2) => (await promisify(execFile2)(file, args2, { encoding: "utf8", timeout })).stdout);
7055
7280
  try {
7056
7281
  if ((options.platform ?? process.platform) === "darwin") {
7057
7282
  return await withLock(
7058
- join5(options.stateDir, "scanner/launchd-replacement-control"),
7283
+ join7(options.stateDir, "scanner/launchd-replacement-control"),
7059
7284
  SCANNER_REMOVAL_BUDGET_MS,
7060
7285
  async () => {
7061
7286
  await removeMacScanner(
7062
7287
  options.stateDir,
7063
- options.home ?? homedir(),
7288
+ options.home ?? homedir3(),
7064
7289
  options.uid ?? process.getuid?.() ?? -1,
7065
7290
  native(SCANNER_REMOVAL_BUDGET_MS),
7066
7291
  { now, sleep, plist: options.systemPlist }
7067
7292
  );
7068
- await rm3(dirname4(store.pointerPath("scanner")), { recursive: true, force: true });
7293
+ await rm3(dirname5(store.pointerPath("scanner")), { recursive: true, force: true });
7069
7294
  }
7070
7295
  );
7071
7296
  }
7072
7297
  if ((options.platform ?? process.platform) === "linux") {
7073
- const recordedPid = await readFile3(join5(options.stateDir, "scanner/status.json"), "utf8").then(
7298
+ const recordedPid = await readFile3(join7(options.stateDir, "scanner/status.json"), "utf8").then(
7074
7299
  (text) => JSON.parse(text).snapshot?.lifecycle?.pid
7075
7300
  ).catch((error) => {
7076
7301
  if (error.code === "ENOENT") return void 0;
7077
7302
  throw error;
7078
7303
  });
7079
7304
  await uninstallSystemdUnit(
7080
- join5(
7081
- process.env.XDG_CONFIG_HOME ?? join5(options.home ?? homedir(), ".config"),
7305
+ join7(
7306
+ process.env.XDG_CONFIG_HOME ?? join7(options.home ?? homedir3(), ".config"),
7082
7307
  "systemd/user/mnemonik-scanner.service"
7083
7308
  ),
7084
7309
  native(SCANNER_STOP_BUDGET_MS),
@@ -7088,7 +7313,7 @@ function scannerService(options) {
7088
7313
  await invoke("stop");
7089
7314
  await invoke("uninstall");
7090
7315
  }
7091
- await rm3(dirname4(store.pointerPath("scanner")), { recursive: true, force: true });
7316
+ await rm3(dirname5(store.pointerPath("scanner")), { recursive: true, force: true });
7092
7317
  } catch (error) {
7093
7318
  const cause = error.cause;
7094
7319
  throw new ScannerServiceLimited(