@sealant/mend 0.35.0 → 0.35.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.
Files changed (77) hide show
  1. package/dist/main.js +306 -282
  2. package/man/mend-accounts.1 +1 -1
  3. package/man/mend-adopt.1 +1 -1
  4. package/man/mend-attach.1 +1 -1
  5. package/man/mend-codex.1 +1 -1
  6. package/man/mend-completions.1 +1 -1
  7. package/man/mend-connect.1 +2 -2
  8. package/man/mend-continue.1 +1 -1
  9. package/man/mend-doctor.1 +1 -1
  10. package/man/mend-dotfiles-repo.1 +1 -1
  11. package/man/mend-dotfiles-sync.1 +1 -1
  12. package/man/mend-dotfiles.1 +1 -1
  13. package/man/mend-env-cluster.1 +1 -1
  14. package/man/mend-env-load.1 +1 -1
  15. package/man/mend-env-show.1 +1 -1
  16. package/man/mend-folder-create.1 +1 -1
  17. package/man/mend-folder-list.1 +1 -1
  18. package/man/mend-folder-push.1 +1 -1
  19. package/man/mend-folder-rm.1 +1 -1
  20. package/man/mend-git-author.1 +1 -1
  21. package/man/mend-help.1 +1 -1
  22. package/man/mend-invite.1 +1 -1
  23. package/man/mend-keys-init.1 +1 -1
  24. package/man/mend-keys-mode.1 +1 -1
  25. package/man/mend-keys-share.1 +1 -1
  26. package/man/mend-keys-show.1 +1 -1
  27. package/man/mend-land.1 +1 -1
  28. package/man/mend-login.1 +1 -1
  29. package/man/mend-logout.1 +1 -1
  30. package/man/mend-man.1 +1 -1
  31. package/man/mend-members.1 +1 -1
  32. package/man/mend-operator-exposure.1 +1 -1
  33. package/man/mend-operator-gate.1 +1 -1
  34. package/man/mend-operator-grant-owner.1 +1 -1
  35. package/man/mend-operator-org-create.1 +1 -1
  36. package/man/mend-operator-org-invite-owner.1 +1 -1
  37. package/man/mend-operator-org-list.1 +1 -1
  38. package/man/mend-operator-org-rename.1 +1 -1
  39. package/man/mend-operator-reset-link.1 +1 -1
  40. package/man/mend-pair.1 +1 -1
  41. package/man/mend-projects.1 +1 -1
  42. package/man/mend-pull.1 +1 -1
  43. package/man/mend-refresh.1 +1 -1
  44. package/man/mend-rejoin.1 +1 -1
  45. package/man/mend-resume.1 +1 -1
  46. package/man/mend-run.1 +1 -1
  47. package/man/mend-server-logs.1 +1 -1
  48. package/man/mend-server-restart.1 +1 -1
  49. package/man/mend-server-setup.1 +1 -1
  50. package/man/mend-server-start.1 +1 -1
  51. package/man/mend-server-status.1 +1 -1
  52. package/man/mend-server-stop.1 +1 -1
  53. package/man/mend-server-upgrade.1 +1 -1
  54. package/man/mend-server.1 +1 -1
  55. package/man/mend-service-add.1 +1 -1
  56. package/man/mend-service-connect.1 +1 -1
  57. package/man/mend-service-init.1 +1 -1
  58. package/man/mend-service-list.1 +1 -1
  59. package/man/mend-service-logs.1 +1 -1
  60. package/man/mend-service-restart.1 +1 -1
  61. package/man/mend-service-run.1 +1 -1
  62. package/man/mend-service-stop.1 +1 -1
  63. package/man/mend-session-share.1 +1 -1
  64. package/man/mend-sessions.1 +1 -1
  65. package/man/mend-shell.1 +1 -1
  66. package/man/mend-skills-push.1 +1 -1
  67. package/man/mend-skills.1 +1 -1
  68. package/man/mend-snake.1 +1 -1
  69. package/man/mend-ssh-setup.1 +1 -1
  70. package/man/mend-ssh.1 +1 -1
  71. package/man/mend-stop.1 +1 -1
  72. package/man/mend-ui.1 +1 -1
  73. package/man/mend-uninstall.1 +1 -1
  74. package/man/mend-version.1 +1 -1
  75. package/man/mend-worktrees.1 +1 -1
  76. package/man/mend.1 +1 -1
  77. package/package.json +5 -4
