@mnemonik/cli 7.109.3 → 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,7 +502,9 @@ var require_ignore = __commonJS({
502
502
  });
503
503
 
504
504
  // packages/shared/dist/runtimeSigners.js
505
+ import { lstatSync, mkdirSync, readFileSync, writeFileSync, renameSync, unlinkSync } from "node:fs";
505
506
  import { basename, dirname as dirname2, join as join2, resolve, sep, win32 } from "node:path";
507
+ import { createHash, createPublicKey, randomUUID, timingSafeEqual, verify as verifySignature } from "node:crypto";
506
508
  import { execFile, execFileSync } from "node:child_process";
507
509
  function windowsCommand(file) {
508
510
  const root = process.env.SystemRoot;
@@ -510,14 +512,44 @@ function windowsCommand(file) {
510
512
  throw new Error("acl_system_root_unavailable");
511
513
  return win32.join(root, "System32", file);
512
514
  }
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"))
515
+ function readIdentity(stdout2) {
516
+ const match = /^"([^"\r\n]+)","(S-1-(?:\d+-)+\d+)"$/.exec(stdout2.trim());
517
+ if (!match?.[1] || !match[2] || stdout2.includes("\uFFFD"))
516
518
  throw new Error("acl_identity_unavailable");
517
519
  return { name: match[1], sid: match[2] };
518
520
  }
521
+ function* readWindowsIdentity() {
522
+ const user = readIdentity(yield [windowsCommand("whoami.exe"), identityArgs]);
523
+ if (!ADMINISTRATOR_RID.test(user.sid))
524
+ return user;
525
+ const groups = yield [windowsCommand("whoami.exe"), groupArgs];
526
+ const local = /^"[^"\r\n]*","[^"\r\n]*","S-1-5-113",/m.test(groups);
527
+ return {
528
+ ...user,
529
+ localAdministratorSid: local ? `${user.sid.slice(0, user.sid.lastIndexOf("-"))}-500` : null
530
+ };
531
+ }
519
532
  function windowsCurrentAccountSync() {
520
- return currentIdentity ??= readIdentity(hookExecuteSync(windowsCommand("whoami.exe"), identityArgs));
533
+ if (currentIdentity)
534
+ return currentIdentity;
535
+ const commands = readWindowsIdentity();
536
+ let step = commands.next();
537
+ while (!step.done)
538
+ step = commands.next(hookExecuteSync(...step.value));
539
+ return currentIdentity = step.value;
540
+ }
541
+ async function windowsIdentity(run2) {
542
+ if (currentIdentity)
543
+ return currentIdentity;
544
+ identityPending ??= drive(readWindowsIdentity(), run2).then((identity) => currentIdentity = identity).finally(() => {
545
+ identityPending = void 0;
546
+ });
547
+ return identityPending;
548
+ }
549
+ async function verifyWindowsAcl(path, run2 = hookExecute, state) {
550
+ const user = await windowsIdentity(run2);
551
+ if (!privateEntries((await drive(saveAcl(path, false, [path], state), run2)).get(path), user, false))
552
+ throw new Error("acl_permissions");
521
553
  }
522
554
  function hookInvocation(file, args2) {
523
555
  if (win32.basename(file) === "whoami.exe") {
@@ -537,12 +569,112 @@ function hookExecuteSync(file, args2, input) {
537
569
  [file, args2] = hookInvocation(file, args2);
538
570
  return execFileSync(file, args2, { ...hookOptions(file, args2), input });
539
571
  }
540
- var identityArgs, currentIdentity, ttl, hookOptions;
572
+ function aclRecords(output, root, paths, onLookup) {
573
+ const records = /* @__PURE__ */ new Map();
574
+ const wanted = new Set(paths);
575
+ const lines = output.replace(/^\uFEFF/, "").trimEnd().split(/\r?\n/);
576
+ if (lines.length % 2)
577
+ throw new Error("acl_unavailable");
578
+ for (let index = 0; index < lines.length; index += 2) {
579
+ onLookup?.();
580
+ const relativePath = lines[index];
581
+ const descriptor = lines[index + 1];
582
+ if (relativePath === void 0 || descriptor === void 0)
583
+ throw new Error("acl_unavailable");
584
+ const path = resolve(dirname2(root), relativePath.replaceAll("\\", sep));
585
+ if (!wanted.has(path))
586
+ continue;
587
+ if (records.has(path))
588
+ throw new Error("acl_unavailable");
589
+ const dacl = /^D:(?:P|AI|AR)*((?:\([^()]*\))*)$/.exec(descriptor);
590
+ records.set(path, dacl?.[1]?.match(/\([^()]*\)/g) ?? []);
591
+ }
592
+ return records;
593
+ }
594
+ function privateEntries(entries, user, directory) {
595
+ if (!entries?.length)
596
+ throw new Error("acl_unavailable");
597
+ return entries.every((line) => {
598
+ const ace = /^\(([AD]);((?:OI|CI|NP|IO|ID|SA|FA)*);[A-Za-z0-9]+;;;((?:S-1-(?:\d+-)+\d+)|[A-Z]{2})\)$/.exec(line);
599
+ if (!ace)
600
+ throw new Error("acl_unavailable");
601
+ const sid = ace[3] === "LA" ? user.localAdministratorSid : ace[3];
602
+ return (!directory || !ace[2]?.includes("ID")) && (ace[1] === "D" || sid === user.sid);
603
+ });
604
+ }
605
+ function* prepareAclDirectory(state) {
606
+ const directory = join2(state, "audit-tmp");
607
+ if (auditDirectories.has(directory)) {
608
+ const stat2 = lstatSync(directory);
609
+ if (!stat2.isDirectory() || stat2.isSymbolicLink())
610
+ throw new Error("acl_permissions");
611
+ return directory;
612
+ }
613
+ let created = false;
614
+ try {
615
+ mkdirSync(directory, { mode: 448 });
616
+ created = true;
617
+ } catch (error) {
618
+ if (error.code !== "EEXIST")
619
+ throw error;
620
+ }
621
+ const stat = lstatSync(directory);
622
+ if (!stat.isDirectory() || stat.isSymbolicLink())
623
+ throw new Error("acl_permissions");
624
+ if (!auditDirectories.has(directory)) {
625
+ currentIdentity ??= yield* readWindowsIdentity();
626
+ yield [windowsCommand("icacls.exe"), aclArgs(directory, currentIdentity.sid, created)];
627
+ if (!created) {
628
+ const temp = join2(directory, `.acl-${randomUUID()}.tmp`);
629
+ writeFileSync(temp, "", { flag: "wx", mode: 384 });
630
+ try {
631
+ yield [windowsCommand("icacls.exe"), [directory, "/save", temp, "/l"]];
632
+ if (!privateEntries(aclRecords(readFileSync(temp, "utf16le"), directory, [directory]).get(directory), currentIdentity, true))
633
+ throw new Error("acl_permissions");
634
+ } finally {
635
+ unlinkSync(temp);
636
+ }
637
+ }
638
+ auditDirectories.add(directory);
639
+ }
640
+ return directory;
641
+ }
642
+ function* saveAcl(path, recursive, paths = [path], state = lstatSync(path).isDirectory() ? path : dirname2(path)) {
643
+ const directory = yield* prepareAclDirectory(state);
644
+ const temp = join2(directory, `.acl-${randomUUID()}.tmp`);
645
+ writeFileSync(temp, "", { flag: "wx", mode: 384 });
646
+ try {
647
+ yield [windowsCommand("icacls.exe"), [path, "/save", temp, ...recursive ? ["/t"] : [], "/l"]];
648
+ return aclRecords(readFileSync(temp, "utf16le"), path, paths.filter((item) => item !== directory && !item.startsWith(directory + sep)));
649
+ } finally {
650
+ unlinkSync(temp);
651
+ }
652
+ }
653
+ async function drive(commands, run2) {
654
+ try {
655
+ let step = commands.next();
656
+ while (!step.done)
657
+ step = commands.next(stdout(await run2(...step.value)));
658
+ return step.value;
659
+ } finally {
660
+ commands.return(void 0);
661
+ }
662
+ }
663
+ var identityArgs, groupArgs, ADMINISTRATOR_RID, currentIdentity, ttl, identityPending, aclArgs, hookOptions, hookExecute, stdout, auditDirectories;
541
664
  var init_runtimeSigners = __esm({
542
665
  "packages/shared/dist/runtimeSigners.js"() {
543
666
  "use strict";
544
667
  identityArgs = ["/user", "/fo", "csv", "/nh"];
668
+ groupArgs = ["/groups", "/fo", "csv", "/nh"];
669
+ ADMINISTRATOR_RID = /^S-1-5-21-\d+-\d+-\d+-500$/;
545
670
  ttl = 10 * 6e4;
671
+ aclArgs = (path, sid, created = false) => [
672
+ path,
673
+ "/inheritance:r",
674
+ "/grant:r",
675
+ `*${sid}:(OI)(CI)F`,
676
+ ...created ? ["/remove:g", "*S-1-5-32-544", "*S-1-5-18"] : []
677
+ ];
546
678
  hookOptions = (file, args2) => ({
547
679
  encoding: args2.includes("/u") ? "utf16le" : "utf8",
548
680
  timeout: win32.basename(file) === "powershell.exe" ? 3e4 : 5e3,
@@ -550,6 +682,22 @@ var init_runtimeSigners = __esm({
550
682
  maxBuffer: 16 * 1024 * 1024,
551
683
  windowsVerbatimArguments: win32.basename(file) === "cmd.exe"
552
684
  });
685
+ hookExecute = (file, args2, input) => {
686
+ const treeListing = win32.basename(file) === "icacls.exe" && args2.includes("/t") || win32.basename(file) === "cmd.exe" && args2.some((arg) => arg.startsWith("dir /q /a /s "));
687
+ [file, args2] = hookInvocation(file, args2);
688
+ const options = hookOptions(file, args2);
689
+ if (treeListing)
690
+ options.timeout = 3e4;
691
+ return new Promise((resolve3, reject) => {
692
+ const child = execFile(file, args2, options, (error, stdout2) => error ? reject(error) : resolve3({ stdout: stdout2 }));
693
+ if (input !== void 0) {
694
+ child.stdin?.on("error", reject);
695
+ child.stdin?.end(input);
696
+ }
697
+ });
698
+ };
699
+ stdout = (value) => value.stdout;
700
+ auditDirectories = /* @__PURE__ */ new Set();
553
701
  }
554
702
  });
555
703
 
@@ -2197,14 +2345,14 @@ var require_proper_lockfile = __commonJS({
2197
2345
  });
2198
2346
 
2199
2347
  // packages/cli/src/diagnostics.ts
2200
- import { createHash as createHash3 } from "node:crypto";
2348
+ import { createHash as createHash4 } from "node:crypto";
2201
2349
  import { execFile as nodeExecFile2 } from "node:child_process";
2202
2350
  import { lstat as lstat2, mkdir as mkdir3, readFile as readFile2 } from "node:fs/promises";
2203
- import { dirname as dirname5, join as join6 } from "node:path";
2351
+ import { dirname as dirname5, join as join7 } from "node:path";
2204
2352
 
2205
2353
  // packages/credentials/dist/index.js
2206
2354
  import { createHmac, randomBytes } from "node:crypto";
2207
- import { join as join5 } from "node:path";
2355
+ import { join as join6 } from "node:path";
2208
2356
 
2209
2357
  // packages/shared/dist/instructions.js
2210
2358
  var INSTRUCTIONS_CONTENT = `Mnemonik provides persistent project memory: decisions, rationale, tasks, and policies across sessions. If no block begins "PROJECT_CONTEXT schemaVersion=", session_bootstrap({ cwd }) loads project context when cwd is the real absolute path of the project root; a placeholder or relative path fails. With that block, context is loaded and no session_bootstrap call is needed. Code and docs show current artifacts, git shows changes, and memory carries the why; memory_search recalls rationale or intent, then Grep or Read verifies current source.
@@ -6399,7 +6547,7 @@ init_repositoryRoot();
6399
6547
  // packages/local-setup/dist/storage.js
6400
6548
  init_hookRuntime();
6401
6549
  init_hookRuntime();
6402
- import { createHash, randomUUID } from "node:crypto";
6550
+ import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto";
6403
6551
  import { execFile as nodeExecFile } from "node:child_process";
6404
6552
  import fs2 from "node:fs";
6405
6553
  import { open, rename, readFile, mkdir, lstat, chmod, writeFile, unlink, rmdir } from "node:fs/promises";
@@ -6462,6 +6610,9 @@ async function windowsCurrentUserAcl(path, directory = false, options = {}, crea
6462
6610
  });
6463
6611
  });
6464
6612
  }
6613
+ async function verifyWindowsCurrentUserOnly(path, state, run2) {
6614
+ await verifyWindowsAcl(path, run2, state);
6615
+ }
6465
6616
  async function protectStateFile(path, platform = process.platform, aclOptions) {
6466
6617
  if (platform === "win32")
6467
6618
  await windowsCurrentUserAcl(path, false, aclOptions);
@@ -6471,7 +6622,7 @@ async function protectStateFile(path, platform = process.platform, aclOptions) {
6471
6622
  }
6472
6623
  async function atomicWrite(path, bytes, fault, assertOwned) {
6473
6624
  await assertOwned?.();
6474
- const temp = `${path}.${randomUUID()}.tmp`;
6625
+ const temp = `${path}.${randomUUID2()}.tmp`;
6475
6626
  const fd = await open(temp, "wx", 384);
6476
6627
  let permissionStatus;
6477
6628
  try {
@@ -6493,7 +6644,7 @@ async function atomicWrite(path, bytes, fault, assertOwned) {
6493
6644
  async function withLock(path, waitMs, work) {
6494
6645
  const lockfile = await sharedLockfile();
6495
6646
  await mkdir(dirname3(path), { recursive: true, mode: 448 });
6496
- const generation = randomUUID();
6647
+ const generation = randomUUID2();
6497
6648
  const owner = join3(`${path}.lock`, "owner");
6498
6649
  let compromised = false;
6499
6650
  let acquired = false;
@@ -6558,6 +6709,100 @@ async function withLock(path, waitMs, work) {
6558
6709
  }
6559
6710
  }
6560
6711
 
6712
+ // packages/local-setup/dist/automaticUpdate.js
6713
+ import { spawn as nodeSpawn } from "node:child_process";
6714
+ import { realpathSync } from "node:fs";
6715
+ import { stat as nodeStat, utimes } from "node:fs/promises";
6716
+ import { homedir as homedir2 } from "node:os";
6717
+ import { join as join4 } from "node:path";
6718
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
6719
+ var DAY_MS = 864e5;
6720
+ var statePath = (stateDir) => join4(stateDir, "automatic-update.json");
6721
+ function cliLauncherPath(options = {}) {
6722
+ const platform = options.platform ?? process.platform;
6723
+ const home = options.home ?? homedir2();
6724
+ return platform === "win32" ? join4(options.env?.LOCALAPPDATA || join4(home, "AppData", "Local"), "Mnemonik", "bin", "mnemonik.cmd") : join4(home, ".local", "bin", "mnemonik");
6725
+ }
6726
+ async function readState(path) {
6727
+ const bytes = await readBytes(path);
6728
+ if (!bytes)
6729
+ return {};
6730
+ const value = JSON.parse(bytes.toString());
6731
+ if (!value || typeof value !== "object" || value.lastAttempt !== void 0 && (!Number.isFinite(value.lastAttempt) || value.lastAttempt < 0))
6732
+ throw new Error("automatic_update_state_invalid");
6733
+ return value.lastAttempt === void 0 ? {} : { lastAttempt: value.lastAttempt };
6734
+ }
6735
+ async function maybeStartAutomaticUpdate(options = {}) {
6736
+ const stateDir = options.stateDir ?? stateDirectory(options.platform, options.env, options.home);
6737
+ const path = statePath(stateDir);
6738
+ try {
6739
+ const now = (options.now ?? Date.now)();
6740
+ const stat = options.stat ?? nodeStat;
6741
+ try {
6742
+ if (now - (await stat(path)).mtimeMs < DAY_MS)
6743
+ return false;
6744
+ } catch (error) {
6745
+ if (error.code !== "ENOENT")
6746
+ throw error;
6747
+ }
6748
+ if (!options.spawn && !(await stat(cliLauncherPath(options))).isFile())
6749
+ return false;
6750
+ return await withLock(path, 0, async (assertOwned) => {
6751
+ const state = await readState(path);
6752
+ if (state.lastAttempt !== void 0 && now - state.lastAttempt < DAY_MS)
6753
+ return false;
6754
+ await atomicWrite(path, Buffer.from(`${JSON.stringify({ lastAttempt: now })}
6755
+ `), void 0, assertOwned);
6756
+ await utimes(path, now / 1e3, now / 1e3);
6757
+ const platform = options.platform ?? process.platform;
6758
+ const launcher = cliLauncherPath(options);
6759
+ const command = platform === "win32" ? {
6760
+ file: options.env?.ComSpec || "cmd.exe",
6761
+ args: ["/d", "/s", "/c", `""${launcher}" update --automatic"`],
6762
+ windowsVerbatimArguments: true
6763
+ } : platform === "linux" && (options.env ?? process.env).INVOCATION_ID ? {
6764
+ // detached creates a process group, not a new systemd cgroup. An
6765
+ // updater spawned by the scanner must survive stopping that service.
6766
+ file: "systemd-run",
6767
+ args: [
6768
+ "--user",
6769
+ "--collect",
6770
+ "--quiet",
6771
+ `--setenv=MNEMONIK_STATE_DIR=${stateDir}`,
6772
+ "--",
6773
+ launcher,
6774
+ "update",
6775
+ "--automatic"
6776
+ ]
6777
+ } : { file: launcher, args: ["update", "--automatic"] };
6778
+ const child = (options.spawn ?? nodeSpawn)(command.file, command.args, {
6779
+ detached: true,
6780
+ stdio: "ignore",
6781
+ windowsHide: true,
6782
+ ..."windowsVerbatimArguments" in command ? { windowsVerbatimArguments: command.windowsVerbatimArguments } : {}
6783
+ });
6784
+ child.once("error", () => {
6785
+ });
6786
+ child.unref();
6787
+ return true;
6788
+ });
6789
+ } catch {
6790
+ return false;
6791
+ }
6792
+ }
6793
+ var HELPER_FLAG = "--mnemonik-automatic-update";
6794
+ function isHelperInvocation() {
6795
+ if (process.argv[2] !== HELPER_FLAG || !process.argv[3] || !process.argv[1])
6796
+ return false;
6797
+ try {
6798
+ return realpathSync(process.argv[1]) === realpathSync(fileURLToPath2(import.meta.url));
6799
+ } catch {
6800
+ return false;
6801
+ }
6802
+ }
6803
+ if (isHelperInvocation())
6804
+ void maybeStartAutomaticUpdate({ stateDir: process.argv[3] });
6805
+
6561
6806
  // packages/local-setup/dist/index.js
6562
6807
  var MAX_ORIGINAL_BYTES = 64 * 1024;
6563
6808
 
@@ -6573,10 +6818,10 @@ var CredentialSessionUnavailableError = class extends Error {
6573
6818
  };
6574
6819
 
6575
6820
  // packages/credentials/dist/storage.js
6576
- import { createHash as createHash2 } from "node:crypto";
6821
+ import { createHash as createHash3 } from "node:crypto";
6577
6822
  import { lstat as nodeLstat, mkdir as mkdir2, open as open2, readdir, rmdir as rmdir2, unlink as unlink2 } from "node:fs/promises";
6578
6823
  import { constants } from "node:fs";
6579
- import { basename as basename2, dirname as dirname4, isAbsolute, join as join4, parse, relative, resolve as resolve2, sep as sep2 } from "node:path";
6824
+ import { basename as basename2, dirname as dirname4, isAbsolute, join as join5, parse, relative, resolve as resolve2, sep as sep2 } from "node:path";
6580
6825
  var CredentialError = class extends Error {
6581
6826
  reason;
6582
6827
  constructor(reason) {
@@ -6585,22 +6830,22 @@ var CredentialError = class extends Error {
6585
6830
  this.name = "CredentialError";
6586
6831
  }
6587
6832
  };
6588
- var digest = (value) => createHash2("sha256").update(value).digest("hex");
6833
+ var digest = (value) => createHash3("sha256").update(value).digest("hex");
6589
6834
  function credentialPaths(stateDir = stateDirectory(), familyId) {
6590
- const root = join4(stateDir, "credentials");
6835
+ const root = join5(stateDir, "credentials");
6591
6836
  const familyName = familyId ? digest(familyId) : "";
6592
6837
  return {
6593
6838
  root,
6594
- records: join4(root, "records"),
6595
- secrets: join4(root, "secrets"),
6596
- cliRecord: join4(root, "records", "cli.json"),
6597
- cliSecret: join4(root, "secrets", "cli.json"),
6598
- rootRecord: join4(root, "records", "root-binding.json"),
6599
- rootSecret: join4(root, "secrets", "root-binding.key"),
6600
- familyRecords: join4(root, "records", "families"),
6601
- familySecrets: join4(root, "secrets", "families"),
6602
- record: join4(root, "records", "families", `${familyName}.json`),
6603
- secret: join4(root, "secrets", "families", `${familyName}.json`)
6839
+ records: join5(root, "records"),
6840
+ secrets: join5(root, "secrets"),
6841
+ cliRecord: join5(root, "records", "cli.json"),
6842
+ cliSecret: join5(root, "secrets", "cli.json"),
6843
+ rootRecord: join5(root, "records", "root-binding.json"),
6844
+ rootSecret: join5(root, "secrets", "root-binding.key"),
6845
+ familyRecords: join5(root, "records", "families"),
6846
+ familySecrets: join5(root, "secrets", "families"),
6847
+ record: join5(root, "records", "families", `${familyName}.json`),
6848
+ secret: join5(root, "secrets", "families", `${familyName}.json`)
6604
6849
  };
6605
6850
  }
6606
6851
  var codeIs2 = (error, code) => error.code === code;
@@ -6612,6 +6857,7 @@ var SecureFiles = class {
6612
6857
  fault;
6613
6858
  execFile;
6614
6859
  username;
6860
+ aclRun;
6615
6861
  constructor(options = {}) {
6616
6862
  this.stateDir = resolve2(options.stateDir ?? stateDirectory());
6617
6863
  this.platform = options.platform ?? process.platform;
@@ -6620,6 +6866,7 @@ var SecureFiles = class {
6620
6866
  this.fault = options.fault;
6621
6867
  this.execFile = options.execFile;
6622
6868
  this.username = options.username;
6869
+ this.aclRun = options.aclRun;
6623
6870
  }
6624
6871
  assertInsideState(path) {
6625
6872
  const absolute = resolve2(path);
@@ -6635,7 +6882,7 @@ var SecureFiles = class {
6635
6882
  const result = [];
6636
6883
  let current = root;
6637
6884
  for (const part of parts2) {
6638
- current = join4(current, part);
6885
+ current = join5(current, part);
6639
6886
  result.push(current);
6640
6887
  }
6641
6888
  return result;
@@ -6654,20 +6901,34 @@ var SecureFiles = class {
6654
6901
  if (value.isSymbolicLink())
6655
6902
  throw new CredentialError("symlink_rejected");
6656
6903
  const protectedComponent = component === this.stateDir || component.startsWith(`${this.stateDir}${sep2}`);
6657
- if (!protectedComponent || this.platform === "win32")
6904
+ if (!protectedComponent)
6658
6905
  continue;
6659
- if (this.uid !== void 0 && value.uid !== this.uid)
6660
- throw new CredentialError("wrong_owner");
6661
6906
  const final = component === absolute;
6662
- const allowed = final && expectFile ? 384 : 448;
6663
- if ((value.mode & 511 & ~allowed) !== 0)
6664
- throw new CredentialError("weak_permissions");
6907
+ if (this.platform === "win32") {
6908
+ if (final)
6909
+ await this.verifyWindowsPrivate(component);
6910
+ } else {
6911
+ if (this.uid !== void 0 && value.uid !== this.uid)
6912
+ throw new CredentialError("wrong_owner");
6913
+ const allowed = final && expectFile ? 384 : 448;
6914
+ if ((value.mode & 511 & ~allowed) !== 0)
6915
+ throw new CredentialError("weak_permissions");
6916
+ }
6665
6917
  if (final && expectFile && !value.isFile())
6666
6918
  throw new CredentialError("not_regular_file");
6667
6919
  if (final && !expectFile && !value.isDirectory())
6668
6920
  throw new CredentialError("not_regular_file");
6669
6921
  }
6670
6922
  }
6923
+ async verifyWindowsPrivate(path) {
6924
+ try {
6925
+ await verifyWindowsCurrentUserOnly(path, this.stateDir, this.aclRun);
6926
+ } catch (error) {
6927
+ if (error.message === "acl_permissions")
6928
+ throw new CredentialError("weak_permissions");
6929
+ throw error;
6930
+ }
6931
+ }
6671
6932
  async makeDirectory(path) {
6672
6933
  let created = false;
6673
6934
  try {
@@ -6721,7 +6982,7 @@ var SecureFiles = class {
6721
6982
  const prefix = `${basename2(absolute)}.`;
6722
6983
  for (const name2 of await this.list(dirname4(absolute))) {
6723
6984
  if (name2.startsWith(prefix) && name2.endsWith(".tmp"))
6724
- await this.remove(join4(dirname4(absolute), name2));
6985
+ await this.remove(join5(dirname4(absolute), name2));
6725
6986
  }
6726
6987
  throw error;
6727
6988
  }
@@ -7256,7 +7517,7 @@ function createCredentialAdapter(options = {}) {
7256
7517
  const cli = await readRecord(paths.cliRecord, "cli-oauth");
7257
7518
  const componentFamilyIds = [];
7258
7519
  for (const name2 of await files.list(paths.familyRecords)) {
7259
- const recordPath2 = join5(paths.familyRecords, name2);
7520
+ const recordPath2 = join6(paths.familyRecords, name2);
7260
7521
  const record = await readRecord(recordPath2, "component");
7261
7522
  if (!record)
7262
7523
  continue;
@@ -7313,10 +7574,10 @@ var DiagnosticsError = class extends Error {
7313
7574
  }
7314
7575
  code;
7315
7576
  };
7316
- var digest2 = (bytes) => createHash3("sha256").update(bytes).digest("hex");
7577
+ var digest2 = (bytes) => createHash4("sha256").update(bytes).digest("hex");
7317
7578
  var validId = (id) => /^diag-[A-Za-z0-9._-]{1,120}$/u.test(id);
7318
7579
  async function scannerConfig(stateDir) {
7319
- const state = JSON.parse(await readFile2(join6(stateDir, "scanner", "state.json"), "utf8"));
7580
+ const state = JSON.parse(await readFile2(join7(stateDir, "scanner", "state.json"), "utf8"));
7320
7581
  if (typeof state.config?.serverUrl !== "string" || typeof state.config.credentialFamilyId !== "string")
7321
7582
  throw new DiagnosticsError("scanner_credential_missing");
7322
7583
  return {
@@ -7345,7 +7606,7 @@ async function previewDiagnostics(out2, dependencies = {}) {
7345
7606
  const stateDir = dependencies.stateDir ?? stateDirectory();
7346
7607
  const binary2 = dependencies.scannerBinary ? await dependencies.scannerBinary() : (await new RuntimeStore(stateDir).verifyRuntime("scanner")).entry;
7347
7608
  const args2 = ["diagnostics", "diagnostics", "bundle", ...out2 ? ["--out", out2] : [], "--json"];
7348
- const stdout = await new Promise((resolve3, reject) => {
7609
+ const stdout2 = await new Promise((resolve3, reject) => {
7349
7610
  (dependencies.execFile ?? nodeExecFile2)(
7350
7611
  binary2,
7351
7612
  args2,
@@ -7358,14 +7619,14 @@ async function previewDiagnostics(out2, dependencies = {}) {
7358
7619
  });
7359
7620
  let result;
7360
7621
  try {
7361
- result = JSON.parse(stdout);
7622
+ result = JSON.parse(stdout2);
7362
7623
  } catch {
7363
7624
  throw new DiagnosticsError("diagnostics_preview_invalid");
7364
7625
  }
7365
7626
  if (!validId(result.manifest?.bundleId) || !/^[a-f0-9]{64}$/u.test(result.sha256) || typeof result.path !== "string")
7366
7627
  throw new DiagnosticsError("diagnostics_preview_invalid");
7367
7628
  const receipt = { schemaVersion: 1, ...result };
7368
- const receiptPath = join6(stateDir, "diagnostics", `${result.manifest.bundleId}.json`);
7629
+ const receiptPath = join7(stateDir, "diagnostics", `${result.manifest.bundleId}.json`);
7369
7630
  await mkdir3(dirname5(receiptPath), { recursive: true, mode: 448 });
7370
7631
  await atomicWrite(receiptPath, Buffer.from(`${JSON.stringify(receipt)}
7371
7632
  `));
@@ -7390,7 +7651,7 @@ async function uploadDiagnosticsBundle(serverUrl, token, bundleId, sha256, bytes
7390
7651
  async function sendDiagnostics(bundleId, dependencies = {}) {
7391
7652
  if (!validId(bundleId)) throw new DiagnosticsError("bundle_id_invalid");
7392
7653
  const stateDir = dependencies.stateDir ?? stateDirectory();
7393
- const receiptPath = join6(stateDir, "diagnostics", `${bundleId}.json`);
7654
+ const receiptPath = join7(stateDir, "diagnostics", `${bundleId}.json`);
7394
7655
  const receipt = JSON.parse(await readFile2(receiptPath, "utf8"));
7395
7656
  if (receipt.schemaVersion !== 1 || receipt.manifest?.bundleId !== bundleId || !/^[a-f0-9]{64}$/u.test(receipt.sha256) || typeof receipt.path !== "string" || !(await lstat2(receipt.path)).isFile())
7396
7657
  throw new DiagnosticsError("diagnostics_preview_invalid");