package/dist/main.js CHANGED
@@ -38,11 +38,11 @@ import {
38
38
 
39
39
  // src/main.ts
40
40
  import { spawn as spawn3, spawnSync as spawnSync6 } from "node:child_process";
41
- import * as fs16 from "node:fs";
41
+ import * as fs17 from "node:fs";
42
42
  import { createRequire } from "node:module";
43
43
  import * as net4 from "node:net";
44
44
  import * as os11 from "node:os";
45
- import * as path17 from "node:path";
45
+ import * as path18 from "node:path";
46
46
 
47
47
  // src/agent-share.ts
48
48
  import * as net from "node:net";
@@ -223,6 +223,15 @@ import * as fs from "node:fs";
223
223
  import * as os from "node:os";
224
224
  import * as path from "node:path";
225
225
  var claudeGrantDir = (home) => path.join(home, "claude-grant");
226
+ var forgetGrant = (configDir, platform = process.platform) => {
227
+ fs.rmSync(configDir, { recursive: true, force: true });
228
+ if (platform !== "darwin") return;
229
+ spawnSync(
230
+ "security",
231
+ ["delete-generic-password", "-a", os.userInfo().username, "-s", keychainService(configDir)],
232
+ { stdio: "ignore", timeout: 6e4 }
233
+ );
234
+ };
226
235
  var personalClaudeDir = (environment = process.env) => {
227
236
  const configured = environment["CLAUDE_CONFIG_DIR"];
228
237
  return configured === void 0 || configured === "" ? path.join(os.homedir(), ".claude") : configured;
@@ -344,16 +353,28 @@ var readClipboardImage = async (platform = process.platform, env = process.env)
344
353
 
345
354
  // src/codex-grant.ts
346
355
  import { spawnSync as spawnSync2 } from "node:child_process";
347
- import * as fs2 from "node:fs";
356
+ import * as fs3 from "node:fs";
348
357
  import * as os2 from "node:os";
358
+ import * as path3 from "node:path";
359
+
360
+ // src/login-dir.ts
361
+ import * as fs2 from "node:fs";
349
362
  import * as path2 from "node:path";
363
+ var throwawayLoginDir = (parent, prefix) => {
364
+ fs2.mkdirSync(parent, { recursive: true, mode: 448 });
365
+ const dir = fs2.mkdtempSync(path2.join(parent, prefix));
366
+ fs2.chmodSync(dir, 448);
367
+ return dir;
368
+ };
369
+
370
+ // src/codex-grant.ts
350
371
  var codexCli = (environment = process.env) => ({
351
372
  bin: environment["MEND_CODEX_BIN"] ?? "codex",
352
373
  env: environment
353
374
  });
354
375
  var personalCodexHome = (environment = process.env) => {
355
376
  const configured = environment["CODEX_HOME"];
356
- return configured === void 0 || configured === "" ? path2.join(os2.homedir(), ".codex") : configured;
377
+ return configured === void 0 || configured === "" ? path3.join(os2.homedir(), ".codex") : configured;
357
378
  };
358
379
  var runCodexDeviceLogin = (cli, codexHome) => {
359
380
  const result = spawnSync2(cli.bin, ["login", "--device-auth"], {
@@ -379,19 +400,18 @@ var sameCodexLogin = (a, b) => {
379
400
  return first !== null && first === refreshTokenOf(b);
380
401
  };
381
402
  var codexGrant = (input) => {
382
- const home = fs2.mkdtempSync(path2.join(os2.tmpdir(), "mend-codex-grant-"));
383
- fs2.chmodSync(home, 448);
403
+ const home = throwawayLoginDir(input.parent, "codex-login-");
384
404
  try {
385
405
  input.say(" Mend needs its own Codex login; it is sent to your server and not kept here");
386
406
  input.say(" your own Codex login stays as it is");
387
407
  if (!runCodexDeviceLogin(input.cli, home)) {
388
408
  return { kind: "failed", reason: "codex: the login did not complete" };
389
409
  }
390
- const file = path2.join(home, "auth.json");
391
- if (!fs2.existsSync(file)) {
410
+ const file = path3.join(home, "auth.json");
411
+ if (!fs3.existsSync(file)) {
392
412
  return { kind: "failed", reason: `codex: logged in, but no auth.json appeared in ${home}` };
393
413
  }
394
- const secret = fs2.readFileSync(file, "utf8").trim();
414
+ const secret = fs3.readFileSync(file, "utf8").trim();
395
415
  if (refreshTokenOf(secret) === null) {
396
416
  return {
397
417
  kind: "failed",
@@ -406,19 +426,19 @@ var codexGrant = (input) => {
406
426
  }
407
427
  return { kind: "grant", secret };
408
428
  } finally {
409
- fs2.rmSync(home, { recursive: true, force: true });
429
+ fs3.rmSync(home, { recursive: true, force: true });
410
430
  }
411
431
  };
412
432
 
413
433
  // src/doctor-bundle-collectors.ts
414
- import * as fs4 from "node:fs";
434
+ import * as fs5 from "node:fs";
415
435
  import * as os3 from "node:os";
416
- import * as path4 from "node:path";
436
+ import * as path5 from "node:path";
417
437
 
418
438
  // src/server-runtime.ts
419
439
  import { spawn } from "node:child_process";
420
- import * as fs3 from "node:fs";
421
- import * as path3 from "node:path";
440
+ import * as fs4 from "node:fs";
441
+ import * as path4 from "node:path";
422
442
  var serverProcessDeadlines = {
423
443
  ordinary: 3e4,
424
444
  pull: 10 * 6e4,
@@ -464,7 +484,7 @@ var runServerProcess = (command, args, parentEnvironment, options = {}) => {
464
484
  return new Promise((resolve7) => {
465
485
  let fd;
466
486
  try {
467
- if (options.stdoutFile !== void 0) fd = fs3.openSync(options.stdoutFile, "wx", 384);
487
+ if (options.stdoutFile !== void 0) fd = fs4.openSync(options.stdoutFile, "wx", 384);
468
488
  const child = spawn(command, [...args], {
469
489
  env,
470
490
  detached: process.platform !== "win32",
@@ -515,12 +535,12 @@ var runServerProcess = (command, args, parentEnvironment, options = {}) => {
515
535
  child.once("close", (status) => {
516
536
  globalThis.clearTimeout(timer);
517
537
  try {
518
- if (fd !== void 0) fs3.fsyncSync(fd);
538
+ if (fd !== void 0) fs4.fsyncSync(fd);
519
539
  } catch {
520
540
  failure2 ??= "Could not durably write process output.";
521
541
  } finally {
522
542
  try {
523
- if (fd !== void 0) fs3.closeSync(fd);
543
+ if (fd !== void 0) fs4.closeSync(fd);
524
544
  } catch {
525
545
  failure2 ??= "Could not close process output file.";
526
546
  }
@@ -534,7 +554,7 @@ var runServerProcess = (command, args, parentEnvironment, options = {}) => {
534
554
  });
535
555
  } catch (cause) {
536
556
  try {
537
- if (fd !== void 0) fs3.closeSync(fd);
557
+ if (fd !== void 0) fs4.closeSync(fd);
538
558
  } catch {
539
559
  }
540
560
  resolve7({
@@ -555,9 +575,9 @@ var serverComposeArgs = (installation, command) => [
555
575
  "--project-directory",
556
576
  installation.directory,
557
577
  "--env-file",
558
- path3.join(installation.directory, "server.env"),
578
+ path4.join(installation.directory, "server.env"),
559
579
  "-f",
560
- path3.join(installation.directory, "compose.yaml"),
580
+ path4.join(installation.directory, "compose.yaml"),
561
581
  ...command
562
582
  ];
563
583
 
@@ -603,11 +623,11 @@ var mapLimit = async (items, limit, work) => {
603
623
  return results;
604
624
  };
605
625
  var pathOf = (command, env = process.env) => {
606
- for (const directory of (env["PATH"] ?? "").split(path4.delimiter)) {
626
+ for (const directory of (env["PATH"] ?? "").split(path5.delimiter)) {
607
627
  if (directory === "") continue;
608
- const candidate = path4.join(directory, command);
628
+ const candidate = path5.join(directory, command);
609
629
  try {
610
- fs4.accessSync(candidate, fs4.constants.X_OK);
630
+ fs5.accessSync(candidate, fs5.constants.X_OK);
611
631
  return candidate;
612
632
  } catch {
613
633
  }
@@ -1097,8 +1117,8 @@ var bundleCollectors = (deps) => {
1097
1117
  };
1098
1118
 
1099
1119
  // src/doctor-bundle.ts
1100
- import * as fs5 from "node:fs";
1101
- import * as path5 from "node:path";
1120
+ import * as fs6 from "node:fs";
1121
+ import * as path6 from "node:path";
1102
1122
  import { gzipSync } from "node:zlib";
1103
1123
 
1104
1124
  // src/help.ts
@@ -1148,7 +1168,7 @@ var COMMANDS = [
1148
1168
  synopsis: ["<claude|codex|github> [--use-my-login] [--from-stdin] [--remove]"],
1149
1169
  description: [
1150
1170
  "Sessions run on the platform, so the platform needs your provider login. It is stored under your own user and used only for your work. Nothing is shared with other users.",
1151
- "Claude and Codex get a login of Mend's own. Both rotate their refresh token, so two copies of one login fight and the one that refreshes second is signed out, and Mend's server refreshes on a schedule. So this logs in through the provider's own flow and your own login stays as it is: Claude against a directory Mend keeps, Codex with a device code, sent and not kept here. Run it again whenever Mend says a login needs reconnecting. GitHub sends gh's token."
1171
+ "Claude and Codex get a login of Mend's own. Both rotate their refresh token, so two copies of one login fight and the one that refreshes second is signed out, and Mend's server refreshes on a schedule. So this logs in through the provider's own flow and your own login stays as it is: Claude in the browser, Codex with a device code, both sent and not kept here. Run it again whenever Mend says a login needs reconnecting. GitHub sends gh's token."
1152
1172
  ],
1153
1173
  options: [
1154
1174
  {
@@ -2539,9 +2559,9 @@ var collectBundle = async (collectors) => {
2539
2559
  };
2540
2560
  var bundleFileName = (now) => `mend-bundle-${now.toISOString().replace(/\.\d{3}Z$/, "Z").replace(/:/g, "-")}.tgz`;
2541
2561
  var writeBundle = (files, outPath, now) => {
2542
- const directory = path5.dirname(outPath);
2543
- fs5.mkdirSync(directory, { recursive: true, mode: 448 });
2544
- const root = path5.basename(outPath).replace(/\.(?:tgz|tar\.gz)$/, "");
2562
+ const directory = path6.dirname(outPath);
2563
+ fs6.mkdirSync(directory, { recursive: true, mode: 448 });
2564
+ const root = path6.basename(outPath).replace(/\.(?:tgz|tar\.gz)$/, "");
2545
2565
  const entries = files.map((file) => ({
2546
2566
  path: file.path,
2547
2567
  content: Buffer.from(file.content, "utf8")
@@ -2550,8 +2570,8 @@ var writeBundle = (files, outPath, now) => {
2550
2570
  entries.map((entry) => ({ path: `${root}/${entry.path}`, content: entry.content })),
2551
2571
  now
2552
2572
  );
2553
- fs5.writeFileSync(outPath, bytes, { mode: 384 });
2554
- fs5.chmodSync(outPath, 384);
2573
+ fs6.writeFileSync(outPath, bytes, { mode: 384 });
2574
+ fs6.chmodSync(outPath, 384);
2555
2575
  return {
2556
2576
  path: outPath,
2557
2577
  bytes: bytes.length,
@@ -2612,7 +2632,7 @@ var doctorBundleCommand = async (args, deps) => {
2612
2632
  return;
2613
2633
  }
2614
2634
  const now = deps.now();
2615
- const outPath = path5.resolve(parsed.args.out ?? path5.join(deps.defaultDir, bundleFileName(now)));
2635
+ const outPath = path6.resolve(parsed.args.out ?? path6.join(deps.defaultDir, bundleFileName(now)));
2616
2636
  deps.warn("collecting \xB7 this can take a minute");
2617
2637
  const files = await collectBundle(deps.collectors(parsed.args.tail));
2618
2638
  const written = writeBundle(files, outPath, now);
@@ -2620,14 +2640,14 @@ var doctorBundleCommand = async (args, deps) => {
2620
2640
  };
2621
2641
 
2622
2642
  // src/doctor.ts
2623
- import * as fs7 from "node:fs";
2624
- import * as path7 from "node:path";
2643
+ import * as fs8 from "node:fs";
2644
+ import * as path8 from "node:path";
2625
2645
 
2626
2646
  // src/docker-shutdown.ts
2627
2647
  import { spawnSync as spawnSync3 } from "node:child_process";
2628
- import * as fs6 from "node:fs";
2648
+ import * as fs7 from "node:fs";
2629
2649
  import * as os4 from "node:os";
2630
- import * as path6 from "node:path";
2650
+ import * as path7 from "node:path";
2631
2651
  var DOCKER_CAPTURE_STOP_GRACE_SECONDS = 3600;
2632
2652
  var DOCKERD_DEFAULT_SHUTDOWN_TIMEOUT_SECONDS = 15;
2633
2653
  var flagValue = (argv, name) => {
@@ -2652,12 +2672,12 @@ var daemonKindOf = (info) => {
2652
2672
  var defaultConfigPath = (facts, daemon) => {
2653
2673
  switch (daemon) {
2654
2674
  case "desktop":
2655
- return path6.join(facts.home, ".docker", "daemon.json");
2675
+ return path7.join(facts.home, ".docker", "daemon.json");
2656
2676
  case "orbstack":
2657
- return path6.join(facts.home, ".orbstack", "config", "docker.json");
2677
+ return path7.join(facts.home, ".orbstack", "config", "docker.json");
2658
2678
  case "rootless":
2659
- return path6.join(
2660
- facts.xdgConfigHome ?? path6.join(facts.home, ".config"),
2679
+ return path7.join(
2680
+ facts.xdgConfigHome ?? path7.join(facts.home, ".config"),
2661
2681
  "docker",
2662
2682
  "daemon.json"
2663
2683
  );
@@ -2786,7 +2806,7 @@ var parseDockerInfo = (stdout) => {
2786
2806
  };
2787
2807
  var readHostFile = (file) => {
2788
2808
  try {
2789
- return { kind: "read", text: fs6.readFileSync(file, "utf8") };
2809
+ return { kind: "read", text: fs7.readFileSync(file, "utf8") };
2790
2810
  } catch (cause) {
2791
2811
  return cause instanceof Error && "code" in cause && cause.code === "ENOENT" ? { kind: "absent" } : { kind: "unreadable" };
2792
2812
  }
@@ -2794,21 +2814,21 @@ var readHostFile = (file) => {
2794
2814
  var hostProcView = {
2795
2815
  list: (dir) => {
2796
2816
  try {
2797
- return fs6.readdirSync(dir);
2817
+ return fs7.readdirSync(dir);
2798
2818
  } catch {
2799
2819
  return null;
2800
2820
  }
2801
2821
  },
2802
2822
  read: (file) => {
2803
2823
  try {
2804
- return fs6.readFileSync(file, "utf8");
2824
+ return fs7.readFileSync(file, "utf8");
2805
2825
  } catch {
2806
2826
  return null;
2807
2827
  }
2808
2828
  },
2809
2829
  link: (file) => {
2810
2830
  try {
2811
- return fs6.readlinkSync(file);
2831
+ return fs7.readlinkSync(file);
2812
2832
  } catch {
2813
2833
  return null;
2814
2834
  }
@@ -2848,7 +2868,7 @@ var observeDockerd = (proc, host) => {
2848
2868
  const cmdline = proc.read(`/proc/${entry}/cmdline`);
2849
2869
  if (cmdline === null) continue;
2850
2870
  const argv = cmdline.split("\0").filter((arg) => arg !== "");
2851
- if (path6.basename(argv[0] ?? "") === "dockerd") daemons.push({ pid: entry, argv });
2871
+ if (path7.basename(argv[0] ?? "") === "dockerd") daemons.push({ pid: entry, argv });
2852
2872
  }
2853
2873
  if (daemons.length === 0) return { kind: "none" };
2854
2874
  const socket = unixSocketOf(host);
@@ -3168,10 +3188,10 @@ var runChecks = async (config, probes) => {
3168
3188
  return checks;
3169
3189
  };
3170
3190
  var onPath = (command) => {
3171
- for (const directory of (process.env["PATH"] ?? "").split(path7.delimiter)) {
3191
+ for (const directory of (process.env["PATH"] ?? "").split(path8.delimiter)) {
3172
3192
  if (directory === "") continue;
3173
3193
  try {
3174
- fs7.accessSync(path7.join(directory, command), fs7.constants.X_OK);
3194
+ fs8.accessSync(path8.join(directory, command), fs8.constants.X_OK);
3175
3195
  return true;
3176
3196
  } catch {
3177
3197
  }
@@ -3196,8 +3216,8 @@ var doctorCommand = async (config, localCredential2, claudeGrant2) => {
3196
3216
  };
3197
3217
 
3198
3218
  // src/dotfiles.ts
3199
- import * as fs8 from "node:fs";
3200
- import * as path8 from "node:path";
3219
+ import * as fs9 from "node:fs";
3220
+ import * as path9 from "node:path";
3201
3221
  var DOTFILE_CANDIDATES = [
3202
3222
  {
3203
3223
  group: "shell",
@@ -3240,7 +3260,7 @@ var DOTFILE_CANDIDATES = [
3240
3260
  var MAX_FILE_BYTES = 1024 * 1024;
3241
3261
  var statFile = (home, relative4) => {
3242
3262
  try {
3243
- const stat = fs8.statSync(path8.join(home, relative4));
3263
+ const stat = fs9.statSync(path9.join(home, relative4));
3244
3264
  return stat.isFile() ? stat : null;
3245
3265
  } catch {
3246
3266
  return null;
@@ -3253,9 +3273,9 @@ var scanDotfileCandidates = (home) => DOTFILE_CANDIDATES.flatMap(
3253
3273
  })
3254
3274
  );
3255
3275
  var homeRelativePath = (home, requested) => {
3256
- const relative4 = path8.relative(home, path8.resolve(home, requested));
3257
- const outside = relative4 === "" || relative4 === ".." || relative4.startsWith(`..${path8.sep}`) || path8.isAbsolute(relative4);
3258
- return outside ? null : relative4.split(path8.sep).join("/");
3276
+ const relative4 = path9.relative(home, path9.resolve(home, requested));
3277
+ const outside = relative4 === "" || relative4 === ".." || relative4.startsWith(`..${path9.sep}`) || path9.isAbsolute(relative4);
3278
+ return outside ? null : relative4.split(path9.sep).join("/");
3259
3279
  };
3260
3280
  var readSyncFiles = (home, paths_) => {
3261
3281
  const files = [];
@@ -3275,7 +3295,7 @@ var readSyncFiles = (home, paths_) => {
3275
3295
  }
3276
3296
  files.push({
3277
3297
  path: relative4,
3278
- contentsBase64: fs8.readFileSync(path8.join(home, relative4)).toString("base64"),
3298
+ contentsBase64: fs9.readFileSync(path9.join(home, relative4)).toString("base64"),
3279
3299
  // eslint-disable-next-line no-bitwise -- permission bits are the point
3280
3300
  mode: (stat.mode & 511).toString(8)
3281
3301
  });
@@ -3373,11 +3393,18 @@ var parseGitAuthorArgs = (args) => {
3373
3393
  };
3374
3394
  var gitAuthorLine = (author) => `${author.name} <${author.email}> \xB7 ${author.source === "setting" ? "your setting" : "your account's name and email"}`;
3375
3395
 
3396
+ // src/http-client.ts
3397
+ import { Agent, setGlobalDispatcher } from "undici";
3398
+ var cliDispatcher = (connect2) => new Agent({ allowH2: false, ...connect2 === void 0 ? {} : { connect: connect2 } });
3399
+ var useHttp1 = () => {
3400
+ setGlobalDispatcher(cliDispatcher());
3401
+ };
3402
+
3376
3403
  // src/landing.ts
3377
3404
  import { spawnSync as spawnSync4 } from "node:child_process";
3378
- import * as fs9 from "node:fs";
3405
+ import * as fs10 from "node:fs";
3379
3406
  import * as os5 from "node:os";
3380
- import * as path9 from "node:path";
3407
+ import * as path10 from "node:path";
3381
3408
  var paint = (code) => (text) => process.stdout.isTTY === true ? `[${code}m${text}[0m` : text;
3382
3409
  var dim = paint("2");
3383
3410
  var green = paint("32");
@@ -3615,9 +3642,9 @@ var gitRemotes = (cwd) => {
3615
3642
  var remoteForOrigin = (remotes, originUrl, cwd) => {
3616
3643
  if (originUrl === null) return null;
3617
3644
  const origin = normalizeRemoteUrl(originUrl);
3618
- const originPath = origin === null ? path9.resolve(originUrl.replace(/^file:\/\//, "")) : null;
3645
+ const originPath = origin === null ? path10.resolve(originUrl.replace(/^file:\/\//, "")) : null;
3619
3646
  return remotes.find(
3620
- (remote) => origin === null ? path9.resolve(cwd, remote.url.replace(/^file:\/\//, "")) === originPath : normalizeRemoteUrl(remote.url) === origin
3647
+ (remote) => origin === null ? path10.resolve(cwd, remote.url.replace(/^file:\/\//, "")) === originPath : normalizeRemoteUrl(remote.url) === origin
3621
3648
  ) ?? null;
3622
3649
  };
3623
3650
  var LOG_LINES = 10;
@@ -3640,10 +3667,10 @@ var fetchBundle = (cwd, bundle) => {
3640
3667
  const before = git(cwd, ["rev-parse", "--verify", "--quiet", `${ref}^{commit}`]);
3641
3668
  const previous = before.status === 0 ? before.stdout.trim() : null;
3642
3669
  if (previous !== bundle.tip) {
3643
- const dir = fs9.mkdtempSync(path9.join(os5.tmpdir(), "mend-pull-"));
3670
+ const dir = fs10.mkdtempSync(path10.join(os5.tmpdir(), "mend-pull-"));
3644
3671
  try {
3645
- const file = path9.join(dir, "change.bundle");
3646
- fs9.writeFileSync(file, bundle.bytes, { mode: 384 });
3672
+ const file = path10.join(dir, "change.bundle");
3673
+ fs10.writeFileSync(file, bundle.bytes, { mode: 384 });
3647
3674
  const fetched = git(cwd, [
3648
3675
  "fetch",
3649
3676
  "--no-tags",
@@ -3653,7 +3680,7 @@ var fetchBundle = (cwd, bundle) => {
3653
3680
  ]);
3654
3681
  if (fetched.status !== 0) return refusedWith(gitWords(fetched));
3655
3682
  } finally {
3656
- fs9.rmSync(dir, { recursive: true, force: true });
3683
+ fs10.rmSync(dir, { recursive: true, force: true });
3657
3684
  }
3658
3685
  }
3659
3686
  const after = git(cwd, ["rev-parse", "--verify", "--quiet", `${ref}^{commit}`]).stdout.trim();
@@ -4087,8 +4114,8 @@ var loginCommand = async (args, deps) => {
4087
4114
  };
4088
4115
 
4089
4116
  // src/organization.ts
4090
- import * as fs10 from "node:fs";
4091
- import * as path10 from "node:path";
4117
+ import * as fs11 from "node:fs";
4118
+ import * as path11 from "node:path";
4092
4119
  var paint4 = (code) => (text) => process.stdout.isTTY === true ? `[${code}m${text}[0m` : text;
4093
4120
  var dim4 = paint4("2");
4094
4121
  var green4 = paint4("32");
@@ -4152,7 +4179,7 @@ var scanFolder = (dir) => {
4152
4179
  const files = [];
4153
4180
  const skipped = [];
4154
4181
  const walk = (relative4) => {
4155
- const entries = fs10.readdirSync(path10.join(dir, relative4), { withFileTypes: true }).toSorted((a, b) => a.name.localeCompare(b.name));
4182
+ const entries = fs11.readdirSync(path11.join(dir, relative4), { withFileTypes: true }).toSorted((a, b) => a.name.localeCompare(b.name));
4156
4183
  for (const entry of entries) {
4157
4184
  const child = relative4 === "" ? entry.name : `${relative4}/${entry.name}`;
4158
4185
  if (entry.isSymbolicLink()) {
@@ -4161,7 +4188,7 @@ var scanFolder = (dir) => {
4161
4188
  if (SKIPPED_DIRECTORIES.has(entry.name)) skipped.push({ path: child, reason: "skipped" });
4162
4189
  else walk(child);
4163
4190
  } else if (entry.isFile()) {
4164
- const size = fs10.statSync(path10.join(dir, child)).size;
4191
+ const size = fs11.statSync(path11.join(dir, child)).size;
4165
4192
  if (size > FOLDER_FILE_BYTES) skipped.push({ path: child, reason: "over 1 MiB" });
4166
4193
  else files.push({ path: child, size });
4167
4194
  }
@@ -4214,7 +4241,7 @@ var folderCommand = async (api2, args) => {
4214
4241
  }
4215
4242
  case "push": {
4216
4243
  if (dir === void 0) return fail4("usage: mend folder push <name> <dir> [--replace]");
4217
- if (!fs10.existsSync(dir) || !fs10.statSync(dir).isDirectory()) {
4244
+ if (!fs11.existsSync(dir) || !fs11.statSync(dir).isDirectory()) {
4218
4245
  return fail4(`${dir} is not a directory`);
4219
4246
  }
4220
4247
  const folder = await folderNamed(api2, name);
@@ -4229,7 +4256,7 @@ var folderCommand = async (api2, args) => {
4229
4256
  files: batch.map((file) => ({
4230
4257
  path: file.path,
4231
4258
  // Read one batch at a time, so a large tree never sits in memory at once.
4232
- contentsBase64: fs10.readFileSync(path10.join(dir, file.path)).toString("base64")
4259
+ contentsBase64: fs11.readFileSync(path11.join(dir, file.path)).toString("base64")
4233
4260
  })),
4234
4261
  // --replace empties the folder with the first batch; the rest add to it.
4235
4262
  merge: !(replace && index === 0)
@@ -4414,7 +4441,7 @@ import { createHmac, randomBytes } from "node:crypto";
4414
4441
  import { readFile } from "node:fs/promises";
4415
4442
  import * as net2 from "node:net";
4416
4443
  import * as os8 from "node:os";
4417
- import * as path12 from "node:path";
4444
+ import * as path13 from "node:path";
4418
4445
 
4419
4446
  // src/server-docker-volumes.ts
4420
4447
  import { createHash as createHash2 } from "node:crypto";
@@ -4632,9 +4659,9 @@ var verifyServerDockerVolumes = (runtime, input) => ownership(runtime, input, "v
4632
4659
 
4633
4660
  // src/server-store.ts
4634
4661
  import { randomUUID } from "node:crypto";
4635
- import * as fs11 from "node:fs";
4662
+ import * as fs12 from "node:fs";
4636
4663
  import * as os7 from "node:os";
4637
- import * as path11 from "node:path";
4664
+ import * as path12 from "node:path";
4638
4665
  var ServerStoreError = class extends Error {
4639
4666
  _tag = "ServerStoreError";
4640
4667
  };
@@ -4655,28 +4682,28 @@ var attempt = (operation) => {
4655
4682
  var hasCode = (cause, code) => cause instanceof Error && "code" in cause && cause.code === code;
4656
4683
  var readOptional = (file) => {
4657
4684
  try {
4658
- return fs11.readFileSync(file, "utf8");
4685
+ return fs12.readFileSync(file, "utf8");
4659
4686
  } catch (cause) {
4660
4687
  if (hasCode(cause, "ENOENT")) return null;
4661
4688
  throw cause;
4662
4689
  }
4663
4690
  };
4664
4691
  var syncDirectory = (directory) => {
4665
- const fd = fs11.openSync(directory, "r");
4692
+ const fd = fs12.openSync(directory, "r");
4666
4693
  try {
4667
- fs11.fsyncSync(fd);
4694
+ fs12.fsyncSync(fd);
4668
4695
  } finally {
4669
- fs11.closeSync(fd);
4696
+ fs12.closeSync(fd);
4670
4697
  }
4671
4698
  };
4672
4699
  var writeDurable = (file, content, mode = 384) => {
4673
- const fd = fs11.openSync(file, "wx", mode);
4700
+ const fd = fs12.openSync(file, "wx", mode);
4674
4701
  try {
4675
- fs11.writeFileSync(fd, content, "utf8");
4676
- fs11.fchmodSync(fd, mode);
4677
- fs11.fsyncSync(fd);
4702
+ fs12.writeFileSync(fd, content, "utf8");
4703
+ fs12.fchmodSync(fd, mode);
4704
+ fs12.fsyncSync(fd);
4678
4705
  } finally {
4679
- fs11.closeSync(fd);
4706
+ fs12.closeSync(fd);
4680
4707
  }
4681
4708
  };
4682
4709
  var fileKeys = ["identity", "config", "env", "compose", "postgresInit"];
@@ -4696,7 +4723,7 @@ var parseLockOwner = (raw) => {
4696
4723
  };
4697
4724
  var describeOwner = (lockDir) => {
4698
4725
  try {
4699
- const raw = JSON.parse(fs11.readFileSync(path11.join(lockDir, "owner.json"), "utf8"));
4726
+ const raw = JSON.parse(fs12.readFileSync(path12.join(lockDir, "owner.json"), "utf8"));
4700
4727
  const owner = parseLockOwner(raw);
4701
4728
  if (owner === null) return "owner metadata is invalid";
4702
4729
  const label = `PID ${owner.pid} on ${owner.hostname}`;
@@ -4716,28 +4743,28 @@ var lockGuidance = (lockDir) => new ServerStoreError(
4716
4743
  );
4717
4744
  var acquireLock = (configDir, create) => {
4718
4745
  if (create) {
4719
- fs11.mkdirSync(configDir, { recursive: true, mode: 448 });
4720
- fs11.chmodSync(configDir, 448);
4721
- } else if (!fs11.existsSync(configDir)) {
4746
+ fs12.mkdirSync(configDir, { recursive: true, mode: 448 });
4747
+ fs12.chmodSync(configDir, 448);
4748
+ } else if (!fs12.existsSync(configDir)) {
4722
4749
  throw new ServerStoreError(
4723
4750
  "No Mend server is configured. Run mend server setup explicitly to install one."
4724
4751
  );
4725
4752
  }
4726
- const lockDir = path11.join(configDir, "server.lock");
4753
+ const lockDir = path12.join(configDir, "server.lock");
4727
4754
  try {
4728
- fs11.mkdirSync(lockDir, { mode: 448 });
4755
+ fs12.mkdirSync(lockDir, { mode: 448 });
4729
4756
  } catch (cause) {
4730
4757
  if (hasCode(cause, "EEXIST")) throw lockGuidance(lockDir);
4731
4758
  throw cause;
4732
4759
  }
4733
- const owned = fs11.statSync(lockDir);
4734
- const ownerFile = path11.join(lockDir, "owner.json");
4760
+ const owned = fs12.statSync(lockDir);
4761
+ const ownerFile = path12.join(lockDir, "owner.json");
4735
4762
  const owner = `${JSON.stringify({ pid: process.pid, hostname: os7.hostname(), token: randomUUID() })}
4736
4763
  `;
4737
4764
  let open = true;
4738
4765
  const assertOwned = () => {
4739
- const current = fs11.statSync(lockDir);
4740
- if (!open || current.dev !== owned.dev || current.ino !== owned.ino || fs11.readFileSync(ownerFile, "utf8") !== owner) {
4766
+ const current = fs12.statSync(lockDir);
4767
+ if (!open || current.dev !== owned.dev || current.ino !== owned.ino || fs12.readFileSync(ownerFile, "utf8") !== owner) {
4741
4768
  throw new ServerStoreError(
4742
4769
  "Server lock ownership was lost. Stop and check for another server command before retrying."
4743
4770
  );
@@ -4753,8 +4780,8 @@ var acquireLock = (configDir, create) => {
4753
4780
  release: () => {
4754
4781
  const result = attempt(() => {
4755
4782
  assertOwned();
4756
- fs11.unlinkSync(ownerFile);
4757
- fs11.rmdirSync(lockDir);
4783
+ fs12.unlinkSync(ownerFile);
4784
+ fs12.rmdirSync(lockDir);
4758
4785
  });
4759
4786
  open = false;
4760
4787
  return result;
@@ -4763,7 +4790,7 @@ var acquireLock = (configDir, create) => {
4763
4790
  };
4764
4791
  var readIdentity = (paths) => {
4765
4792
  const identity = readOptional(paths.identity);
4766
- if (identity === null && (fs11.existsSync(paths.active) || fs11.existsSync(paths.generations) && fs11.readdirSync(paths.generations).length > 0)) {
4793
+ if (identity === null && (fs12.existsSync(paths.active) || fs12.existsSync(paths.generations) && fs12.readdirSync(paths.generations).length > 0)) {
4767
4794
  throw new ServerStoreError(
4768
4795
  "Server identity.env is missing. Restore it from a retained generation or backup; refusing to generate replacement credentials."
4769
4796
  );
@@ -4773,7 +4800,7 @@ var readIdentity = (paths) => {
4773
4800
  var readActive = (paths) => {
4774
4801
  let target;
4775
4802
  try {
4776
- target = fs11.readlinkSync(paths.active);
4803
+ target = fs12.readlinkSync(paths.active);
4777
4804
  } catch (cause) {
4778
4805
  if (hasCode(cause, "ENOENT")) return null;
4779
4806
  throw cause;
@@ -4783,13 +4810,13 @@ var readActive = (paths) => {
4783
4810
  "Server active pointer is invalid. Restore the symlink to a retained generation before retrying."
4784
4811
  );
4785
4812
  }
4786
- const directory = path11.join(paths.configDir, target);
4813
+ const directory = path12.join(paths.configDir, target);
4787
4814
  const files = {
4788
- identity: fs11.readFileSync(path11.join(directory, fileNames.identity), "utf8"),
4789
- config: fs11.readFileSync(path11.join(directory, fileNames.config), "utf8"),
4790
- env: fs11.readFileSync(path11.join(directory, fileNames.env), "utf8"),
4791
- compose: fs11.readFileSync(path11.join(directory, fileNames.compose), "utf8"),
4792
- postgresInit: fs11.readFileSync(path11.join(directory, fileNames.postgresInit), "utf8")
4815
+ identity: fs12.readFileSync(path12.join(directory, fileNames.identity), "utf8"),
4816
+ config: fs12.readFileSync(path12.join(directory, fileNames.config), "utf8"),
4817
+ env: fs12.readFileSync(path12.join(directory, fileNames.env), "utf8"),
4818
+ compose: fs12.readFileSync(path12.join(directory, fileNames.compose), "utf8"),
4819
+ postgresInit: fs12.readFileSync(path12.join(directory, fileNames.postgresInit), "utf8")
4793
4820
  };
4794
4821
  if (readIdentity(paths) !== files.identity) {
4795
4822
  throw new ServerStoreError(
@@ -4799,20 +4826,20 @@ var readActive = (paths) => {
4799
4826
  return { directory, files };
4800
4827
  };
4801
4828
  var publishIdentity = (paths, identity) => {
4802
- const temporary = path11.join(paths.configDir, `.identity-${randomUUID()}`);
4829
+ const temporary = path12.join(paths.configDir, `.identity-${randomUUID()}`);
4803
4830
  writeDurable(temporary, identity);
4804
- fs11.linkSync(temporary, paths.identity);
4831
+ fs12.linkSync(temporary, paths.identity);
4805
4832
  syncDirectory(paths.configDir);
4806
- fs11.unlinkSync(temporary);
4833
+ fs12.unlinkSync(temporary);
4807
4834
  };
4808
4835
  var prepareGeneration = (paths, files) => {
4809
- fs11.mkdirSync(paths.generations, { recursive: true, mode: 448 });
4836
+ fs12.mkdirSync(paths.generations, { recursive: true, mode: 448 });
4810
4837
  const generationName = `gen-${randomUUID()}`;
4811
- const directory = path11.join(paths.generations, generationName);
4812
- fs11.mkdirSync(directory, { mode: 448 });
4838
+ const directory = path12.join(paths.generations, generationName);
4839
+ fs12.mkdirSync(directory, { mode: 448 });
4813
4840
  for (const key of fileKeys) {
4814
4841
  writeDurable(
4815
- path11.join(directory, fileNames[key]),
4842
+ path12.join(directory, fileNames[key]),
4816
4843
  files[key],
4817
4844
  key === "postgresInit" ? 493 : 384
4818
4845
  );
@@ -4823,18 +4850,18 @@ var prepareGeneration = (paths, files) => {
4823
4850
  return { directory, files };
4824
4851
  };
4825
4852
  var activateGeneration = (paths, generation) => {
4826
- const relative4 = path11.relative(paths.configDir, generation.directory);
4827
- if (!/^generations\/gen-[0-9a-f-]{36}$/.test(relative4) || readIdentity(paths) !== fs11.readFileSync(path11.join(generation.directory, "identity.env"), "utf8")) {
4853
+ const relative4 = path12.relative(paths.configDir, generation.directory);
4854
+ if (!/^generations\/gen-[0-9a-f-]{36}$/.test(relative4) || readIdentity(paths) !== fs12.readFileSync(path12.join(generation.directory, "identity.env"), "utf8")) {
4828
4855
  throw new ServerStoreError("Cannot activate a generation outside this installation identity.");
4829
4856
  }
4830
4857
  for (const key of fileKeys) {
4831
- if (fs11.readFileSync(path11.join(generation.directory, fileNames[key]), "utf8") !== generation.files[key]) {
4858
+ if (fs12.readFileSync(path12.join(generation.directory, fileNames[key]), "utf8") !== generation.files[key]) {
4832
4859
  throw new ServerStoreError("Cannot activate an incomplete or changed server generation.");
4833
4860
  }
4834
4861
  }
4835
- const pointer = path11.join(paths.configDir, `.active-${randomUUID()}`);
4836
- fs11.symlinkSync(relative4, pointer);
4837
- fs11.renameSync(pointer, paths.active);
4862
+ const pointer = path12.join(paths.configDir, `.active-${randomUUID()}`);
4863
+ fs12.symlinkSync(relative4, pointer);
4864
+ fs12.renameSync(pointer, paths.active);
4838
4865
  syncDirectory(paths.configDir);
4839
4866
  };
4840
4867
  var prepareFiles = (paths, files) => {
@@ -4843,7 +4870,7 @@ var prepareFiles = (paths, files) => {
4843
4870
  throw new ServerStoreError("Server identity already exists; refusing to replace credentials.");
4844
4871
  }
4845
4872
  const active = readActive(paths);
4846
- if (active !== null && fileKeys.every((key) => files[key] === active.files[key]) && (fs11.statSync(path11.join(active.directory, fileNames.postgresInit)).mode & 4095) === 493)
4873
+ if (active !== null && fileKeys.every((key) => files[key] === active.files[key]) && (fs12.statSync(path12.join(active.directory, fileNames.postgresInit)).mode & 4095) === 493)
4847
4874
  return active;
4848
4875
  if (identity === null) publishIdentity(paths, files.identity);
4849
4876
  return prepareGeneration(paths, files);
@@ -4856,9 +4883,9 @@ var commitGeneration = (paths, files) => {
4856
4883
  var createStore = (configDir, lock) => {
4857
4884
  const paths = {
4858
4885
  configDir,
4859
- identity: path11.join(configDir, "identity.env"),
4860
- generations: path11.join(configDir, "generations"),
4861
- active: path11.join(configDir, "active")
4886
+ identity: path12.join(configDir, "identity.env"),
4887
+ generations: path12.join(configDir, "generations"),
4888
+ active: path12.join(configDir, "active")
4862
4889
  };
4863
4890
  const whileOwned = (operation) => attempt(() => {
4864
4891
  lock.assertOwned();
@@ -4871,13 +4898,13 @@ var createStore = (configDir, lock) => {
4871
4898
  prepare: (files) => whileOwned(() => prepareFiles(paths, files)),
4872
4899
  activate: (generation) => whileOwned(() => activateGeneration(paths, generation)),
4873
4900
  createBackup: (previous, target) => whileOwned(() => {
4874
- const backups = path11.join(configDir, "backups");
4875
- fs11.mkdirSync(backups, { recursive: true, mode: 448 });
4876
- fs11.chmodSync(backups, 448);
4877
- const directory = path11.join(backups, `upgrade-${randomUUID()}`);
4878
- fs11.mkdirSync(directory, { mode: 448 });
4901
+ const backups = path12.join(configDir, "backups");
4902
+ fs12.mkdirSync(backups, { recursive: true, mode: 448 });
4903
+ fs12.chmodSync(backups, 448);
4904
+ const directory = path12.join(backups, `upgrade-${randomUUID()}`);
4905
+ fs12.mkdirSync(directory, { mode: 448 });
4879
4906
  writeDurable(
4880
- path11.join(directory, "recovery.json"),
4907
+ path12.join(directory, "recovery.json"),
4881
4908
  `${JSON.stringify(
4882
4909
  {
4883
4910
  previousGeneration: previous.directory,
@@ -4893,21 +4920,21 @@ var createStore = (configDir, lock) => {
4893
4920
  syncDirectory(directory);
4894
4921
  syncDirectory(backups);
4895
4922
  syncDirectory(configDir);
4896
- const partialFile = path11.join(directory, "database.sql.partial");
4923
+ const partialFile = path12.join(directory, "database.sql.partial");
4897
4924
  return {
4898
4925
  directory,
4899
4926
  partialFile,
4900
4927
  complete: () => whileOwned(() => {
4901
- if (fs11.statSync(partialFile).size === 0)
4928
+ if (fs12.statSync(partialFile).size === 0)
4902
4929
  throw new ServerStoreError("Database backup is empty; refusing target startup.");
4903
- const fd = fs11.openSync(partialFile, "r");
4930
+ const fd = fs12.openSync(partialFile, "r");
4904
4931
  try {
4905
- fs11.fchmodSync(fd, 384);
4906
- fs11.fsyncSync(fd);
4932
+ fs12.fchmodSync(fd, 384);
4933
+ fs12.fsyncSync(fd);
4907
4934
  } finally {
4908
- fs11.closeSync(fd);
4935
+ fs12.closeSync(fd);
4909
4936
  }
4910
- fs11.renameSync(partialFile, path11.join(directory, "database.sql"));
4937
+ fs12.renameSync(partialFile, path12.join(directory, "database.sql"));
4911
4938
  syncDirectory(directory);
4912
4939
  })
4913
4940
  };
@@ -4916,7 +4943,7 @@ var createStore = (configDir, lock) => {
4916
4943
  };
4917
4944
  var refuseFlatLayout = (configDir) => {
4918
4945
  if (["server.json", "server.env", "compose.yaml", "postgres-init.sh"].some(
4919
- (name) => fs11.existsSync(path11.join(configDir, name))
4946
+ (name) => fs12.existsSync(path12.join(configDir, name))
4920
4947
  )) {
4921
4948
  throw new ServerStoreError(
4922
4949
  "Unreleased flat server configuration found. Preserve its credentials and volumes; migrate it to the generation layout before retrying. Setup will not replace this identity."
@@ -4924,7 +4951,7 @@ var refuseFlatLayout = (configDir) => {
4924
4951
  }
4925
4952
  };
4926
4953
  var withServerStore = async (directory, operation, options = {}) => {
4927
- const configDir = path11.resolve(directory);
4954
+ const configDir = path12.resolve(directory);
4928
4955
  let lock;
4929
4956
  let result;
4930
4957
  try {
@@ -4941,9 +4968,9 @@ var withServerStore = async (directory, operation, options = {}) => {
4941
4968
  };
4942
4969
 
4943
4970
  // src/version.ts
4944
- import * as fs12 from "node:fs";
4971
+ import * as fs13 from "node:fs";
4945
4972
  var cliVersion = () => {
4946
- const raw = fs12.readFileSync(new URL("../package.json", import.meta.url), "utf8");
4973
+ const raw = fs13.readFileSync(new URL("../package.json", import.meta.url), "utf8");
4947
4974
  const parsed = JSON.parse(raw);
4948
4975
  if (typeof parsed === "object" && parsed !== null && "version" in parsed) {
4949
4976
  const version = parsed.version;
@@ -5646,7 +5673,7 @@ var resolveServerVersion = async (runtime, options, existing) => {
5646
5673
  return version;
5647
5674
  };
5648
5675
  var parseDockerSocketPath = (socket) => {
5649
- if (!path12.isAbsolute(socket) || /[\r\n$'"#:\\]/.test(socket)) {
5676
+ if (!path13.isAbsolute(socket) || /[\r\n$'"#:\\]/.test(socket)) {
5650
5677
  throw setupError(
5651
5678
  "--docker-socket must be an absolute path without line breaks or Compose interpolation characters."
5652
5679
  );
@@ -5672,8 +5699,8 @@ var resolveAssets = async (runtime, serverVersion, existing, store, options) =>
5672
5699
  if (options.assetsDir !== void 0) {
5673
5700
  try {
5674
5701
  const [compose2, postgresInit2] = await Promise.all([
5675
- readFile(path12.join(options.assetsDir, COMPOSE_ASSET), "utf8"),
5676
- readFile(path12.join(options.assetsDir, POSTGRES_INIT_ASSET), "utf8")
5702
+ readFile(path13.join(options.assetsDir, COMPOSE_ASSET), "utf8"),
5703
+ readFile(path13.join(options.assetsDir, POSTGRES_INIT_ASSET), "utf8")
5677
5704
  ]);
5678
5705
  validateComposeAsset(compose2);
5679
5706
  validatePostgresAsset(postgresInit2);
@@ -6200,9 +6227,9 @@ var manageServer = async (command, args, runtime, store) => {
6200
6227
  var nodeServerRuntime = () => {
6201
6228
  const environment = { ...process.env };
6202
6229
  const home = os8.homedir();
6203
- const configHome = environment["XDG_CONFIG_HOME"] ?? path12.join(home, ".config");
6230
+ const configHome = environment["XDG_CONFIG_HOME"] ?? path13.join(home, ".config");
6204
6231
  return {
6205
- configDir: path12.join(configHome, "mend"),
6232
+ configDir: path13.join(configHome, "mend"),
6206
6233
  platform: process.platform,
6207
6234
  cliVersion: cliVersion(),
6208
6235
  run: (command, args, options) => runServerProcess(command, args, environment, options),
@@ -6655,8 +6682,8 @@ var createServiceTunnels = (options) => {
6655
6682
  };
6656
6683
 
6657
6684
  // src/skills.ts
6658
- import * as fs13 from "node:fs";
6659
- import * as path13 from "node:path";
6685
+ import * as fs14 from "node:fs";
6686
+ import * as path14 from "node:path";
6660
6687
  var DEFAULT_SKILLS_DIR = ".agents/skills";
6661
6688
  var MAX_SKILL_FILES = 64;
6662
6689
  var MAX_SKILL_FILE_BYTES = 512 * 1024;
@@ -6679,12 +6706,12 @@ var readFrontmatterDescription = (contents) => {
6679
6706
  var walkFiles = (root) => {
6680
6707
  const found = [];
6681
6708
  const visit = (dir) => {
6682
- for (const entry of fs13.readdirSync(dir, { withFileTypes: true })) {
6709
+ for (const entry of fs14.readdirSync(dir, { withFileTypes: true })) {
6683
6710
  if (IGNORED_DIRS.has(entry.name)) continue;
6684
- const absolute = path13.join(dir, entry.name);
6711
+ const absolute = path14.join(dir, entry.name);
6685
6712
  let stat;
6686
6713
  try {
6687
- stat = fs13.statSync(absolute);
6714
+ stat = fs14.statSync(absolute);
6688
6715
  } catch {
6689
6716
  continue;
6690
6717
  }
@@ -6698,7 +6725,7 @@ var walkFiles = (root) => {
6698
6725
  var scanSkillLibrary = (root) => {
6699
6726
  let entries;
6700
6727
  try {
6701
- entries = fs13.readdirSync(root, { withFileTypes: true });
6728
+ entries = fs14.readdirSync(root, { withFileTypes: true });
6702
6729
  } catch {
6703
6730
  return { error: `${root} is not a readable directory` };
6704
6731
  }
@@ -6706,23 +6733,23 @@ var scanSkillLibrary = (root) => {
6706
6733
  const notes = [];
6707
6734
  for (const entry of entries.toSorted((a, b) => a.name.localeCompare(b.name))) {
6708
6735
  if (entry.name.startsWith(".")) continue;
6709
- const skillDir = path13.join(root, entry.name);
6736
+ const skillDir = path14.join(root, entry.name);
6710
6737
  let stat;
6711
6738
  try {
6712
- stat = fs13.statSync(skillDir);
6739
+ stat = fs14.statSync(skillDir);
6713
6740
  } catch {
6714
6741
  continue;
6715
6742
  }
6716
6743
  if (!stat.isDirectory()) continue;
6717
- if (!fs13.existsSync(path13.join(skillDir, "SKILL.md"))) {
6744
+ if (!fs14.existsSync(path14.join(skillDir, "SKILL.md"))) {
6718
6745
  notes.push({ skill: entry.name, message: "no SKILL.md \u2014 skipped" });
6719
6746
  continue;
6720
6747
  }
6721
6748
  const files = [];
6722
6749
  let bytes = 0;
6723
6750
  for (const absolute of walkFiles(skillDir)) {
6724
- const relative4 = path13.relative(skillDir, absolute).split(path13.sep).join("/");
6725
- const buffer = fs13.readFileSync(absolute);
6751
+ const relative4 = path14.relative(skillDir, absolute).split(path14.sep).join("/");
6752
+ const buffer = fs14.readFileSync(absolute);
6726
6753
  if (buffer.byteLength > MAX_SKILL_FILE_BYTES) {
6727
6754
  notes.push({ skill: entry.name, message: `${relative4} is over 512KB \u2014 skipped` });
6728
6755
  continue;
@@ -6758,15 +6785,15 @@ var scanSkillLibrary = (root) => {
6758
6785
 
6759
6786
  // src/ssh-setup.ts
6760
6787
  import * as os10 from "node:os";
6761
- import * as path15 from "node:path";
6788
+ import * as path16 from "node:path";
6762
6789
 
6763
6790
  // ../../packages/workspace-ssh/src/index.ts
6764
6791
  import { spawnSync as spawnSync5 } from "node:child_process";
6765
6792
  import { createHash as createHash3 } from "node:crypto";
6766
- import * as fs14 from "node:fs";
6793
+ import * as fs15 from "node:fs";
6767
6794
  import { isIP as isIP2 } from "node:net";
6768
6795
  import * as os9 from "node:os";
6769
- import * as path14 from "node:path";
6796
+ import * as path15 from "node:path";
6770
6797
  var LEGACY_BLOCK_BEGIN = "# >>> mend workspace ssh (managed by `mend ssh setup`) >>>";
6771
6798
  var LEGACY_BLOCK_END = "# <<< mend workspace ssh <<<";
6772
6799
  var WorkspaceSshError = class extends Error {
@@ -6853,8 +6880,8 @@ var blockBegin = (alias) => `# >>> mend workspace ssh ${alias} (managed) >>>`;
6853
6880
  var blockEnd = (alias) => `# <<< mend workspace ssh ${alias} <<<`;
6854
6881
  var hasControls = (value) => /[\p{Cc}\p{Zl}\p{Zp}]/u.test(value);
6855
6882
  var parseIdentityPath = (value) => {
6856
- const resolved = path14.resolve(
6857
- value.startsWith("~/") ? path14.join(os9.homedir(), value.slice(2)) : value
6883
+ const resolved = path15.resolve(
6884
+ value.startsWith("~/") ? path15.join(os9.homedir(), value.slice(2)) : value
6858
6885
  );
6859
6886
  if (value === "" || hasControls(value) || hasControls(resolved) || value.includes("${") || resolved.includes("${")) {
6860
6887
  return failure(
@@ -7010,7 +7037,7 @@ var agentKeys = () => {
7010
7037
  };
7011
7038
  var readText = (file) => {
7012
7039
  try {
7013
- return success(fs14.readFileSync(file, "utf8"));
7040
+ return success(fs15.readFileSync(file, "utf8"));
7014
7041
  } catch (cause) {
7015
7042
  const error = cause instanceof Error && "code" in cause ? cause.code : void 0;
7016
7043
  return error === "ENOENT" ? success("") : failure(new WorkspaceSshError("key", `Could not read ${file}.`, cause));
@@ -7068,19 +7095,19 @@ var readRequiredKey = (keyPath, source) => {
7068
7095
  var readOptionalKey = (keyPath) => {
7069
7096
  const parsed = parseIdentityPath(keyPath);
7070
7097
  if (!parsed.ok) return parsed;
7071
- if (!fs14.existsSync(parsed.value) && !fs14.existsSync(publicKeyPath(parsed.value)))
7098
+ if (!fs15.existsSync(parsed.value) && !fs15.existsSync(publicKeyPath(parsed.value)))
7072
7099
  return success(null);
7073
7100
  return readRequiredKey(parsed.value, "existing");
7074
7101
  };
7075
7102
  var pinAgentKey = (configHome, publicKey) => {
7076
- const identityFile = path14.resolve(
7103
+ const identityFile = path15.resolve(
7077
7104
  configHome,
7078
7105
  "ssh",
7079
7106
  `agent-${hashIdentity(publicKeyIdentity(publicKey))}.pub`
7080
7107
  );
7081
7108
  try {
7082
- fs14.mkdirSync(path14.dirname(identityFile), { recursive: true, mode: 448 });
7083
- fs14.writeFileSync(identityFile, `${publicKey}
7109
+ fs15.mkdirSync(path15.dirname(identityFile), { recursive: true, mode: 448 });
7110
+ fs15.writeFileSync(identityFile, `${publicKey}
7084
7111
  `, { mode: 384 });
7085
7112
  return success({ publicKey, identityFile, source: "agent" });
7086
7113
  } catch (cause) {
@@ -7091,10 +7118,10 @@ var pinAgentKey = (configHome, publicKey) => {
7091
7118
  };
7092
7119
  var generateDedicatedKey = (privatePath) => {
7093
7120
  try {
7094
- fs14.mkdirSync(path14.dirname(privatePath), { recursive: true, mode: 448 });
7121
+ fs15.mkdirSync(path15.dirname(privatePath), { recursive: true, mode: 448 });
7095
7122
  } catch (cause) {
7096
7123
  return failure(
7097
- new WorkspaceSshError("key", `Could not create ${path14.dirname(privatePath)}.`, cause)
7124
+ new WorkspaceSshError("key", `Could not create ${path15.dirname(privatePath)}.`, cause)
7098
7125
  );
7099
7126
  }
7100
7127
  const generated = spawnSync5(
@@ -7123,7 +7150,7 @@ var generateDedicatedKey = (privatePath) => {
7123
7150
  return fresh;
7124
7151
  };
7125
7152
  var dedicatedKey = (configHome, create) => {
7126
- const privatePath = path14.join(configHome, "ssh", "id_ed25519");
7153
+ const privatePath = path15.join(configHome, "ssh", "id_ed25519");
7127
7154
  const existing = readOptionalKey(privatePath);
7128
7155
  if (existing.ok === false) return failure(existing.error);
7129
7156
  if (existing.value !== null || !create) return existing;
@@ -7171,10 +7198,10 @@ var writeWorkspaceSshConfig = (configFile, target, identityFile) => {
7171
7198
  const reconciled = reconcileWorkspaceSshConfig(before.value, target, identityFile);
7172
7199
  if (reconciled.ok === false) return failure(reconciled.error);
7173
7200
  try {
7174
- fs14.mkdirSync(path14.dirname(configFile), { recursive: true, mode: 448 });
7175
- fs14.chmodSync(path14.dirname(configFile), 448);
7176
- fs14.writeFileSync(configFile, reconciled.value, { mode: 384 });
7177
- fs14.chmodSync(configFile, 384);
7201
+ fs15.mkdirSync(path15.dirname(configFile), { recursive: true, mode: 448 });
7202
+ fs15.chmodSync(path15.dirname(configFile), 448);
7203
+ fs15.writeFileSync(configFile, reconciled.value, { mode: 384 });
7204
+ fs15.chmodSync(configFile, 384);
7178
7205
  return success(void 0);
7179
7206
  } catch (cause) {
7180
7207
  return failure(new WorkspaceSshError("config", `Could not write ${configFile}.`, cause));
@@ -7187,7 +7214,7 @@ var dim5 = ansi("2");
7187
7214
  var green5 = ansi("32");
7188
7215
  var warn = ansi("33");
7189
7216
  var say5 = (line) => console.log(line);
7190
- var sshConfigPath = () => path15.join(os10.homedir(), ".ssh", "config");
7217
+ var sshConfigPath = () => path16.join(os10.homedir(), ".ssh", "config");
7191
7218
  var flagValue2 = (args, flag) => {
7192
7219
  const index = args.indexOf(flag);
7193
7220
  return index === -1 || args[index + 1] === void 0 ? null : String(args[index + 1]);
@@ -7299,8 +7326,8 @@ var sshCommand = async (args, api2, cliHome, serverUrl) => {
7299
7326
  };
7300
7327
 
7301
7328
  // src/uninstall.ts
7302
- import * as fs15 from "node:fs";
7303
- import * as path16 from "node:path";
7329
+ import * as fs16 from "node:fs";
7330
+ import * as path17 from "node:path";
7304
7331
  var UNINSTALL_USAGE = "usage: mend uninstall [--all | --server | --home] [--yes]";
7305
7332
  var parseUninstallArgs = (args) => {
7306
7333
  let scope = null;
@@ -7322,14 +7349,14 @@ var parseUninstallArgs = (args) => {
7322
7349
  var SERVER_FILES = ["identity.env", "active", "generations", "backups"];
7323
7350
  var countEntries = (directory) => {
7324
7351
  try {
7325
- return fs15.readdirSync(directory).length;
7352
+ return fs16.readdirSync(directory).length;
7326
7353
  } catch {
7327
7354
  return 0;
7328
7355
  }
7329
7356
  };
7330
7357
  var exists = (file) => {
7331
7358
  try {
7332
- fs15.lstatSync(file);
7359
+ fs16.lstatSync(file);
7333
7360
  return true;
7334
7361
  } catch {
7335
7362
  return false;
@@ -7338,7 +7365,7 @@ var exists = (file) => {
7338
7365
  var managedBlockCount = (sshConfigFile) => {
7339
7366
  let config;
7340
7367
  try {
7341
- config = fs15.readFileSync(sshConfigFile, "utf8");
7368
+ config = fs16.readFileSync(sshConfigFile, "utf8");
7342
7369
  } catch {
7343
7370
  return 0;
7344
7371
  }
@@ -7362,27 +7389,27 @@ var describeUninstall = async (runtime, scope) => {
7362
7389
  if (!read.error.message.startsWith("No Mend server is configured")) throw read.error;
7363
7390
  server = "none";
7364
7391
  } else if (read.value === null) {
7365
- server = exists(path16.join(configDir, "identity.env")) ? {
7392
+ server = exists(path17.join(configDir, "identity.env")) ? {
7366
7393
  version: "(no active generation)",
7367
7394
  appUrl: "",
7368
7395
  dockerContext: "",
7369
- generations: countEntries(path16.join(configDir, "generations")),
7370
- backups: countEntries(path16.join(configDir, "backups"))
7396
+ generations: countEntries(path17.join(configDir, "generations")),
7397
+ backups: countEntries(path17.join(configDir, "backups"))
7371
7398
  } : "none";
7372
7399
  } else {
7373
7400
  server = {
7374
7401
  version: read.value.config.serverVersion,
7375
7402
  appUrl: read.value.config.appUrl,
7376
7403
  dockerContext: read.value.config.dockerContext,
7377
- generations: countEntries(path16.join(configDir, "generations")),
7378
- backups: countEntries(path16.join(configDir, "backups"))
7404
+ generations: countEntries(path17.join(configDir, "generations")),
7405
+ backups: countEntries(path17.join(configDir, "backups"))
7379
7406
  };
7380
7407
  }
7381
7408
  }
7382
7409
  let home = null;
7383
7410
  if (scope !== "server") {
7384
- const cliConfig = path16.join(runtime.cliHome, "cli.json");
7385
- const sshDirectory = path16.join(runtime.cliHome, "ssh");
7411
+ const cliConfig = path17.join(runtime.cliHome, "cli.json");
7412
+ const sshDirectory = path17.join(runtime.cliHome, "ssh");
7386
7413
  home = {
7387
7414
  cliConfig: exists(cliConfig) ? cliConfig : null,
7388
7415
  sshDirectory: exists(sshDirectory) ? sshDirectory : null,
@@ -7514,7 +7541,7 @@ var removeServer = async (runtime, failures, leftovers) => {
7514
7541
  }
7515
7542
  }
7516
7543
  for (const name of SERVER_FILES) {
7517
- fs15.rmSync(path16.join(configDir, name), { recursive: true, force: true });
7544
+ fs16.rmSync(path17.join(configDir, name), { recursive: true, force: true });
7518
7545
  }
7519
7546
  server.writeLine(`removed ${configDir}/{identity.env, active, generations, backups}`);
7520
7547
  },
@@ -7525,20 +7552,20 @@ var removeServer = async (runtime, failures, leftovers) => {
7525
7552
  var removeHome = async (runtime, plan, failures, leftovers) => {
7526
7553
  const { server } = runtime;
7527
7554
  if (plan.cliConfig !== null) {
7528
- fs15.rmSync(plan.cliConfig, { force: true });
7555
+ fs16.rmSync(plan.cliConfig, { force: true });
7529
7556
  server.writeLine(`removed ${plan.cliConfig}`);
7530
7557
  }
7531
7558
  if (plan.sshDirectory !== null) {
7532
- fs15.rmSync(plan.sshDirectory, { recursive: true, force: true });
7559
+ fs16.rmSync(plan.sshDirectory, { recursive: true, force: true });
7533
7560
  server.writeLine(`removed ${plan.sshDirectory}`);
7534
7561
  }
7535
7562
  if (plan.managedSshBlocks > 0) {
7536
7563
  try {
7537
- const before = fs15.readFileSync(runtime.sshConfigFile, "utf8");
7564
+ const before = fs16.readFileSync(runtime.sshConfigFile, "utf8");
7538
7565
  const stripped = stripManagedWorkspaceSshBlocks(before);
7539
7566
  if (!stripped.ok) throw stripped.error;
7540
7567
  if (stripped.value.removed > 0) {
7541
- fs15.writeFileSync(runtime.sshConfigFile, stripped.value.config, { mode: 384 });
7568
+ fs16.writeFileSync(runtime.sshConfigFile, stripped.value.config, { mode: 384 });
7542
7569
  server.writeLine(
7543
7570
  `removed ${plural(stripped.value.removed, "managed block")} from ${runtime.sshConfigFile}`
7544
7571
  );
@@ -7551,12 +7578,12 @@ var removeHome = async (runtime, plan, failures, leftovers) => {
7551
7578
  }
7552
7579
  let remaining = [];
7553
7580
  try {
7554
- remaining = fs15.readdirSync(runtime.cliHome);
7581
+ remaining = fs16.readdirSync(runtime.cliHome);
7555
7582
  } catch {
7556
7583
  return;
7557
7584
  }
7558
7585
  if (remaining.length === 0) {
7559
- fs15.rmdirSync(runtime.cliHome);
7586
+ fs16.rmdirSync(runtime.cliHome);
7560
7587
  server.writeLine(`removed ${runtime.cliHome}`);
7561
7588
  } else {
7562
7589
  leftovers.push(
@@ -7620,19 +7647,19 @@ var upgradeUrl = async (input) => {
7620
7647
  // src/main.ts
7621
7648
  var mendCliHome = () => {
7622
7649
  const xdg = process.env["XDG_CONFIG_HOME"];
7623
- const preferred = path17.join(
7624
- xdg === void 0 || xdg === "" ? path17.join(os11.homedir(), ".config") : xdg,
7650
+ const preferred = path18.join(
7651
+ xdg === void 0 || xdg === "" ? path18.join(os11.homedir(), ".config") : xdg,
7625
7652
  "mend"
7626
7653
  );
7627
- const legacy = path17.join(os11.homedir(), ".mend");
7628
- return !fs16.existsSync(preferred) && fs16.existsSync(legacy) ? legacy : preferred;
7654
+ const legacy = path18.join(os11.homedir(), ".mend");
7655
+ return !fs17.existsSync(preferred) && fs17.existsSync(legacy) ? legacy : preferred;
7629
7656
  };
7630
- var CONFIG_PATH = path17.join(mendCliHome(), "cli.json");
7657
+ var CONFIG_PATH = path18.join(mendCliHome(), "cli.json");
7631
7658
  var loadConfig = () => {
7632
7659
  let fileConfig = {};
7633
- if (fs16.existsSync(CONFIG_PATH)) {
7660
+ if (fs17.existsSync(CONFIG_PATH)) {
7634
7661
  try {
7635
- fileConfig = JSON.parse(fs16.readFileSync(CONFIG_PATH, "utf8"));
7662
+ fileConfig = JSON.parse(fs17.readFileSync(CONFIG_PATH, "utf8"));
7636
7663
  } catch {
7637
7664
  fail6(`could not parse ${CONFIG_PATH}`);
7638
7665
  }
@@ -7884,7 +7911,7 @@ var adopt = async (config, args) => {
7884
7911
  }
7885
7912
  const sourceIssue = repositoryCloneUrlIssue(source);
7886
7913
  if (sourceIssue !== null) return fail6(sourceIssue);
7887
- const projectName = name ?? normalizeProjectName(path17.basename(source, ".git"));
7914
+ const projectName = name ?? normalizeProjectName(path18.basename(source, ".git"));
7888
7915
  const auth = authFlagIndex !== -1 && args[authFlagIndex + 1] !== void 0 ? String(args[authFlagIndex + 1]) : null;
7889
7916
  if (auth !== null && auth !== "ambient" && auth !== "mend-key" && auth !== "bridge") {
7890
7917
  return fail6(`--auth takes "ambient", "mend-key", or "bridge", not "${auth}"`);
@@ -7933,7 +7960,7 @@ var findProject = async (config, explicit, adoptCwd = false) => {
7933
7960
  const sourceIssue = repositoryCloneUrlIssue(facts.originUrl);
7934
7961
  if (sourceIssue !== null) return fail6(sourceIssue);
7935
7962
  const adopted = await api(config, "POST", "/projects", {
7936
- name: normalizeProjectName(path17.basename(facts.repoRoot)),
7963
+ name: normalizeProjectName(path18.basename(facts.repoRoot)),
7937
7964
  source: facts.originUrl
7938
7965
  });
7939
7966
  say6(`${green6("\u2713")} adopted \xB7 ${adopted.name} \xB7 ${dim6(adopted.storePath)}`);
@@ -8894,13 +8921,13 @@ var serviceRestart = async (config, args) => {
8894
8921
  };
8895
8922
  var serviceInit = async (args) => {
8896
8923
  const root = gitTopLevel(process.cwd()) ?? process.cwd();
8897
- const target = path17.join(root, "mend.toml");
8898
- if (fs16.existsSync(target)) {
8924
+ const target = path18.join(root, "mend.toml");
8925
+ if (fs17.existsSync(target)) {
8899
8926
  return fail6(`${target} already exists \u2014 edit it directly (init never merges)`);
8900
8927
  }
8901
- const rootFiles = fs16.readdirSync(root);
8928
+ const rootFiles = fs17.readdirSync(root);
8902
8929
  const proposals = [];
8903
- const readRoot = (name) => fs16.readFileSync(path17.join(root, name), "utf8");
8930
+ const readRoot = (name) => fs17.readFileSync(path18.join(root, name), "utf8");
8904
8931
  if (rootFiles.includes("package.json")) {
8905
8932
  proposals.push(...proposeFromPackageJson(readRoot("package.json"), rootFiles));
8906
8933
  }
@@ -8910,13 +8937,13 @@ var serviceInit = async (args) => {
8910
8937
  );
8911
8938
  for (const glob of globs) {
8912
8939
  const parent = glob.replace(/\/?\*+$/, "");
8913
- const dirs = glob.endsWith("*") ? fs16.existsSync(path17.join(root, parent)) ? fs16.readdirSync(path17.join(root, parent)).map((dir) => path17.join(parent, dir)) : [] : [glob];
8940
+ const dirs = glob.endsWith("*") ? fs17.existsSync(path18.join(root, parent)) ? fs17.readdirSync(path18.join(root, parent)).map((dir) => path18.join(parent, dir)) : [] : [glob];
8914
8941
  for (const dir of dirs) {
8915
- const manifest = path17.join(root, dir, "package.json");
8916
- if (!fs16.existsSync(manifest)) continue;
8942
+ const manifest = path18.join(root, dir, "package.json");
8943
+ if (!fs17.existsSync(manifest)) continue;
8917
8944
  for (const proposal of proposeFromWorkspacePackage(
8918
- path17.basename(dir),
8919
- fs16.readFileSync(manifest, "utf8"),
8945
+ path18.basename(dir),
8946
+ fs17.readFileSync(manifest, "utf8"),
8920
8947
  rootFiles
8921
8948
  )) {
8922
8949
  if (!proposals.some((existing) => existing.name === proposal.name)) {
@@ -8960,7 +8987,7 @@ var serviceInit = async (args) => {
8960
8987
  return;
8961
8988
  }
8962
8989
  }
8963
- fs16.writeFileSync(target, toml);
8990
+ fs17.writeFileSync(target, toml);
8964
8991
  say6(`${green6("\u2713")} wrote ${target} \u2014 commit it, then: mend service run ${proposals[0]?.name}`);
8965
8992
  };
8966
8993
  var tunnelServices = async (config, services, portOverride) => {
@@ -9064,18 +9091,18 @@ var serviceCommand = async (config, args) => {
9064
9091
  }
9065
9092
  };
9066
9093
  var isProvider = (value) => value === "claude" || value === "codex" || value === "github";
9067
- var readIfExists = (file) => fs16.existsSync(file) ? fs16.readFileSync(file, "utf8") : null;
9094
+ var readIfExists = (file) => fs17.existsSync(file) ? fs17.readFileSync(file, "utf8") : null;
9068
9095
  var localCredential = (provider) => {
9069
9096
  const home = os11.homedir();
9070
9097
  switch (provider) {
9071
9098
  case "codex":
9072
9099
  return readIfExists(
9073
- path17.join(process.env["CODEX_HOME"] ?? path17.join(home, ".codex"), "auth.json")
9100
+ path18.join(process.env["CODEX_HOME"] ?? path18.join(home, ".codex"), "auth.json")
9074
9101
  );
9075
9102
  case "claude":
9076
9103
  return readIfExists(
9077
- path17.join(
9078
- process.env["CLAUDE_CONFIG_DIR"] ?? path17.join(home, ".claude"),
9104
+ path18.join(
9105
+ process.env["CLAUDE_CONFIG_DIR"] ?? path18.join(home, ".claude"),
9079
9106
  ".credentials.json"
9080
9107
  )
9081
9108
  );
@@ -9125,7 +9152,7 @@ var claudeGrantSecret = () => {
9125
9152
  return read.kind === "missing" ? null : read.secret;
9126
9153
  };
9127
9154
  var doctorBundle = (config, args) => doctorBundleCommand(args, {
9128
- defaultDir: path17.join(mendCliHome(), "bundles"),
9155
+ defaultDir: path18.join(mendCliHome(), "bundles"),
9129
9156
  now: () => /* @__PURE__ */ new Date(),
9130
9157
  say: say6,
9131
9158
  warn: (line) => process.stderr.write(`${line}
@@ -9166,74 +9193,69 @@ var staleGrantReason = (secret) => {
9166
9193
  };
9167
9194
  var claudeGrant = async () => {
9168
9195
  const cli = claudeCli();
9169
- const dir = claudeGrantDir(mendCliHome());
9196
+ const home = mendCliHome();
9170
9197
  const personal = personalClaudeDir();
9171
9198
  const personalBefore = grantStatus(cli, personal);
9172
- let status = grantStatus(cli, dir);
9173
- if (status === null) {
9174
- fail6(
9175
- "claude: could not run `claude auth status` \u2014 install Claude Code, set MEND_CLAUDE_BIN, or paste a credential: mend connect claude --from-stdin"
9176
- );
9177
- return null;
9178
- }
9179
- if (!status.loggedIn) {
9180
- say6(` Mend needs its own Claude login, kept in ${dir}`);
9199
+ const dir = throwawayLoginDir(home, "claude-login-");
9200
+ try {
9201
+ if (grantStatus(cli, dir) === null) {
9202
+ fail6(
9203
+ "claude: could not run `claude auth status` \u2014 install Claude Code, set MEND_CLAUDE_BIN, or paste a credential: mend connect claude --from-stdin"
9204
+ );
9205
+ return null;
9206
+ }
9207
+ say6(" Mend needs its own Claude login; it is sent to your server and not kept here");
9181
9208
  say6(dim6(" your own Claude login stays as it is"));
9182
9209
  if (!runClaudeLogin(cli, dir)) {
9183
9210
  fail6("claude: the login did not complete");
9184
9211
  return null;
9185
9212
  }
9186
- status = grantStatus(cli, dir) ?? status;
9187
- if (!status.loggedIn) {
9213
+ const status = grantStatus(cli, dir);
9214
+ if (status === null || !status.loggedIn) {
9188
9215
  fail6("claude: the login completed but Claude still reports no grant in Mend's directory");
9189
9216
  return null;
9190
9217
  }
9191
- }
9192
- if (status.configDirectory !== null && path17.resolve(status.configDirectory) !== path17.resolve(dir)) {
9193
- fail6(
9194
- `claude: this Claude read ${status.configDirectory} instead of ${dir}, so a separate grant is not possible \u2014 connect the shared one deliberately with --use-my-login`
9195
- );
9196
- return null;
9197
- }
9198
- let read = readGrant(dir);
9199
- if (read.kind !== "missing") {
9218
+ if (status.configDirectory !== null && path18.resolve(status.configDirectory) !== path18.resolve(dir)) {
9219
+ fail6(
9220
+ `claude: this Claude read ${status.configDirectory} instead of ${dir}, so a separate grant is not possible \u2014 connect the shared one deliberately with --use-my-login`
9221
+ );
9222
+ return null;
9223
+ }
9224
+ const read = readGrant(dir);
9225
+ if (read.kind === "missing") {
9226
+ const where = read.triedService === null ? read.triedPath : `${read.triedPath} or the Keychain item ${read.triedService}`;
9227
+ fail6(`claude: logged in, but no credential to read \u2014 looked in ${where}`);
9228
+ return null;
9229
+ }
9200
9230
  const why = staleGrantReason(read.secret);
9201
9231
  if (why !== null) {
9202
- say6(` Mend's Claude grant is ${why}; logging in again`);
9203
- if (!runClaudeLogin(cli, dir)) {
9204
- fail6("claude: the login did not complete");
9205
- return null;
9206
- }
9207
- read = readGrant(dir);
9208
- const still = read.kind === "missing" ? "missing" : staleGrantReason(read.secret);
9209
- if (still !== null) {
9210
- fail6(`claude: the grant is still ${still} after logging in`);
9211
- return null;
9212
- }
9232
+ fail6(`claude: the new login is already ${why}`);
9233
+ return null;
9213
9234
  }
9235
+ const mine = localCredential("claude");
9236
+ if (mine !== null && sameGrant(read.secret, mine)) {
9237
+ fail6(
9238
+ "claude: that is the same grant this machine's Claude holds, so both sides would race on refresh \u2014 connect it deliberately with --use-my-login"
9239
+ );
9240
+ return null;
9241
+ }
9242
+ const personalAfter = grantStatus(cli, personal);
9243
+ if (personalBefore?.loggedIn === true && personalAfter?.loggedIn === false) {
9244
+ say6(
9245
+ ` your own Claude login was signed out by this one \u2014 this account allows one grant at a time. Run \`claude auth login\` to get it back, and connect the shared grant with --use-my-login instead.`
9246
+ );
9247
+ } else if (personalAfter?.loggedIn === true) {
9248
+ say6(dim6(" your own Claude login still works \xB7 verified"));
9249
+ }
9250
+ const kept = claudeGrantDir(home);
9251
+ if (fs17.existsSync(kept)) {
9252
+ forgetGrant(kept);
9253
+ say6(dim6(` removed the copy an older mend kept in ${kept} \xB7 the server refreshes the login`));
9254
+ }
9255
+ return read.secret;
9256
+ } finally {
9257
+ forgetGrant(dir);
9214
9258
  }
9215
- if (read.kind === "missing") {
9216
- const where = read.triedService === null ? read.triedPath : `${read.triedPath} or the Keychain item ${read.triedService}`;
9217
- fail6(`claude: logged in, but no credential to read \u2014 looked in ${where}`);
9218
- return null;
9219
- }
9220
- const mine = localCredential("claude");
9221
- if (mine !== null && sameGrant(read.secret, mine)) {
9222
- fail6(
9223
- "claude: that is the same grant this machine's Claude holds, so both sides would race on refresh \u2014 remove Mend's directory and log in again, or accept the race with --use-my-login"
9224
- );
9225
- return null;
9226
- }
9227
- const personalAfter = grantStatus(cli, personal);
9228
- if (personalBefore?.loggedIn === true && personalAfter?.loggedIn === false) {
9229
- say6(
9230
- ` your own Claude login was signed out by this one \u2014 this account allows one grant at a time. Run \`claude auth login\` to get it back, and connect the shared grant with --use-my-login instead.`
9231
- );
9232
- } else if (personalAfter?.loggedIn === true) {
9233
- say6(dim6(" your own Claude login still works \xB7 verified"));
9234
- }
9235
- say6(dim6(` grant ${read.kind === "file" ? read.path : `keychain ${read.service}`}`));
9236
- return read.secret;
9237
9259
  };
9238
9260
  var connectCommand = async (config, args) => {
9239
9261
  const [providerArg, ...flags] = args;
@@ -9252,13 +9274,14 @@ var connectCommand = async (config, args) => {
9252
9274
  }
9253
9275
  let secret;
9254
9276
  if (flags.includes("--from-stdin")) {
9255
- secret = fs16.readFileSync(0, "utf8").trim();
9277
+ secret = fs17.readFileSync(0, "utf8").trim();
9256
9278
  if (secret === "") return fail6("nothing on stdin");
9257
9279
  } else if (provider === "codex" && !flags.includes("--use-my-login")) {
9258
9280
  const grant = codexGrant({
9259
9281
  cli: codexCli(),
9260
- personalAuthJson: readIfExists(path17.join(personalCodexHome(), "auth.json")),
9261
- say: say6
9282
+ personalAuthJson: readIfExists(path18.join(personalCodexHome(), "auth.json")),
9283
+ say: say6,
9284
+ parent: mendCliHome()
9262
9285
  });
9263
9286
  if (grant.kind === "failed") return fail6(grant.reason);
9264
9287
  secret = grant.secret;
@@ -9306,14 +9329,14 @@ var takeFlagValue4 = (args, flag) => {
9306
9329
  return at !== -1 && args[at + 1] !== void 0 ? String(args[at + 1]) : null;
9307
9330
  };
9308
9331
  var saveCliConfig = (next) => {
9309
- fs16.mkdirSync(path17.dirname(CONFIG_PATH), { recursive: true, mode: 448 });
9310
- fs16.writeFileSync(
9332
+ fs17.mkdirSync(path18.dirname(CONFIG_PATH), { recursive: true, mode: 448 });
9333
+ fs17.writeFileSync(
9311
9334
  CONFIG_PATH,
9312
9335
  `${JSON.stringify({ url: next.url, token: next.token, deviceId: next.deviceId }, null, 2)}
9313
9336
  `,
9314
9337
  { mode: 384 }
9315
9338
  );
9316
- fs16.chmodSync(CONFIG_PATH, 384);
9339
+ fs17.chmodSync(CONFIG_PATH, 384);
9317
9340
  };
9318
9341
  var login = async (config, args) => {
9319
9342
  await loginCommand(args, {
@@ -9326,7 +9349,7 @@ var login = async (config, args) => {
9326
9349
  });
9327
9350
  };
9328
9351
  var logout = async (config) => {
9329
- if (!fs16.existsSync(CONFIG_PATH) && config.token === null) {
9352
+ if (!fs17.existsSync(CONFIG_PATH) && config.token === null) {
9330
9353
  say6(dim6("nothing saved \u2014 already signed out"));
9331
9354
  return;
9332
9355
  }
@@ -9379,8 +9402,8 @@ var uninstallCommand = async (config, args) => {
9379
9402
  const runtime = {
9380
9403
  server,
9381
9404
  cliHome: mendCliHome(),
9382
- sshConfigFile: path17.join(os11.homedir(), ".ssh", "config"),
9383
- signedIn: config.token === null || !fs16.existsSync(CONFIG_PATH) ? null : { url: config.url, deviceId: config.deviceId },
9405
+ sshConfigFile: path18.join(os11.homedir(), ".ssh", "config"),
9406
+ signedIn: config.token === null || !fs17.existsSync(CONFIG_PATH) ? null : { url: config.url, deviceId: config.deviceId },
9384
9407
  revokeDevice: async () => {
9385
9408
  if (config.deviceId === null) return "no device id saved";
9386
9409
  try {
@@ -9621,10 +9644,10 @@ var envLoad = async (config, args) => {
9621
9644
  const positional = args.filter(
9622
9645
  (arg, i) => !arg.startsWith("--") && args[i - 1] !== "--project" && !consumed.has(i)
9623
9646
  );
9624
- const file = path17.resolve(positional[0] ?? ".env");
9647
+ const file = path18.resolve(positional[0] ?? ".env");
9625
9648
  let contents;
9626
9649
  try {
9627
- contents = fs16.readFileSync(file, "utf8");
9650
+ contents = fs17.readFileSync(file, "utf8");
9628
9651
  } catch {
9629
9652
  return fail6(`cannot read ${file} \u2014 pass a path: mend env load path/to/.env`);
9630
9653
  }
@@ -9640,10 +9663,10 @@ var envLoad = async (config, args) => {
9640
9663
  { contents, allSecret, secretNames }
9641
9664
  );
9642
9665
  if (report.loaded.length === 0 && report.rejected.length === 0 && report.malformedLines.length === 0) {
9643
- say6(dim6(`${path17.basename(file)} has no variables`));
9666
+ say6(dim6(`${path18.basename(file)} has no variables`));
9644
9667
  return;
9645
9668
  }
9646
- say6(`${green6("\u2713")} loaded ${path17.basename(file)} into ${project2.name}`);
9669
+ say6(`${green6("\u2713")} loaded ${path18.basename(file)} into ${project2.name}`);
9647
9670
  for (const line of formatLoadReport(report, { dim: dim6, warn: amber2 })) say6(line);
9648
9671
  const plaintextUrls = report.loaded.filter(
9649
9672
  (entry) => entry.lane === "configuration" && /_(URL|URI|DSN)$/.test(entry.name)
@@ -9834,7 +9857,7 @@ var skillsList = async (config, args) => {
9834
9857
  };
9835
9858
  var skillsPush = async (config, args) => {
9836
9859
  const dirFlag = takeFlagValue4(args, "--dir");
9837
- const root = dirFlag === null ? path17.join(os11.homedir(), DEFAULT_SKILLS_DIR) : path17.resolve(dirFlag);
9860
+ const root = dirFlag === null ? path18.join(os11.homedir(), DEFAULT_SKILLS_DIR) : path18.resolve(dirFlag);
9838
9861
  const scanned = scanSkillLibrary(root);
9839
9862
  if ("error" in scanned) return fail6(scanned.error);
9840
9863
  for (const note of scanned.notes) say6(dim6(` ${note.skill}: ${note.message}`));
@@ -10590,15 +10613,16 @@ var manCommand = (words) => {
10590
10613
  }
10591
10614
  const version = cliVersion();
10592
10615
  const page = doc === null ? renderManIndex(version) : renderManPage(doc, version);
10593
- const file = path17.join(os11.tmpdir(), `mend-man-${process.pid}-${manFileName(doc)}`);
10594
- fs16.writeFileSync(file, page);
10616
+ const file = path18.join(os11.tmpdir(), `mend-man-${process.pid}-${manFileName(doc)}`);
10617
+ fs17.writeFileSync(file, page);
10595
10618
  const result = spawnSync6("man", ["-l", file], { stdio: "inherit" });
10596
- fs16.rmSync(file, { force: true });
10619
+ fs17.rmSync(file, { force: true });
10597
10620
  if (result.error !== void 0 || result.status !== 0) {
10598
10621
  say6(doc === null ? renderIndex() : renderCommand(doc));
10599
10622
  }
10600
10623
  };
10601
10624
  var main = async () => {
10625
+ useHttp1();
10602
10626
  const [command, ...rest] = process.argv.slice(2);
10603
10627
  const ownArgs = rest.slice(0, rest.indexOf("--") === -1 ? rest.length : rest.indexOf("--"));
10604
10628
  if (command !== void 0 && command !== "help" && ownArgs.some((a) => a === "--help" || a === "-h")) {