@mtreeai/msapling-cli 2.3.6-beta.3 → 2.3.6-beta.4

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 (3) hide show
  1. package/dist/index.js +823 -474
  2. package/package.json +5 -6
  3. package/LICENSE +0 -24
package/dist/index.js CHANGED
@@ -657,6 +657,7 @@ import { resolve as resolve2, normalize as normalize2, relative as relative2, is
657
657
  import { writeFile, readFile as readFile2, mkdir } from "fs/promises";
658
658
  import { existsSync as existsSync2 } from "fs";
659
659
  import { homedir } from "os";
660
+ import { randomBytes } from "crypto";
660
661
  var MAX_CONTENT_BYTES, WriteFileTool;
661
662
  var init_WriteFileTool = __esm({
662
663
  "../core/src/tools/WriteFileTool.ts"() {
@@ -732,7 +733,9 @@ var init_WriteFileTool = __esm({
732
733
  if (existsSync2(resolvedTarget)) {
733
734
  const existingContent = await readFile2(resolvedTarget, "utf8");
734
735
  const filename = resolvedTarget.split(/[\\/]/).pop() ?? "file";
735
- const backupPath = join2(homedir(), ".msapling", "backups", `${filename}.${Date.now()}.bak`);
736
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
737
+ const suffix = randomBytes(4).toString("hex");
738
+ const backupPath = join2(homedir(), ".msapling", "backups", `${filename}.backup-${stamp}-${suffix}.bak`);
736
739
  await mkdir(join2(homedir(), ".msapling", "backups"), { recursive: true });
737
740
  await writeFile(backupPath, existingContent, "utf8");
738
741
  backedUpTo = backupPath;
@@ -1028,7 +1031,7 @@ var init_RunCommandTool = __esm({
1028
1031
  this.activeCommands++;
1029
1032
  return;
1030
1033
  }
1031
- return new Promise((resolve17) => this.queue.push(resolve17));
1034
+ return new Promise((resolve18) => this.queue.push(resolve18));
1032
1035
  }
1033
1036
  static releaseLock() {
1034
1037
  if (this.queue.length > 0) {
@@ -1107,9 +1110,9 @@ var init_RunCommandTool = __esm({
1107
1110
  const chunks = { stdout: [], stderr: [] };
1108
1111
  proc.stdout?.on("data", (chunk) => chunks.stdout.push(chunk));
1109
1112
  proc.stderr?.on("data", (chunk) => chunks.stderr.push(chunk));
1110
- const exitCode = await new Promise((resolve17) => {
1111
- proc.on("exit", (code) => resolve17(code ?? 1));
1112
- proc.on("error", () => resolve17(1));
1113
+ const exitCode = await new Promise((resolve18) => {
1114
+ proc.on("exit", (code) => resolve18(code ?? 1));
1115
+ proc.on("error", () => resolve18(1));
1113
1116
  });
1114
1117
  const stdout = Buffer.concat(chunks.stdout).toString("utf-8");
1115
1118
  const stderr = Buffer.concat(chunks.stderr).toString("utf-8");
@@ -1220,9 +1223,9 @@ var init_src2 = __esm({
1220
1223
  const messages = this.parser.parse(value);
1221
1224
  for (const msg of messages) {
1222
1225
  if (msg.id !== void 0 && this.pendingRequests.has(Number(msg.id))) {
1223
- const resolve17 = this.pendingRequests.get(Number(msg.id));
1224
- if (resolve17) {
1225
- resolve17(msg.result || msg.error);
1226
+ const resolve18 = this.pendingRequests.get(Number(msg.id));
1227
+ if (resolve18) {
1228
+ resolve18(msg.result || msg.error);
1226
1229
  this.pendingRequests.delete(Number(msg.id));
1227
1230
  }
1228
1231
  }
@@ -1237,8 +1240,8 @@ var init_src2 = __esm({
1237
1240
  const message = `Content-Length: ${Buffer.byteLength(content, "utf8")}\r
1238
1241
  \r
1239
1242
  ${content}`;
1240
- return new Promise((resolve17) => {
1241
- this.pendingRequests.set(id, resolve17);
1243
+ return new Promise((resolve18) => {
1244
+ this.pendingRequests.set(id, resolve18);
1242
1245
  this.process.stdin.write(message);
1243
1246
  this.process.stdin.flush();
1244
1247
  });
@@ -1370,9 +1373,9 @@ var init_SubShellTool = __esm({
1370
1373
  }
1371
1374
  throw e;
1372
1375
  }
1373
- await new Promise((resolve17) => {
1374
- proc.on("exit", () => resolve17());
1375
- proc.on("error", () => resolve17());
1376
+ await new Promise((resolve18) => {
1377
+ proc.on("exit", () => resolve18());
1378
+ proc.on("error", () => resolve18());
1376
1379
  });
1377
1380
  return { content: `Successfully launched separate window for ${args2.worker_id}` };
1378
1381
  }
@@ -1455,13 +1458,13 @@ async function findRg() {
1455
1458
  const candidates = ["rg", "C:\\Program Files\\ripgrep\\rg.exe"];
1456
1459
  for (const bin of candidates) {
1457
1460
  try {
1458
- const exited = await new Promise((resolve17) => {
1461
+ const exited = await new Promise((resolve18) => {
1459
1462
  try {
1460
1463
  const p = spawn4(bin, ["--version"], { stdio: ["ignore", "pipe", "pipe"] });
1461
- p.on("error", () => resolve17(null));
1462
- p.on("exit", (code) => resolve17(code));
1464
+ p.on("error", () => resolve18(null));
1465
+ p.on("exit", (code) => resolve18(code));
1463
1466
  } catch {
1464
- resolve17(null);
1467
+ resolve18(null);
1465
1468
  }
1466
1469
  });
1467
1470
  if (exited === 0) return bin;
@@ -1471,7 +1474,7 @@ async function findRg() {
1471
1474
  return null;
1472
1475
  }
1473
1476
  function runRg(bin, args2) {
1474
- return new Promise((resolve17) => {
1477
+ return new Promise((resolve18) => {
1475
1478
  const p = spawn4(bin, args2, { stdio: ["ignore", "pipe", "pipe"] });
1476
1479
  let stdout = "";
1477
1480
  let stderr = "";
@@ -1482,10 +1485,10 @@ function runRg(bin, args2) {
1482
1485
  stderr += d.toString("utf8");
1483
1486
  });
1484
1487
  p.on("error", (e) => {
1485
- resolve17({ stdout, stderr: stderr + (e?.message ?? ""), exitCode: -1 });
1488
+ resolve18({ stdout, stderr: stderr + (e?.message ?? ""), exitCode: -1 });
1486
1489
  });
1487
1490
  p.on("exit", (code) => {
1488
- resolve17({ stdout, stderr, exitCode: code });
1491
+ resolve18({ stdout, stderr, exitCode: code });
1489
1492
  });
1490
1493
  });
1491
1494
  }
@@ -2037,6 +2040,7 @@ import { resolve as resolve6, normalize as normalize5, relative as relative6, is
2037
2040
  import { readFile as readFile4, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
2038
2041
  import { existsSync as existsSync5 } from "fs";
2039
2042
  import { homedir as homedir2 } from "os";
2043
+ import { randomBytes as randomBytes2 } from "crypto";
2040
2044
  var PatchFileTool;
2041
2045
  var init_PatchFileTool = __esm({
2042
2046
  "../core/src/tools/PatchFileTool.ts"() {
@@ -2143,7 +2147,9 @@ File preview (first 200 chars): ${JSON.stringify(preview)}`,
2143
2147
  let backedUpTo = null;
2144
2148
  try {
2145
2149
  const filename = resolvedTarget.split(/[\\/]/).pop() ?? "file";
2146
- const backupPath = join6(homedir2(), ".msapling", "backups", `${filename}.${Date.now()}.bak`);
2150
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
2151
+ const suffix = randomBytes2(4).toString("hex");
2152
+ const backupPath = join6(homedir2(), ".msapling", "backups", `${filename}.backup-${stamp}-${suffix}.bak`);
2147
2153
  await mkdir2(join6(homedir2(), ".msapling", "backups"), { recursive: true });
2148
2154
  await writeFile2(backupPath, originalContent, "utf8");
2149
2155
  backedUpTo = backupPath;
@@ -2734,12 +2740,12 @@ Command: ${command}`,
2734
2740
  proc.stdout?.on("data", (chunk) => chunks.stdout.push(chunk));
2735
2741
  proc.stderr?.on("data", (chunk) => chunks.stderr.push(chunk));
2736
2742
  const timeoutPromise = new Promise(
2737
- (resolve17) => setTimeout(() => resolve17("timeout"), timeoutMs)
2743
+ (resolve18) => setTimeout(() => resolve18("timeout"), timeoutMs)
2738
2744
  );
2739
2745
  const processPromise = (async () => {
2740
- const exitCode2 = await new Promise((resolve17) => {
2741
- proc.on("exit", (code) => resolve17(code ?? 1));
2742
- proc.on("error", () => resolve17(1));
2746
+ const exitCode2 = await new Promise((resolve18) => {
2747
+ proc.on("exit", (code) => resolve18(code ?? 1));
2748
+ proc.on("error", () => resolve18(1));
2743
2749
  });
2744
2750
  const stdout2 = Buffer.concat(chunks.stdout).toString("utf-8");
2745
2751
  const stderr2 = Buffer.concat(chunks.stderr).toString("utf-8");
@@ -3003,6 +3009,7 @@ import { resolve as resolve9, normalize as normalize8, relative as relative9, is
3003
3009
  import { readFile as readFile6, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
3004
3010
  import { existsSync as existsSync7 } from "fs";
3005
3011
  import { homedir as homedir3 } from "os";
3012
+ import { randomBytes as randomBytes3 } from "crypto";
3006
3013
  function normaliseSource(source) {
3007
3014
  if (source === "") return [];
3008
3015
  const lines = source.split("\n");
@@ -3179,11 +3186,13 @@ var init_NotebookEditTool = __esm({
3179
3186
  let backedUpTo = null;
3180
3187
  try {
3181
3188
  const filename = absPath.split(/[\\/]/).pop() ?? "notebook.ipynb";
3189
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
3190
+ const suffix = randomBytes3(4).toString("hex");
3182
3191
  const backupPath = join8(
3183
3192
  homedir3(),
3184
3193
  ".msapling",
3185
3194
  "backups",
3186
- `${filename}.${Date.now()}.bak`
3195
+ `${filename}.backup-${stamp}-${suffix}.bak`
3187
3196
  );
3188
3197
  await mkdir3(join8(homedir3(), ".msapling", "backups"), { recursive: true });
3189
3198
  await writeFile3(backupPath, rawJson, "utf8");
@@ -3246,7 +3255,7 @@ var init_NotebookEditTool = __esm({
3246
3255
  File: ${absPath}`;
3247
3256
  if (backedUpTo) {
3248
3257
  summary += `
3249
- Pre-edit content backed up to: ${backedUpTo}`;
3258
+ Backup: ${backedUpTo}`;
3250
3259
  }
3251
3260
  return { content: summary };
3252
3261
  }
@@ -3259,6 +3268,7 @@ import { resolve as resolve10, normalize as normalize9, relative as relative10,
3259
3268
  import { readFile as readFile7, writeFile as writeFile4, mkdir as mkdir4 } from "fs/promises";
3260
3269
  import { existsSync as existsSync8 } from "fs";
3261
3270
  import { homedir as homedir4 } from "os";
3271
+ import { randomBytes as randomBytes4 } from "crypto";
3262
3272
  var MAX_EDITS, MultiEditFileTool;
3263
3273
  var init_MultiEditFileTool = __esm({
3264
3274
  "../core/src/tools/MultiEditFileTool.ts"() {
@@ -3419,11 +3429,13 @@ No changes were written (atomic: all-or-nothing).`,
3419
3429
  let backedUpTo = null;
3420
3430
  try {
3421
3431
  const filename = resolvedTarget.split(/[\\/]/).pop() ?? "file";
3432
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
3433
+ const suffix = randomBytes4(4).toString("hex");
3422
3434
  const backupPath = join9(
3423
3435
  homedir4(),
3424
3436
  ".msapling",
3425
3437
  "backups",
3426
- `${filename}.${Date.now()}.bak`
3438
+ `${filename}.backup-${stamp}-${suffix}.bak`
3427
3439
  );
3428
3440
  await mkdir4(join9(homedir4(), ".msapling", "backups"), { recursive: true });
3429
3441
  await writeFile4(backupPath, originalContent, "utf8");
@@ -3456,6 +3468,7 @@ Pre-edit content backed up to: ${backedUpTo}`;
3456
3468
  import { resolve as resolve11, normalize as normalize10, relative as relative11, isAbsolute as isAbsolute11, dirname } from "path";
3457
3469
  import { rename, mkdir as mkdir5, copyFile, rm, stat as stat2, readdir as readdir2 } from "fs/promises";
3458
3470
  import { existsSync as existsSync9, statSync as statSync3 } from "fs";
3471
+ import { randomBytes as randomBytes5 } from "crypto";
3459
3472
  function containedPath(p, root) {
3460
3473
  const abs = isAbsolute11(p) ? normalize10(p) : resolve11(root, p.trim());
3461
3474
  const rel = relative11(root, abs);
@@ -3480,16 +3493,18 @@ async function copyDir(src, dst) {
3480
3493
  async function backupFile(absPath) {
3481
3494
  try {
3482
3495
  const { readFile: readFile23, writeFile: writeFile12, mkdir: mkdir9 } = await import("fs/promises");
3483
- const { homedir: homedir15 } = await import("os");
3484
- const { join: join27 } = await import("path");
3496
+ const { homedir: homedir16 } = await import("os");
3497
+ const { join: join29 } = await import("path");
3485
3498
  const filename = absPath.split(/[\\/]/).pop() ?? "file";
3486
- const backupPath = join27(
3487
- homedir15(),
3499
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
3500
+ const suffix = randomBytes5(4).toString("hex");
3501
+ const backupPath = join29(
3502
+ homedir16(),
3488
3503
  ".msapling",
3489
3504
  "backups",
3490
- `${filename}.${Date.now()}.bak`
3505
+ `${filename}.backup-${stamp}-${suffix}.bak`
3491
3506
  );
3492
- await mkdir9(join27(homedir15(), ".msapling", "backups"), { recursive: true });
3507
+ await mkdir9(join29(homedir16(), ".msapling", "backups"), { recursive: true });
3493
3508
  const content = await readFile23(absPath, "utf8");
3494
3509
  await writeFile12(backupPath, content, "utf8");
3495
3510
  return backupPath;
@@ -3641,8 +3656,9 @@ Overwritten destination backed up to: ${backedUpTo}`;
3641
3656
  });
3642
3657
 
3643
3658
  // ../core/src/tools/DeleteFileTool.ts
3644
- import { resolve as resolve12, normalize as normalize11, relative as relative12, isAbsolute as isAbsolute12, join as join10 } from "path";
3659
+ import { resolve as resolve12, normalize as normalize11, relative as relative12, isAbsolute as isAbsolute12, join as join11 } from "path";
3645
3660
  import { rm as rm2, stat as stat3 } from "fs/promises";
3661
+ import { randomBytes as randomBytes6 } from "crypto";
3646
3662
  var DeleteFileTool;
3647
3663
  var init_DeleteFileTool = __esm({
3648
3664
  "../core/src/tools/DeleteFileTool.ts"() {
@@ -3716,11 +3732,13 @@ var init_DeleteFileTool = __esm({
3716
3732
  if (isFile) {
3717
3733
  try {
3718
3734
  const { readFile: readFile23, writeFile: writeFile12, mkdir: mkdir9 } = await import("fs/promises");
3719
- const { homedir: homedir15 } = await import("os");
3735
+ const { homedir: homedir16 } = await import("os");
3720
3736
  const existingContent = await readFile23(abs, "utf8");
3721
3737
  const filename = abs.split(/[\\/]/).pop() ?? "file";
3722
- const backupPath = join10(homedir15(), ".msapling", "backups", `${filename}.${Date.now()}.bak`);
3723
- await mkdir9(join10(homedir15(), ".msapling", "backups"), { recursive: true });
3738
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
3739
+ const suffix = randomBytes6(4).toString("hex");
3740
+ const backupPath = join11(homedir16(), ".msapling", "backups", `${filename}.backup-${stamp}-${suffix}.bak`);
3741
+ await mkdir9(join11(homedir16(), ".msapling", "backups"), { recursive: true });
3724
3742
  await writeFile12(backupPath, existingContent, "utf8");
3725
3743
  backedUpTo = backupPath;
3726
3744
  } catch {
@@ -3744,7 +3762,7 @@ var init_DeleteFileTool = __esm({
3744
3762
  let summary = `Deleted ${kind}: ${abs}`;
3745
3763
  if (backedUpTo) {
3746
3764
  summary += `
3747
- Content backed up to: ${backedUpTo}`;
3765
+ Backup: ${backedUpTo}`;
3748
3766
  }
3749
3767
  return { content: summary };
3750
3768
  }
@@ -3991,10 +4009,10 @@ var init_Voice = __esm({
3991
4009
  `;
3992
4010
  try {
3993
4011
  if (process.platform === "win32") {
3994
- await new Promise((resolve17, reject) => {
4012
+ await new Promise((resolve18, reject) => {
3995
4013
  try {
3996
4014
  const proc = spawn6("powershell", ["-Command", psCommand]);
3997
- proc.on("exit", () => resolve17());
4015
+ proc.on("exit", () => resolve18());
3998
4016
  proc.on("error", reject);
3999
4017
  } catch (e) {
4000
4018
  reject(e);
@@ -4108,7 +4126,7 @@ function matches(entry, ctx) {
4108
4126
  async function runOne(entry, ctx) {
4109
4127
  const timeoutMs = entry.timeoutMs ?? DEFAULT_TIMEOUT_MS3;
4110
4128
  const command = entry.command;
4111
- return new Promise((resolve17) => {
4129
+ return new Promise((resolve18) => {
4112
4130
  const isWindows = process.platform === "win32";
4113
4131
  const child = spawn7(isWindows ? "cmd.exe" : "sh", isWindows ? ["/c", command] : ["-c", command], {
4114
4132
  cwd: ctx.cwd ?? process.cwd(),
@@ -4123,7 +4141,7 @@ async function runOne(entry, ctx) {
4123
4141
  settled = true;
4124
4142
  clearTimeout(killer);
4125
4143
  const blocked = !!entry.blocking && (exitCode === null || exitCode !== 0);
4126
- resolve17({ command, exitCode, stdout, stderr, timedOut, blocked });
4144
+ resolve18({ command, exitCode, stdout, stderr, timedOut, blocked });
4127
4145
  };
4128
4146
  const killer = setTimeout(() => {
4129
4147
  timedOut = true;
@@ -4519,7 +4537,7 @@ var init_Safety = __esm({
4519
4537
 
4520
4538
  // ../core/src/ProjectConfig.ts
4521
4539
  import { homedir as homedir5 } from "os";
4522
- import { join as join11, dirname as dirname2, parse as parsePath } from "path";
4540
+ import { join as join12, dirname as dirname2, parse as parsePath } from "path";
4523
4541
  import { existsSync as existsSync10 } from "fs";
4524
4542
  import { readFile as readFile9 } from "fs/promises";
4525
4543
  async function readIfExists(path2) {
@@ -4533,7 +4551,7 @@ async function readIfExists(path2) {
4533
4551
  }
4534
4552
  async function findInDir(dir) {
4535
4553
  for (const filename of FILENAMES) {
4536
- const path2 = join11(dir, filename);
4554
+ const path2 = join12(dir, filename);
4537
4555
  const content = await readIfExists(path2);
4538
4556
  if (content !== null) {
4539
4557
  return { path: path2, filename, content };
@@ -4558,7 +4576,7 @@ async function findProjectConfig(start) {
4558
4576
  async function findUserConfig() {
4559
4577
  const home = homedir5();
4560
4578
  if (!home) return null;
4561
- const userDir = join11(home, ".msapling");
4579
+ const userDir = join12(home, ".msapling");
4562
4580
  return findInDir(userDir);
4563
4581
  }
4564
4582
  function buildCombined(user, project) {
@@ -4968,8 +4986,8 @@ var init_Mutex = __esm({
4968
4986
  */
4969
4987
  acquire() {
4970
4988
  let release2;
4971
- const next = new Promise((resolve17) => {
4972
- release2 = resolve17;
4989
+ const next = new Promise((resolve18) => {
4990
+ release2 = resolve18;
4973
4991
  });
4974
4992
  const entry = this._queue.then(() => release2);
4975
4993
  this._queue = this._queue.then(() => next);
@@ -4992,7 +5010,7 @@ var init_Mutex = __esm({
4992
5010
  });
4993
5011
 
4994
5012
  // ../core/src/TrustStore.ts
4995
- import { join as join12 } from "path";
5013
+ import { join as join13 } from "path";
4996
5014
  import { homedir as homedir6 } from "os";
4997
5015
  import { existsSync as existsSync11, mkdirSync } from "fs";
4998
5016
  import { readFile as readFile10, writeFile as writeFile5 } from "fs/promises";
@@ -5002,7 +5020,7 @@ var init_TrustStore = __esm({
5002
5020
  "use strict";
5003
5021
  init_esm_shims();
5004
5022
  init_Mutex();
5005
- USER_SETTINGS_PATH = join12(homedir6(), ".msapling", "settings.json");
5023
+ USER_SETTINGS_PATH = join13(homedir6(), ".msapling", "settings.json");
5006
5024
  TrustStore = class {
5007
5025
  /** Current in-memory set of trusted `tool:command` keys. */
5008
5026
  trusted = /* @__PURE__ */ new Set();
@@ -5032,7 +5050,7 @@ var init_TrustStore = __esm({
5032
5050
  * updating `trustedCommands`.
5033
5051
  */
5034
5052
  async writeSettings(settings) {
5035
- const dir = join12(homedir6(), ".msapling");
5053
+ const dir = join13(homedir6(), ".msapling");
5036
5054
  if (!existsSync11(dir)) mkdirSync(dir, { recursive: true });
5037
5055
  await writeFile5(this.settingsPath, JSON.stringify(settings, null, 2), "utf8");
5038
5056
  }
@@ -5112,7 +5130,7 @@ var require_polyfills = __commonJS({
5112
5130
  var constants = __require("constants");
5113
5131
  var origCwd = process.cwd;
5114
5132
  var cwd = null;
5115
- var platform2 = process.env.GRACEFUL_FS_PLATFORM || process.platform;
5133
+ var platform3 = process.env.GRACEFUL_FS_PLATFORM || process.platform;
5116
5134
  process.cwd = function() {
5117
5135
  if (!cwd)
5118
5136
  cwd = origCwd.call(process);
@@ -5132,54 +5150,54 @@ var require_polyfills = __commonJS({
5132
5150
  }
5133
5151
  var chdir;
5134
5152
  module.exports = patch;
5135
- function patch(fs2) {
5153
+ function patch(fs3) {
5136
5154
  if (constants.hasOwnProperty("O_SYMLINK") && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
5137
- patchLchmod(fs2);
5138
- }
5139
- if (!fs2.lutimes) {
5140
- patchLutimes(fs2);
5141
- }
5142
- fs2.chown = chownFix(fs2.chown);
5143
- fs2.fchown = chownFix(fs2.fchown);
5144
- fs2.lchown = chownFix(fs2.lchown);
5145
- fs2.chmod = chmodFix(fs2.chmod);
5146
- fs2.fchmod = chmodFix(fs2.fchmod);
5147
- fs2.lchmod = chmodFix(fs2.lchmod);
5148
- fs2.chownSync = chownFixSync(fs2.chownSync);
5149
- fs2.fchownSync = chownFixSync(fs2.fchownSync);
5150
- fs2.lchownSync = chownFixSync(fs2.lchownSync);
5151
- fs2.chmodSync = chmodFixSync(fs2.chmodSync);
5152
- fs2.fchmodSync = chmodFixSync(fs2.fchmodSync);
5153
- fs2.lchmodSync = chmodFixSync(fs2.lchmodSync);
5154
- fs2.stat = statFix(fs2.stat);
5155
- fs2.fstat = statFix(fs2.fstat);
5156
- fs2.lstat = statFix(fs2.lstat);
5157
- fs2.statSync = statFixSync(fs2.statSync);
5158
- fs2.fstatSync = statFixSync(fs2.fstatSync);
5159
- fs2.lstatSync = statFixSync(fs2.lstatSync);
5160
- if (fs2.chmod && !fs2.lchmod) {
5161
- fs2.lchmod = function(path2, mode, cb) {
5155
+ patchLchmod(fs3);
5156
+ }
5157
+ if (!fs3.lutimes) {
5158
+ patchLutimes(fs3);
5159
+ }
5160
+ fs3.chown = chownFix(fs3.chown);
5161
+ fs3.fchown = chownFix(fs3.fchown);
5162
+ fs3.lchown = chownFix(fs3.lchown);
5163
+ fs3.chmod = chmodFix(fs3.chmod);
5164
+ fs3.fchmod = chmodFix(fs3.fchmod);
5165
+ fs3.lchmod = chmodFix(fs3.lchmod);
5166
+ fs3.chownSync = chownFixSync(fs3.chownSync);
5167
+ fs3.fchownSync = chownFixSync(fs3.fchownSync);
5168
+ fs3.lchownSync = chownFixSync(fs3.lchownSync);
5169
+ fs3.chmodSync = chmodFixSync(fs3.chmodSync);
5170
+ fs3.fchmodSync = chmodFixSync(fs3.fchmodSync);
5171
+ fs3.lchmodSync = chmodFixSync(fs3.lchmodSync);
5172
+ fs3.stat = statFix(fs3.stat);
5173
+ fs3.fstat = statFix(fs3.fstat);
5174
+ fs3.lstat = statFix(fs3.lstat);
5175
+ fs3.statSync = statFixSync(fs3.statSync);
5176
+ fs3.fstatSync = statFixSync(fs3.fstatSync);
5177
+ fs3.lstatSync = statFixSync(fs3.lstatSync);
5178
+ if (fs3.chmod && !fs3.lchmod) {
5179
+ fs3.lchmod = function(path2, mode, cb) {
5162
5180
  if (cb) process.nextTick(cb);
5163
5181
  };
5164
- fs2.lchmodSync = function() {
5182
+ fs3.lchmodSync = function() {
5165
5183
  };
5166
5184
  }
5167
- if (fs2.chown && !fs2.lchown) {
5168
- fs2.lchown = function(path2, uid, gid, cb) {
5185
+ if (fs3.chown && !fs3.lchown) {
5186
+ fs3.lchown = function(path2, uid, gid, cb) {
5169
5187
  if (cb) process.nextTick(cb);
5170
5188
  };
5171
- fs2.lchownSync = function() {
5189
+ fs3.lchownSync = function() {
5172
5190
  };
5173
5191
  }
5174
- if (platform2 === "win32") {
5175
- fs2.rename = typeof fs2.rename !== "function" ? fs2.rename : (function(fs$rename) {
5192
+ if (platform3 === "win32") {
5193
+ fs3.rename = typeof fs3.rename !== "function" ? fs3.rename : (function(fs$rename) {
5176
5194
  function rename2(from, to, cb) {
5177
5195
  var start = Date.now();
5178
5196
  var backoff = 0;
5179
5197
  fs$rename(from, to, function CB(er) {
5180
5198
  if (er && (er.code === "EACCES" || er.code === "EPERM" || er.code === "EBUSY") && Date.now() - start < 6e4) {
5181
5199
  setTimeout(function() {
5182
- fs2.stat(to, function(stater, st) {
5200
+ fs3.stat(to, function(stater, st) {
5183
5201
  if (stater && stater.code === "ENOENT")
5184
5202
  fs$rename(from, to, CB);
5185
5203
  else
@@ -5195,9 +5213,9 @@ var require_polyfills = __commonJS({
5195
5213
  }
5196
5214
  if (Object.setPrototypeOf) Object.setPrototypeOf(rename2, fs$rename);
5197
5215
  return rename2;
5198
- })(fs2.rename);
5216
+ })(fs3.rename);
5199
5217
  }
5200
- fs2.read = typeof fs2.read !== "function" ? fs2.read : (function(fs$read) {
5218
+ fs3.read = typeof fs3.read !== "function" ? fs3.read : (function(fs$read) {
5201
5219
  function read(fd, buffer, offset, length, position, callback_) {
5202
5220
  var callback;
5203
5221
  if (callback_ && typeof callback_ === "function") {
@@ -5205,22 +5223,22 @@ var require_polyfills = __commonJS({
5205
5223
  callback = function(er, _, __) {
5206
5224
  if (er && er.code === "EAGAIN" && eagCounter < 10) {
5207
5225
  eagCounter++;
5208
- return fs$read.call(fs2, fd, buffer, offset, length, position, callback);
5226
+ return fs$read.call(fs3, fd, buffer, offset, length, position, callback);
5209
5227
  }
5210
5228
  callback_.apply(this, arguments);
5211
5229
  };
5212
5230
  }
5213
- return fs$read.call(fs2, fd, buffer, offset, length, position, callback);
5231
+ return fs$read.call(fs3, fd, buffer, offset, length, position, callback);
5214
5232
  }
5215
5233
  if (Object.setPrototypeOf) Object.setPrototypeOf(read, fs$read);
5216
5234
  return read;
5217
- })(fs2.read);
5218
- fs2.readSync = typeof fs2.readSync !== "function" ? fs2.readSync : /* @__PURE__ */ (function(fs$readSync) {
5235
+ })(fs3.read);
5236
+ fs3.readSync = typeof fs3.readSync !== "function" ? fs3.readSync : /* @__PURE__ */ (function(fs$readSync) {
5219
5237
  return function(fd, buffer, offset, length, position) {
5220
5238
  var eagCounter = 0;
5221
5239
  while (true) {
5222
5240
  try {
5223
- return fs$readSync.call(fs2, fd, buffer, offset, length, position);
5241
+ return fs$readSync.call(fs3, fd, buffer, offset, length, position);
5224
5242
  } catch (er) {
5225
5243
  if (er.code === "EAGAIN" && eagCounter < 10) {
5226
5244
  eagCounter++;
@@ -5230,10 +5248,10 @@ var require_polyfills = __commonJS({
5230
5248
  }
5231
5249
  }
5232
5250
  };
5233
- })(fs2.readSync);
5234
- function patchLchmod(fs3) {
5235
- fs3.lchmod = function(path2, mode, callback) {
5236
- fs3.open(
5251
+ })(fs3.readSync);
5252
+ function patchLchmod(fs4) {
5253
+ fs4.lchmod = function(path2, mode, callback) {
5254
+ fs4.open(
5237
5255
  path2,
5238
5256
  constants.O_WRONLY | constants.O_SYMLINK,
5239
5257
  mode,
@@ -5242,80 +5260,80 @@ var require_polyfills = __commonJS({
5242
5260
  if (callback) callback(err);
5243
5261
  return;
5244
5262
  }
5245
- fs3.fchmod(fd, mode, function(err2) {
5246
- fs3.close(fd, function(err22) {
5263
+ fs4.fchmod(fd, mode, function(err2) {
5264
+ fs4.close(fd, function(err22) {
5247
5265
  if (callback) callback(err2 || err22);
5248
5266
  });
5249
5267
  });
5250
5268
  }
5251
5269
  );
5252
5270
  };
5253
- fs3.lchmodSync = function(path2, mode) {
5254
- var fd = fs3.openSync(path2, constants.O_WRONLY | constants.O_SYMLINK, mode);
5271
+ fs4.lchmodSync = function(path2, mode) {
5272
+ var fd = fs4.openSync(path2, constants.O_WRONLY | constants.O_SYMLINK, mode);
5255
5273
  var threw = true;
5256
5274
  var ret;
5257
5275
  try {
5258
- ret = fs3.fchmodSync(fd, mode);
5276
+ ret = fs4.fchmodSync(fd, mode);
5259
5277
  threw = false;
5260
5278
  } finally {
5261
5279
  if (threw) {
5262
5280
  try {
5263
- fs3.closeSync(fd);
5281
+ fs4.closeSync(fd);
5264
5282
  } catch (er) {
5265
5283
  }
5266
5284
  } else {
5267
- fs3.closeSync(fd);
5285
+ fs4.closeSync(fd);
5268
5286
  }
5269
5287
  }
5270
5288
  return ret;
5271
5289
  };
5272
5290
  }
5273
- function patchLutimes(fs3) {
5274
- if (constants.hasOwnProperty("O_SYMLINK") && fs3.futimes) {
5275
- fs3.lutimes = function(path2, at, mt, cb) {
5276
- fs3.open(path2, constants.O_SYMLINK, function(er, fd) {
5291
+ function patchLutimes(fs4) {
5292
+ if (constants.hasOwnProperty("O_SYMLINK") && fs4.futimes) {
5293
+ fs4.lutimes = function(path2, at, mt, cb) {
5294
+ fs4.open(path2, constants.O_SYMLINK, function(er, fd) {
5277
5295
  if (er) {
5278
5296
  if (cb) cb(er);
5279
5297
  return;
5280
5298
  }
5281
- fs3.futimes(fd, at, mt, function(er2) {
5282
- fs3.close(fd, function(er22) {
5299
+ fs4.futimes(fd, at, mt, function(er2) {
5300
+ fs4.close(fd, function(er22) {
5283
5301
  if (cb) cb(er2 || er22);
5284
5302
  });
5285
5303
  });
5286
5304
  });
5287
5305
  };
5288
- fs3.lutimesSync = function(path2, at, mt) {
5289
- var fd = fs3.openSync(path2, constants.O_SYMLINK);
5306
+ fs4.lutimesSync = function(path2, at, mt) {
5307
+ var fd = fs4.openSync(path2, constants.O_SYMLINK);
5290
5308
  var ret;
5291
5309
  var threw = true;
5292
5310
  try {
5293
- ret = fs3.futimesSync(fd, at, mt);
5311
+ ret = fs4.futimesSync(fd, at, mt);
5294
5312
  threw = false;
5295
5313
  } finally {
5296
5314
  if (threw) {
5297
5315
  try {
5298
- fs3.closeSync(fd);
5316
+ fs4.closeSync(fd);
5299
5317
  } catch (er) {
5300
5318
  }
5301
5319
  } else {
5302
- fs3.closeSync(fd);
5320
+ fs4.closeSync(fd);
5303
5321
  }
5304
5322
  }
5305
5323
  return ret;
5306
5324
  };
5307
- } else if (fs3.futimes) {
5308
- fs3.lutimes = function(_a, _b, _c, cb) {
5325
+ } else if (fs4.futimes) {
5326
+ fs4.lutimes = function(_a, _b, _c, cb) {
5309
5327
  if (cb) process.nextTick(cb);
5310
5328
  };
5311
- fs3.lutimesSync = function() {
5329
+ fs4.lutimesSync = function() {
5312
5330
  };
5313
5331
  }
5314
5332
  }
5315
5333
  function chmodFix(orig) {
5316
5334
  if (!orig) return orig;
5317
5335
  return function(target, mode, cb) {
5318
- return orig.call(fs2, target, mode, function(er) {
5336
+ return orig.call(fs3, target, mode, function(er) {
5319
5337
  if (chownErOk(er)) er = null;
5320
5338
  if (cb) cb.apply(this, arguments);
5321
5339
  });
@@ -5325,7 +5343,7 @@ var require_polyfills = __commonJS({
5325
5343
  if (!orig) return orig;
5326
5344
  return function(target, mode) {
5327
5345
  try {
5328
- return orig.call(fs2, target, mode);
5346
+ return orig.call(fs3, target, mode);
5329
5347
  } catch (er) {
5330
5348
  if (!chownErOk(er)) throw er;
5331
5349
  }
@@ -5334,7 +5352,7 @@ var require_polyfills = __commonJS({
5334
5352
  function chownFix(orig) {
5335
5353
  if (!orig) return orig;
5336
5354
  return function(target, uid, gid, cb) {
5337
- return orig.call(fs2, target, uid, gid, function(er) {
5355
+ return orig.call(fs3, target, uid, gid, function(er) {
5338
5356
  if (chownErOk(er)) er = null;
5339
5357
  if (cb) cb.apply(this, arguments);
5340
5358
  });
@@ -5344,7 +5362,7 @@ var require_polyfills = __commonJS({
5344
5362
  if (!orig) return orig;
5345
5363
  return function(target, uid, gid) {
5346
5364
  try {
5347
- return orig.call(fs2, target, uid, gid);
5365
+ return orig.call(fs3, target, uid, gid);
5348
5366
  } catch (er) {
5349
5367
  if (!chownErOk(er)) throw er;
5350
5368
  }
@@ -5364,13 +5382,13 @@ var require_polyfills = __commonJS({
5364
5382
  }
5365
5383
  if (cb) cb.apply(this, arguments);
5366
5384
  }
5367
- return options ? orig.call(fs2, target, options, callback) : orig.call(fs2, target, callback);
5385
+ return options ? orig.call(fs3, target, options, callback) : orig.call(fs3, target, callback);
5368
5386
  };
5369
5387
  }
5370
5388
  function statFixSync(orig) {
5371
5389
  if (!orig) return orig;
5372
5390
  return function(target, options) {
5373
- var stats = options ? orig.call(fs2, target, options) : orig.call(fs2, target);
5391
+ var stats = options ? orig.call(fs3, target, options) : orig.call(fs3, target);
5374
5392
  if (stats) {
5375
5393
  if (stats.uid < 0) stats.uid += 4294967296;
5376
5394
  if (stats.gid < 0) stats.gid += 4294967296;
@@ -5401,7 +5419,7 @@ var require_legacy_streams = __commonJS({
5401
5419
  init_esm_shims();
5402
5420
  var Stream = __require("stream").Stream;
5403
5421
  module.exports = legacy;
5404
- function legacy(fs2) {
5422
+ function legacy(fs3) {
5405
5423
  return {
5406
5424
  ReadStream,
5407
5425
  WriteStream
@@ -5444,7 +5462,7 @@ var require_legacy_streams = __commonJS({
5444
5462
  });
5445
5463
  return;
5446
5464
  }
5447
- fs2.open(this.path, this.flags, this.mode, function(err, fd) {
5465
+ fs3.open(this.path, this.flags, this.mode, function(err, fd) {
5448
5466
  if (err) {
5449
5467
  self.emit("error", err);
5450
5468
  self.readable = false;
@@ -5483,7 +5501,7 @@ var require_legacy_streams = __commonJS({
5483
5501
  this.busy = false;
5484
5502
  this._queue = [];
5485
5503
  if (this.fd === null) {
5486
- this._open = fs2.open;
5504
+ this._open = fs3.open;
5487
5505
  this._queue.push([this._open, this.path, this.flags, this.mode, void 0]);
5488
5506
  this.flush();
5489
5507
  }
@@ -5521,7 +5539,7 @@ var require_graceful_fs = __commonJS({
5521
5539
  "../../node_modules/.bun/graceful-fs@4.2.11/node_modules/graceful-fs/graceful-fs.js"(exports, module) {
5522
5540
  "use strict";
5523
5541
  init_esm_shims();
5524
- var fs2 = __require("fs");
5542
+ var fs3 = __require("fs");
5525
5543
  var polyfills = require_polyfills();
5526
5544
  var legacy = require_legacy_streams();
5527
5545
  var clone = require_clone();
@@ -5553,12 +5571,12 @@ var require_graceful_fs = __commonJS({
5553
5571
  m = "GFS4: " + m.split(/\n/).join("\nGFS4: ");
5554
5572
  console.error(m);
5555
5573
  };
5556
- if (!fs2[gracefulQueue]) {
5574
+ if (!fs3[gracefulQueue]) {
5557
5575
  queue = global[gracefulQueue] || [];
5558
- publishQueue(fs2, queue);
5559
- fs2.close = (function(fs$close) {
5576
+ publishQueue(fs3, queue);
5577
+ fs3.close = (function(fs$close) {
5560
5578
  function close(fd, cb) {
5561
- return fs$close.call(fs2, fd, function(err) {
5579
+ return fs$close.call(fs3, fd, function(err) {
5562
5580
  if (!err) {
5563
5581
  resetQueue();
5564
5582
  }
@@ -5570,40 +5588,40 @@ var require_graceful_fs = __commonJS({
5570
5588
  value: fs$close
5571
5589
  });
5572
5590
  return close;
5573
- })(fs2.close);
5574
- fs2.closeSync = (function(fs$closeSync) {
5591
+ })(fs3.close);
5592
+ fs3.closeSync = (function(fs$closeSync) {
5575
5593
  function closeSync(fd) {
5576
- fs$closeSync.apply(fs2, arguments);
5594
+ fs$closeSync.apply(fs3, arguments);
5577
5595
  resetQueue();
5578
5596
  }
5579
5597
  Object.defineProperty(closeSync, previousSymbol, {
5580
5598
  value: fs$closeSync
5581
5599
  });
5582
5600
  return closeSync;
5583
- })(fs2.closeSync);
5601
+ })(fs3.closeSync);
5584
5602
  if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || "")) {
5585
5603
  process.on("exit", function() {
5586
- debug(fs2[gracefulQueue]);
5587
- __require("assert").equal(fs2[gracefulQueue].length, 0);
5604
+ debug(fs3[gracefulQueue]);
5605
+ __require("assert").equal(fs3[gracefulQueue].length, 0);
5588
5606
  });
5589
5607
  }
5590
5608
  }
5591
5609
  var queue;
5592
5610
  if (!global[gracefulQueue]) {
5593
- publishQueue(global, fs2[gracefulQueue]);
5594
- }
5595
- module.exports = patch(clone(fs2));
5596
- if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs2.__patched) {
5597
- module.exports = patch(fs2);
5598
- fs2.__patched = true;
5599
- }
5600
- function patch(fs3) {
5601
- polyfills(fs3);
5602
- fs3.gracefulify = patch;
5603
- fs3.createReadStream = createReadStream;
5604
- fs3.createWriteStream = createWriteStream;
5605
- var fs$readFile = fs3.readFile;
5606
- fs3.readFile = readFile23;
5611
+ publishQueue(global, fs3[gracefulQueue]);
5612
+ }
5613
+ module.exports = patch(clone(fs3));
5614
+ if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs3.__patched) {
5615
+ module.exports = patch(fs3);
5616
+ fs3.__patched = true;
5617
+ }
5618
+ function patch(fs4) {
5619
+ polyfills(fs4);
5620
+ fs4.gracefulify = patch;
5621
+ fs4.createReadStream = createReadStream;
5622
+ fs4.createWriteStream = createWriteStream;
5623
+ var fs$readFile = fs4.readFile;
5624
+ fs4.readFile = readFile23;
5607
5625
  function readFile23(path2, options, cb) {
5608
5626
  if (typeof options === "function")
5609
5627
  cb = options, options = null;
@@ -5619,8 +5637,8 @@ var require_graceful_fs = __commonJS({
5619
5637
  });
5620
5638
  }
5621
5639
  }
5622
- var fs$writeFile = fs3.writeFile;
5623
- fs3.writeFile = writeFile12;
5640
+ var fs$writeFile = fs4.writeFile;
5641
+ fs4.writeFile = writeFile12;
5624
5642
  function writeFile12(path2, data, options, cb) {
5625
5643
  if (typeof options === "function")
5626
5644
  cb = options, options = null;
@@ -5636,9 +5654,9 @@ var require_graceful_fs = __commonJS({
5636
5654
  });
5637
5655
  }
5638
5656
  }
5639
- var fs$appendFile = fs3.appendFile;
5657
+ var fs$appendFile = fs4.appendFile;
5640
5658
  if (fs$appendFile)
5641
- fs3.appendFile = appendFile;
5659
+ fs4.appendFile = appendFile;
5642
5660
  function appendFile(path2, data, options, cb) {
5643
5661
  if (typeof options === "function")
5644
5662
  cb = options, options = null;
@@ -5654,9 +5672,9 @@ var require_graceful_fs = __commonJS({
5654
5672
  });
5655
5673
  }
5656
5674
  }
5657
- var fs$copyFile = fs3.copyFile;
5675
+ var fs$copyFile = fs4.copyFile;
5658
5676
  if (fs$copyFile)
5659
- fs3.copyFile = copyFile2;
5677
+ fs4.copyFile = copyFile2;
5660
5678
  function copyFile2(src, dest, flags, cb) {
5661
5679
  if (typeof flags === "function") {
5662
5680
  cb = flags;
@@ -5674,10 +5692,10 @@ var require_graceful_fs = __commonJS({
5674
5692
  });
5675
5693
  }
5676
5694
  }
5677
- var fs$readdir = fs3.readdir;
5678
- fs3.readdir = readdir4;
5695
+ var fs$readdir = fs4.readdir;
5696
+ fs4.readdir = readdir5;
5679
5697
  var noReaddirOptionVersions = /^v[0-5]\./;
5680
- function readdir4(path2, options, cb) {
5698
+ function readdir5(path2, options, cb) {
5681
5699
  if (typeof options === "function")
5682
5700
  cb = options, options = null;
5683
5701
  var go$readdir = noReaddirOptionVersions.test(process.version) ? function go$readdir2(path3, options2, cb2, startTime) {
@@ -5716,21 +5734,21 @@ var require_graceful_fs = __commonJS({
5716
5734
  }
5717
5735
  }
5718
5736
  if (process.version.substr(0, 4) === "v0.8") {
5719
- var legStreams = legacy(fs3);
5737
+ var legStreams = legacy(fs4);
5720
5738
  ReadStream = legStreams.ReadStream;
5721
5739
  WriteStream = legStreams.WriteStream;
5722
5740
  }
5723
- var fs$ReadStream = fs3.ReadStream;
5741
+ var fs$ReadStream = fs4.ReadStream;
5724
5742
  if (fs$ReadStream) {
5725
5743
  ReadStream.prototype = Object.create(fs$ReadStream.prototype);
5726
5744
  ReadStream.prototype.open = ReadStream$open;
5727
5745
  }
5728
- var fs$WriteStream = fs3.WriteStream;
5746
+ var fs$WriteStream = fs4.WriteStream;
5729
5747
  if (fs$WriteStream) {
5730
5748
  WriteStream.prototype = Object.create(fs$WriteStream.prototype);
5731
5749
  WriteStream.prototype.open = WriteStream$open;
5732
5750
  }
5733
- Object.defineProperty(fs3, "ReadStream", {
5751
+ Object.defineProperty(fs4, "ReadStream", {
5734
5752
  get: function() {
5735
5753
  return ReadStream;
5736
5754
  },
@@ -5740,7 +5758,7 @@ var require_graceful_fs = __commonJS({
5740
5758
  enumerable: true,
5741
5759
  configurable: true
5742
5760
  });
5743
- Object.defineProperty(fs3, "WriteStream", {
5761
+ Object.defineProperty(fs4, "WriteStream", {
5744
5762
  get: function() {
5745
5763
  return WriteStream;
5746
5764
  },
@@ -5751,7 +5769,7 @@ var require_graceful_fs = __commonJS({
5751
5769
  configurable: true
5752
5770
  });
5753
5771
  var FileReadStream = ReadStream;
5754
- Object.defineProperty(fs3, "FileReadStream", {
5772
+ Object.defineProperty(fs4, "FileReadStream", {
5755
5773
  get: function() {
5756
5774
  return FileReadStream;
5757
5775
  },
@@ -5762,7 +5780,7 @@ var require_graceful_fs = __commonJS({
5762
5780
  configurable: true
5763
5781
  });
5764
5782
  var FileWriteStream = WriteStream;
5765
- Object.defineProperty(fs3, "FileWriteStream", {
5783
+ Object.defineProperty(fs4, "FileWriteStream", {
5766
5784
  get: function() {
5767
5785
  return FileWriteStream;
5768
5786
  },
@@ -5811,13 +5829,13 @@ var require_graceful_fs = __commonJS({
5811
5829
  });
5812
5830
  }
5813
5831
  function createReadStream(path2, options) {
5814
- return new fs3.ReadStream(path2, options);
5832
+ return new fs4.ReadStream(path2, options);
5815
5833
  }
5816
5834
  function createWriteStream(path2, options) {
5817
- return new fs3.WriteStream(path2, options);
5835
+ return new fs4.WriteStream(path2, options);
5818
5836
  }
5819
- var fs$open = fs3.open;
5820
- fs3.open = open;
5837
+ var fs$open = fs4.open;
5838
+ fs4.open = open;
5821
5839
  function open(path2, flags, mode, cb) {
5822
5840
  if (typeof mode === "function")
5823
5841
  cb = mode, mode = null;
@@ -5833,20 +5851,20 @@ var require_graceful_fs = __commonJS({
5833
5851
  });
5834
5852
  }
5835
5853
  }
5836
- return fs3;
5854
+ return fs4;
5837
5855
  }
5838
5856
  function enqueue(elem) {
5839
5857
  debug("ENQUEUE", elem[0].name, elem[1]);
5840
- fs2[gracefulQueue].push(elem);
5858
+ fs3[gracefulQueue].push(elem);
5841
5859
  retry();
5842
5860
  }
5843
5861
  var retryTimer;
5844
5862
  function resetQueue() {
5845
5863
  var now = Date.now();
5846
- for (var i = 0; i < fs2[gracefulQueue].length; ++i) {
5847
- if (fs2[gracefulQueue][i].length > 2) {
5848
- fs2[gracefulQueue][i][3] = now;
5849
- fs2[gracefulQueue][i][4] = now;
5864
+ for (var i = 0; i < fs3[gracefulQueue].length; ++i) {
5865
+ if (fs3[gracefulQueue][i].length > 2) {
5866
+ fs3[gracefulQueue][i][3] = now;
5867
+ fs3[gracefulQueue][i][4] = now;
5850
5868
  }
5851
5869
  }
5852
5870
  retry();
@@ -5854,9 +5872,9 @@ var require_graceful_fs = __commonJS({
5854
5872
  function retry() {
5855
5873
  clearTimeout(retryTimer);
5856
5874
  retryTimer = void 0;
5857
- if (fs2[gracefulQueue].length === 0)
5875
+ if (fs3[gracefulQueue].length === 0)
5858
5876
  return;
5859
- var elem = fs2[gracefulQueue].shift();
5877
+ var elem = fs3[gracefulQueue].shift();
5860
5878
  var fn = elem[0];
5861
5879
  var args2 = elem[1];
5862
5880
  var err = elem[2];
@@ -5878,7 +5896,7 @@ var require_graceful_fs = __commonJS({
5878
5896
  debug("RETRY", fn.name, args2);
5879
5897
  fn.apply(null, args2.concat([startTime]));
5880
5898
  } else {
5881
- fs2[gracefulQueue].push(elem);
5899
+ fs3[gracefulQueue].push(elem);
5882
5900
  }
5883
5901
  }
5884
5902
  if (retryTimer === void 0) {
@@ -6324,10 +6342,10 @@ var require_mtime_precision = __commonJS({
6324
6342
  "use strict";
6325
6343
  init_esm_shims();
6326
6344
  var cacheSymbol = /* @__PURE__ */ Symbol();
6327
- function probe(file, fs2, callback) {
6328
- const cachedPrecision = fs2[cacheSymbol];
6345
+ function probe(file, fs3, callback) {
6346
+ const cachedPrecision = fs3[cacheSymbol];
6329
6347
  if (cachedPrecision) {
6330
- return fs2.stat(file, (err, stat5) => {
6348
+ return fs3.stat(file, (err, stat5) => {
6331
6349
  if (err) {
6332
6350
  return callback(err);
6333
6351
  }
@@ -6335,16 +6353,16 @@ var require_mtime_precision = __commonJS({
6335
6353
  });
6336
6354
  }
6337
6355
  const mtime = new Date(Math.ceil(Date.now() / 1e3) * 1e3 + 5);
6338
- fs2.utimes(file, mtime, mtime, (err) => {
6356
+ fs3.utimes(file, mtime, mtime, (err) => {
6339
6357
  if (err) {
6340
6358
  return callback(err);
6341
6359
  }
6342
- fs2.stat(file, (err2, stat5) => {
6360
+ fs3.stat(file, (err2, stat5) => {
6343
6361
  if (err2) {
6344
6362
  return callback(err2);
6345
6363
  }
6346
6364
  const precision = stat5.mtime.getTime() % 1e3 === 0 ? "s" : "ms";
6347
- Object.defineProperty(fs2, cacheSymbol, { value: precision });
6365
+ Object.defineProperty(fs3, cacheSymbol, { value: precision });
6348
6366
  callback(null, stat5.mtime, precision);
6349
6367
  });
6350
6368
  });
@@ -6367,7 +6385,7 @@ var require_lockfile = __commonJS({
6367
6385
  "use strict";
6368
6386
  init_esm_shims();
6369
6387
  var path2 = __require("path");
6370
- var fs2 = require_graceful_fs();
6388
+ var fs3 = require_graceful_fs();
6371
6389
  var retry = require_retry2();
6372
6390
  var onExit = require_signal_exit();
6373
6391
  var mtimePrecision = require_mtime_precision();
@@ -6498,7 +6516,7 @@ var require_lockfile = __commonJS({
6498
6516
  update: null,
6499
6517
  realpath: true,
6500
6518
  retries: 0,
6501
- fs: fs2,
6519
+ fs: fs3,
6502
6520
  onCompromised: (err) => {
6503
6521
  throw err;
6504
6522
  },
@@ -6542,7 +6560,7 @@ var require_lockfile = __commonJS({
6542
6560
  }
6543
6561
  function unlock2(file, options, callback) {
6544
6562
  options = {
6545
- fs: fs2,
6563
+ fs: fs3,
6546
6564
  realpath: true,
6547
6565
  ...options
6548
6566
  };
@@ -6564,7 +6582,7 @@ var require_lockfile = __commonJS({
6564
6582
  options = {
6565
6583
  stale: 1e4,
6566
6584
  realpath: true,
6567
- fs: fs2,
6585
+ fs: fs3,
6568
6586
  ...options
6569
6587
  };
6570
6588
  options.stale = Math.max(options.stale || 0, 2e3);
@@ -6604,16 +6622,16 @@ var require_adapter = __commonJS({
6604
6622
  "../../node_modules/.bun/proper-lockfile@4.1.2/node_modules/proper-lockfile/lib/adapter.js"(exports, module) {
6605
6623
  "use strict";
6606
6624
  init_esm_shims();
6607
- var fs2 = require_graceful_fs();
6608
- function createSyncFs(fs3) {
6625
+ var fs3 = require_graceful_fs();
6626
+ function createSyncFs(fs4) {
6609
6627
  const methods = ["mkdir", "realpath", "stat", "rmdir", "utimes"];
6610
- const newFs = { ...fs3 };
6628
+ const newFs = { ...fs4 };
6611
6629
  methods.forEach((method) => {
6612
6630
  newFs[method] = (...args2) => {
6613
6631
  const callback = args2.pop();
6614
6632
  let ret;
6615
6633
  try {
6616
- ret = fs3[`${method}Sync`](...args2);
6634
+ ret = fs4[`${method}Sync`](...args2);
6617
6635
  } catch (err) {
6618
6636
  return callback(err);
6619
6637
  }
@@ -6623,12 +6641,12 @@ var require_adapter = __commonJS({
6623
6641
  return newFs;
6624
6642
  }
6625
6643
  function toPromise(method) {
6626
- return (...args2) => new Promise((resolve17, reject) => {
6644
+ return (...args2) => new Promise((resolve18, reject) => {
6627
6645
  args2.push((err, result) => {
6628
6646
  if (err) {
6629
6647
  reject(err);
6630
6648
  } else {
6631
- resolve17(result);
6649
+ resolve18(result);
6632
6650
  }
6633
6651
  });
6634
6652
  method(...args2);
@@ -6651,7 +6669,7 @@ var require_adapter = __commonJS({
6651
6669
  }
6652
6670
  function toSyncOptions(options) {
6653
6671
  options = { ...options };
6654
- options.fs = createSyncFs(options.fs || fs2);
6672
+ options.fs = createSyncFs(options.fs || fs3);
6655
6673
  if (typeof options.retries === "number" && options.retries > 0 || options.retries && typeof options.retries.retries === "number" && options.retries.retries > 0) {
6656
6674
  throw Object.assign(new Error("Cannot use retries with the sync api"), { code: "ESYNC" });
6657
6675
  }
@@ -6763,142 +6781,12 @@ var require_keytar2 = __commonJS({
6763
6781
  }
6764
6782
  });
6765
6783
 
6766
- // ../core/src/Settings.ts
6767
- import { homedir as homedir7 } from "os";
6768
- import { join as join13 } from "path";
6769
- import { existsSync as existsSync12 } from "fs";
6770
- import * as fs from "fs";
6771
- import { readFile as readFile11 } from "fs/promises";
6772
- function ensureConfigDir(p) {
6773
- try {
6774
- fs.mkdirSync(p, { recursive: true, mode: 448 });
6775
- } catch (e) {
6776
- if (e.code === "EEXIST" || e.code === "ENOTDIR") {
6777
- const stat5 = fs.statSync(p);
6778
- if (!stat5.isDirectory()) {
6779
- fs.renameSync(p, `${p}.broken-${Date.now()}`);
6780
- fs.mkdirSync(p, { recursive: true, mode: 448 });
6781
- }
6782
- } else {
6783
- throw e;
6784
- }
6785
- }
6786
- }
6787
- async function readJson(path2) {
6788
- try {
6789
- if (!existsSync12(path2)) return null;
6790
- const text = await readFile11(path2, "utf8");
6791
- if (!text.trim()) return null;
6792
- return JSON.parse(text);
6793
- } catch {
6794
- return null;
6795
- }
6796
- }
6797
- function fromEnv(env) {
6798
- const out = {};
6799
- for (const [envKey, settingKey] of Object.entries(ENV_MAP)) {
6800
- const raw = env[envKey];
6801
- if (raw === void 0) continue;
6802
- if (settingKey === "maxTokens") {
6803
- const n = Number.parseInt(raw, 10);
6804
- if (Number.isFinite(n)) out.maxTokens = n;
6805
- } else if (settingKey === "temperature") {
6806
- const n = Number.parseFloat(raw);
6807
- if (Number.isFinite(n)) out.temperature = n;
6808
- } else if (settingKey === "ollamaEnabled" || settingKey === "telemetryEnabled") {
6809
- out[settingKey] = raw === "true" || raw === "1";
6810
- } else if (settingKey === "defaultMode") {
6811
- const v = raw;
6812
- if (["default", "plan", "acceptEdits", "bypassPermissions"].includes(v)) {
6813
- out.defaultMode = v;
6814
- }
6815
- } else {
6816
- out[settingKey] = raw;
6817
- }
6818
- }
6819
- return out;
6820
- }
6821
- function mergeSettings(base, override) {
6822
- const out = { ...base, ...override };
6823
- if (override.mcpServers) {
6824
- out.mcpServers = { ...base.mcpServers, ...override.mcpServers };
6825
- }
6826
- if (override.hooks) {
6827
- out.hooks = { ...base.hooks, ...override.hooks };
6828
- }
6829
- if (override.trustedCommands) {
6830
- const seen = /* @__PURE__ */ new Set();
6831
- const merged = [];
6832
- for (const c of [...base.trustedCommands, ...override.trustedCommands]) {
6833
- if (!seen.has(c)) {
6834
- seen.add(c);
6835
- merged.push(c);
6836
- }
6837
- }
6838
- out.trustedCommands = merged;
6839
- }
6840
- return out;
6841
- }
6842
- async function loadSettings(cwd = process.cwd(), env = process.env, warn) {
6843
- const sources = [];
6844
- const userPath = join13(homedir7() || ".", ".msapling", "settings.json");
6845
- const projectPath = join13(cwd, ".msapling", "settings.json");
6846
- const [user, project] = await Promise.all([readJson(userPath), readJson(projectPath)]);
6847
- if (user) sources.push(userPath);
6848
- if (project) sources.push(projectPath);
6849
- let settings = DEFAULT_SETTINGS;
6850
- if (user) settings = mergeSettings(settings, user);
6851
- if (project) settings = mergeSettings(settings, project);
6852
- settings = mergeSettings(settings, fromEnv(env));
6853
- if (settings.temperature < 0 || settings.temperature > 2) {
6854
- warn?.(`Settings: temperature out of range (${settings.temperature}); clamping to 0.7`);
6855
- settings = { ...settings, temperature: 0.7 };
6856
- }
6857
- if (settings.maxTokens <= 0) {
6858
- warn?.(`Settings: maxTokens must be positive; resetting to ${DEFAULT_SETTINGS.maxTokens}`);
6859
- settings = { ...settings, maxTokens: DEFAULT_SETTINGS.maxTokens };
6860
- }
6861
- return { settings, sources };
6862
- }
6863
- var DEFAULT_SETTINGS, ENV_MAP;
6864
- var init_Settings = __esm({
6865
- "../core/src/Settings.ts"() {
6866
- "use strict";
6867
- init_esm_shims();
6868
- DEFAULT_SETTINGS = {
6869
- apiUrl: "https://api.msapling.com",
6870
- defaultModel: "google/gemini-2.0-flash-001",
6871
- defaultMode: "default",
6872
- theme: "diamond",
6873
- maxTokens: 4096,
6874
- temperature: 0.7,
6875
- ollamaEnabled: true,
6876
- ollamaBaseUrl: "http://127.0.0.1:11434",
6877
- telemetryEnabled: true,
6878
- mcpServers: {},
6879
- hooks: {},
6880
- trustedCommands: [],
6881
- shellEscapeEnabled: true
6882
- };
6883
- ENV_MAP = {
6884
- MSAPLING_API_URL: "apiUrl",
6885
- MSAPLING_DEFAULT_MODEL: "defaultModel",
6886
- MSAPLING_DEFAULT_MODE: "defaultMode",
6887
- MSAPLING_THEME: "theme",
6888
- MSAPLING_MAX_TOKENS: "maxTokens",
6889
- MSAPLING_TEMPERATURE: "temperature",
6890
- MSAPLING_OLLAMA_ENABLED: "ollamaEnabled",
6891
- MSAPLING_OLLAMA_BASE_URL: "ollamaBaseUrl",
6892
- MSAPLING_TELEMETRY_ENABLED: "telemetryEnabled"
6893
- };
6894
- }
6895
- });
6896
-
6897
6784
  // ../core/src/Storage.ts
6898
6785
  import { join as join14 } from "path";
6899
- import { homedir as homedir8 } from "os";
6900
- import { chmodSync, existsSync as existsSync13, renameSync as renameSync2, unlinkSync } from "fs";
6901
- import { writeFile as writeFile6, readFile as readFile12 } from "fs/promises";
6786
+ import { homedir as homedir7 } from "os";
6787
+ import { chmodSync, existsSync as existsSync12, renameSync, unlinkSync } from "fs";
6788
+ import { mkdir as mkdir6, writeFile as writeFile6, readFile as readFile11 } from "fs/promises";
6789
+ import { randomBytes as randomBytes7 } from "crypto";
6902
6790
  var lockfile, keytar, StorageManager;
6903
6791
  var init_Storage = __esm({
6904
6792
  "../core/src/Storage.ts"() {
@@ -6907,7 +6795,6 @@ var init_Storage = __esm({
6907
6795
  init_Mutex();
6908
6796
  lockfile = __toESM(require_proper_lockfile(), 1);
6909
6797
  keytar = __toESM(require_keytar2(), 1);
6910
- init_Settings();
6911
6798
  StorageManager = class {
6912
6799
  baseDir;
6913
6800
  /**
@@ -6926,16 +6813,16 @@ var init_Storage = __esm({
6926
6813
  */
6927
6814
  _ready;
6928
6815
  constructor() {
6929
- this.baseDir = join14(homedir8(), ".msapling");
6816
+ this.baseDir = join14(homedir7(), ".msapling");
6930
6817
  this._ready = this.ensureDirs();
6931
6818
  }
6932
6819
  async ensureDirs() {
6933
6820
  try {
6934
- ensureConfigDir(this.baseDir);
6935
- const subdirs = ["history", "backups", "cache", "vault", "mcp"];
6821
+ await mkdir6(this.baseDir, { recursive: true });
6822
+ const subdirs = ["history", "backups", "cache", "vault"];
6936
6823
  for (const sub of subdirs) {
6937
6824
  const path2 = join14(this.baseDir, sub);
6938
- ensureConfigDir(path2);
6825
+ await mkdir6(path2, { recursive: true });
6939
6826
  }
6940
6827
  if (process.platform !== "win32") {
6941
6828
  chmodSync(this.baseDir, 448);
@@ -6956,7 +6843,7 @@ var init_Storage = __esm({
6956
6843
  try {
6957
6844
  await keytar.setPassword(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT, token);
6958
6845
  try {
6959
- if (existsSync13(filePath)) {
6846
+ if (existsSync12(filePath)) {
6960
6847
  unlinkSync(filePath);
6961
6848
  }
6962
6849
  } catch {
@@ -6981,8 +6868,8 @@ var init_Storage = __esm({
6981
6868
  } catch (e) {
6982
6869
  console.debug(`Keychain unavailable (${e instanceof Error ? e.message : String(e)}), falling back to file storage`);
6983
6870
  }
6984
- if (existsSync13(filePath)) {
6985
- const text = await readFile12(filePath, "utf8");
6871
+ if (existsSync12(filePath)) {
6872
+ const text = await readFile11(filePath, "utf8");
6986
6873
  return text.trim();
6987
6874
  }
6988
6875
  return null;
@@ -7000,9 +6887,9 @@ var init_Storage = __esm({
7000
6887
  console.debug(`Keychain unavailable for deletion (${e instanceof Error ? e.message : String(e)})`);
7001
6888
  }
7002
6889
  try {
7003
- if (existsSync13(filePath)) {
7004
- const fs2 = await import("fs/promises");
7005
- await fs2.unlink(filePath);
6890
+ if (existsSync12(filePath)) {
6891
+ const fs3 = await import("fs/promises");
6892
+ await fs3.unlink(filePath);
7006
6893
  }
7007
6894
  } catch (e) {
7008
6895
  console.warn(`Failed to delete token file: ${e}`);
@@ -7016,26 +6903,23 @@ var init_Storage = __esm({
7016
6903
  * This ensures:
7017
6904
  * 1. Only one process writes at a time (file lock)
7018
6905
  * 2. Partial writes don't corrupt the JSON (atomic rename)
7019
- *
7020
- * CLI-LSTAT-HISTORY-01: Pass realpath:false so lockfile never calls lstat on a
7021
- * path that may not exist yet (first run before any history has been written).
7022
6906
  */
7023
6907
  async saveHistory(history) {
7024
6908
  const path2 = join14(this.baseDir, "history", "shell_history.json");
7025
6909
  let release2;
7026
6910
  try {
7027
- release2 = await lockfile.lock(path2, { retries: 5, retryWait: 50, realpath: false });
6911
+ release2 = await lockfile.lock(path2, { retries: 5, retryWait: 50 });
7028
6912
  await this.historyMutex.run(async () => {
7029
6913
  const tmpPath = `${path2}.tmp`;
7030
6914
  const content = JSON.stringify(history, null, 2);
7031
6915
  await writeFile6(tmpPath, content, "utf8");
7032
6916
  try {
7033
- renameSync2(tmpPath, path2);
6917
+ renameSync(tmpPath, path2);
7034
6918
  } catch (e) {
7035
6919
  try {
7036
- if (existsSync13(tmpPath)) {
7037
- const fs2 = await import("fs/promises");
7038
- await fs2.unlink(tmpPath);
6920
+ if (existsSync12(tmpPath)) {
6921
+ const fs3 = await import("fs/promises");
6922
+ await fs3.unlink(tmpPath);
7039
6923
  }
7040
6924
  } catch {
7041
6925
  }
@@ -7045,7 +6929,7 @@ var init_Storage = __esm({
7045
6929
  } finally {
7046
6930
  if (release2) {
7047
6931
  try {
7048
- await lockfile.unlock(path2, { skipStale: true, realpath: false });
6932
+ await lockfile.unlock(path2, { skipStale: true });
7049
6933
  } catch (e) {
7050
6934
  console.warn(`Failed to unlock history file: ${e}`);
7051
6935
  }
@@ -7056,41 +6940,23 @@ var init_Storage = __esm({
7056
6940
  * SYNC-01: Serialised history read with file-based locking.
7057
6941
  * Reads are gated behind the file lock so a read that overlaps with an
7058
6942
  * in-progress write from another process always sees a complete, valid JSON.
7059
- *
7060
- * CLI-LSTAT-HISTORY-01: Short-circuit before locking when the file is absent
7061
- * so lockfile never calls lstat/realpath on a nonexistent path (ENOENT crash
7062
- * on fresh install). Corrupt JSON is caught, backed up, and treated as empty
7063
- * rather than propagating a parse error.
7064
6943
  */
7065
6944
  async loadHistory() {
7066
6945
  const path2 = join14(this.baseDir, "history", "shell_history.json");
7067
- if (!existsSync13(path2)) {
7068
- return [];
7069
- }
7070
6946
  let release2;
7071
6947
  try {
7072
- release2 = await lockfile.lock(path2, { retries: 5, retryWait: 50, realpath: false });
7073
- return await this.historyMutex.run(async () => {
7074
- if (!existsSync13(path2)) {
7075
- return [];
7076
- }
7077
- const text = await readFile12(path2, "utf8");
7078
- try {
6948
+ release2 = await lockfile.lock(path2, { retries: 5, retryWait: 50 });
6949
+ return this.historyMutex.run(async () => {
6950
+ if (existsSync12(path2)) {
6951
+ const text = await readFile11(path2, "utf8");
7079
6952
  return JSON.parse(text);
7080
- } catch {
7081
- console.warn("[msapling] shell_history.json is corrupt; resetting to empty history.");
7082
- const backupPath = `${path2}.corrupt.${Date.now()}.bak`;
7083
- try {
7084
- renameSync2(path2, backupPath);
7085
- } catch {
7086
- }
7087
- return [];
7088
6953
  }
6954
+ return [];
7089
6955
  });
7090
6956
  } finally {
7091
6957
  if (release2) {
7092
6958
  try {
7093
- await lockfile.unlock(path2, { skipStale: true, realpath: false });
6959
+ await lockfile.unlock(path2, { skipStale: true });
7094
6960
  } catch (e) {
7095
6961
  console.warn(`Failed to unlock history file: ${e}`);
7096
6962
  }
@@ -7099,24 +6965,23 @@ var init_Storage = __esm({
7099
6965
  }
7100
6966
  /**
7101
6967
  * SYNC-01: Serialised permissions write with file-based locking.
7102
- * CLI-LSTAT-HISTORY-01: realpath:false prevents ENOENT lstat on first run.
7103
6968
  */
7104
6969
  async savePermissions(permissions) {
7105
6970
  const path2 = join14(this.baseDir, "vault", "permissions.json");
7106
6971
  let release2;
7107
6972
  try {
7108
- release2 = await lockfile.lock(path2, { retries: 5, retryWait: 50, realpath: false });
6973
+ release2 = await lockfile.lock(path2, { retries: 5, retryWait: 50 });
7109
6974
  await this.permissionsMutex.run(async () => {
7110
6975
  const tmpPath = `${path2}.tmp`;
7111
6976
  const content = JSON.stringify(permissions, null, 2);
7112
6977
  await writeFile6(tmpPath, content, "utf8");
7113
6978
  try {
7114
- renameSync2(tmpPath, path2);
6979
+ renameSync(tmpPath, path2);
7115
6980
  } catch (e) {
7116
6981
  try {
7117
- if (existsSync13(tmpPath)) {
7118
- const fs2 = await import("fs/promises");
7119
- await fs2.unlink(tmpPath);
6982
+ if (existsSync12(tmpPath)) {
6983
+ const fs3 = await import("fs/promises");
6984
+ await fs3.unlink(tmpPath);
7120
6985
  }
7121
6986
  } catch {
7122
6987
  }
@@ -7126,7 +6991,7 @@ var init_Storage = __esm({
7126
6991
  } finally {
7127
6992
  if (release2) {
7128
6993
  try {
7129
- await lockfile.unlock(path2, { skipStale: true, realpath: false });
6994
+ await lockfile.unlock(path2, { skipStale: true });
7130
6995
  } catch (e) {
7131
6996
  console.warn(`Failed to unlock permissions file: ${e}`);
7132
6997
  }
@@ -7135,28 +7000,23 @@ var init_Storage = __esm({
7135
7000
  }
7136
7001
  /**
7137
7002
  * SYNC-01: Serialised permissions read with file-based locking.
7138
- * CLI-LSTAT-HISTORY-01: Short-circuit on missing file; realpath:false avoids
7139
- * lstat on a path that may not exist yet on a fresh install.
7140
7003
  */
7141
7004
  async loadPermissions() {
7142
7005
  const path2 = join14(this.baseDir, "vault", "permissions.json");
7143
- if (!existsSync13(path2)) {
7144
- return { trustedCommands: [], trustedPaths: [] };
7145
- }
7146
7006
  let release2;
7147
7007
  try {
7148
- release2 = await lockfile.lock(path2, { retries: 5, retryWait: 50, realpath: false });
7149
- return await this.permissionsMutex.run(async () => {
7150
- if (!existsSync13(path2)) {
7151
- return { trustedCommands: [], trustedPaths: [] };
7008
+ release2 = await lockfile.lock(path2, { retries: 5, retryWait: 50 });
7009
+ return this.permissionsMutex.run(async () => {
7010
+ if (existsSync12(path2)) {
7011
+ const text = await readFile11(path2, "utf8");
7012
+ return JSON.parse(text);
7152
7013
  }
7153
- const text = await readFile12(path2, "utf8");
7154
- return JSON.parse(text);
7014
+ return { trustedCommands: [], trustedPaths: [] };
7155
7015
  });
7156
7016
  } finally {
7157
7017
  if (release2) {
7158
7018
  try {
7159
- await lockfile.unlock(path2, { skipStale: true, realpath: false });
7019
+ await lockfile.unlock(path2, { skipStale: true });
7160
7020
  } catch (e) {
7161
7021
  console.warn(`Failed to unlock permissions file: ${e}`);
7162
7022
  }
@@ -7167,11 +7027,14 @@ var init_Storage = __esm({
7167
7027
  * Backup a file before AI edit.
7168
7028
  * CLI-R11-STORAGE-03: backup artifacts are written with restrictive 0600
7169
7029
  * permissions so restored content is not readable by other OS users.
7030
+ * CLI-ARCH-NO-EPOCH-IN-KEYS-FU-01: uses ISO timestamp + random suffix
7031
+ * instead of epoch milliseconds for better traceability and collision avoidance.
7170
7032
  */
7171
7033
  async backup(filePath, content) {
7172
7034
  const filename = filePath.split("/").pop() || "file";
7173
- const timestamp = Date.now();
7174
- const backupPath = join14(this.baseDir, "backups", `${filename}.${timestamp}.bak`);
7035
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
7036
+ const suffix = randomBytes7(4).toString("hex");
7037
+ const backupPath = join14(this.baseDir, "backups", `${filename}.backup-${stamp}-${suffix}.bak`);
7175
7038
  await writeFile6(backupPath, content, "utf8");
7176
7039
  if (process.platform !== "win32") {
7177
7040
  chmodSync(backupPath, 384);
@@ -7182,6 +7045,137 @@ var init_Storage = __esm({
7182
7045
  }
7183
7046
  });
7184
7047
 
7048
+ // ../core/src/Settings.ts
7049
+ import { homedir as homedir8 } from "os";
7050
+ import { join as join15 } from "path";
7051
+ import { existsSync as existsSync13 } from "fs";
7052
+ import * as fs from "fs";
7053
+ import { readFile as readFile12 } from "fs/promises";
7054
+ function ensureConfigDir(p) {
7055
+ try {
7056
+ fs.mkdirSync(p, { recursive: true, mode: 448 });
7057
+ } catch (e) {
7058
+ if (e.code === "EEXIST" || e.code === "ENOTDIR") {
7059
+ const stat5 = fs.statSync(p);
7060
+ if (!stat5.isDirectory()) {
7061
+ fs.renameSync(p, `${p}.broken-${Date.now()}`);
7062
+ fs.mkdirSync(p, { recursive: true, mode: 448 });
7063
+ }
7064
+ } else {
7065
+ throw e;
7066
+ }
7067
+ }
7068
+ }
7069
+ async function readJson(path2) {
7070
+ try {
7071
+ if (!existsSync13(path2)) return null;
7072
+ const text = await readFile12(path2, "utf8");
7073
+ if (!text.trim()) return null;
7074
+ return JSON.parse(text);
7075
+ } catch {
7076
+ return null;
7077
+ }
7078
+ }
7079
+ function fromEnv(env) {
7080
+ const out = {};
7081
+ for (const [envKey, settingKey] of Object.entries(ENV_MAP)) {
7082
+ const raw = env[envKey];
7083
+ if (raw === void 0) continue;
7084
+ if (settingKey === "maxTokens") {
7085
+ const n = Number.parseInt(raw, 10);
7086
+ if (Number.isFinite(n)) out.maxTokens = n;
7087
+ } else if (settingKey === "temperature") {
7088
+ const n = Number.parseFloat(raw);
7089
+ if (Number.isFinite(n)) out.temperature = n;
7090
+ } else if (settingKey === "ollamaEnabled" || settingKey === "telemetryEnabled") {
7091
+ out[settingKey] = raw === "true" || raw === "1";
7092
+ } else if (settingKey === "defaultMode") {
7093
+ const v = raw;
7094
+ if (["default", "plan", "acceptEdits", "bypassPermissions"].includes(v)) {
7095
+ out.defaultMode = v;
7096
+ }
7097
+ } else {
7098
+ out[settingKey] = raw;
7099
+ }
7100
+ }
7101
+ return out;
7102
+ }
7103
+ function mergeSettings(base, override) {
7104
+ const out = { ...base, ...override };
7105
+ if (override.mcpServers) {
7106
+ out.mcpServers = { ...base.mcpServers, ...override.mcpServers };
7107
+ }
7108
+ if (override.hooks) {
7109
+ out.hooks = { ...base.hooks, ...override.hooks };
7110
+ }
7111
+ if (override.trustedCommands) {
7112
+ const seen = /* @__PURE__ */ new Set();
7113
+ const merged = [];
7114
+ for (const c of [...base.trustedCommands, ...override.trustedCommands]) {
7115
+ if (!seen.has(c)) {
7116
+ seen.add(c);
7117
+ merged.push(c);
7118
+ }
7119
+ }
7120
+ out.trustedCommands = merged;
7121
+ }
7122
+ return out;
7123
+ }
7124
+ async function loadSettings(cwd = process.cwd(), env = process.env, warn) {
7125
+ const sources = [];
7126
+ const userPath = join15(homedir8() || ".", ".msapling", "settings.json");
7127
+ const projectPath = join15(cwd, ".msapling", "settings.json");
7128
+ const [user, project] = await Promise.all([readJson(userPath), readJson(projectPath)]);
7129
+ if (user) sources.push(userPath);
7130
+ if (project) sources.push(projectPath);
7131
+ let settings = DEFAULT_SETTINGS;
7132
+ if (user) settings = mergeSettings(settings, user);
7133
+ if (project) settings = mergeSettings(settings, project);
7134
+ settings = mergeSettings(settings, fromEnv(env));
7135
+ if (settings.temperature < 0 || settings.temperature > 2) {
7136
+ warn?.(`Settings: temperature out of range (${settings.temperature}); clamping to 0.7`);
7137
+ settings = { ...settings, temperature: 0.7 };
7138
+ }
7139
+ if (settings.maxTokens <= 0) {
7140
+ warn?.(`Settings: maxTokens must be positive; resetting to ${DEFAULT_SETTINGS.maxTokens}`);
7141
+ settings = { ...settings, maxTokens: DEFAULT_SETTINGS.maxTokens };
7142
+ }
7143
+ return { settings, sources };
7144
+ }
7145
+ var DEFAULT_SETTINGS, ENV_MAP;
7146
+ var init_Settings = __esm({
7147
+ "../core/src/Settings.ts"() {
7148
+ "use strict";
7149
+ init_esm_shims();
7150
+ DEFAULT_SETTINGS = {
7151
+ apiUrl: "https://api.msapling.com",
7152
+ defaultModel: "google/gemini-2.0-flash-001",
7153
+ defaultMode: "default",
7154
+ theme: "diamond",
7155
+ maxTokens: 4096,
7156
+ temperature: 0.7,
7157
+ ollamaEnabled: true,
7158
+ ollamaBaseUrl: "http://127.0.0.1:11434",
7159
+ telemetryEnabled: true,
7160
+ mcpServers: {},
7161
+ hooks: {},
7162
+ trustedCommands: [],
7163
+ shellEscapeEnabled: true
7164
+ };
7165
+ ENV_MAP = {
7166
+ MSAPLING_API_URL: "apiUrl",
7167
+ MSAPLING_DEFAULT_MODEL: "defaultModel",
7168
+ MSAPLING_DEFAULT_MODE: "defaultMode",
7169
+ MSAPLING_THEME: "theme",
7170
+ MSAPLING_MAX_TOKENS: "maxTokens",
7171
+ MSAPLING_TEMPERATURE: "temperature",
7172
+ MSAPLING_OLLAMA_ENABLED: "ollamaEnabled",
7173
+ MSAPLING_OLLAMA_BASE_URL: "ollamaBaseUrl",
7174
+ MSAPLING_TELEMETRY_ENABLED: "telemetryEnabled"
7175
+ };
7176
+ }
7177
+ });
7178
+
7185
7179
  // ../core/src/mcp/client.ts
7186
7180
  import { spawn as spawn8 } from "child_process";
7187
7181
  var PROTOCOL_VERSION, CLIENT_INFO, MCPClientError, MCPClient, MCPRegistry;
@@ -7293,7 +7287,7 @@ var init_client = __esm({
7293
7287
  if (!this.proc) throw new MCPClientError(`MCP server "${this.name}" not started`);
7294
7288
  const id = this.nextId++;
7295
7289
  const frame = { jsonrpc: "2.0", id, method, params };
7296
- return new Promise((resolve17, reject) => {
7290
+ return new Promise((resolve18, reject) => {
7297
7291
  const timer = setTimeout(() => {
7298
7292
  this.pending.delete(id);
7299
7293
  reject(new MCPClientError(`MCP request ${method} timed out after ${timeoutMs}ms`));
@@ -7301,7 +7295,7 @@ var init_client = __esm({
7301
7295
  this.pending.set(id, {
7302
7296
  resolve: (v) => {
7303
7297
  clearTimeout(timer);
7304
- resolve17(v);
7298
+ resolve18(v);
7305
7299
  },
7306
7300
  reject: (e) => {
7307
7301
  clearTimeout(timer);
@@ -7328,7 +7322,7 @@ var init_client = __esm({
7328
7322
  if (!this.proc?.stdout) return;
7329
7323
  const stdout = this.proc.stdout;
7330
7324
  const decoder = new TextDecoder();
7331
- return new Promise((resolve17) => {
7325
+ return new Promise((resolve18) => {
7332
7326
  stdout.on("data", (chunk) => {
7333
7327
  this.buffer += decoder.decode(chunk, { stream: true });
7334
7328
  let idx;
@@ -7339,8 +7333,8 @@ var init_client = __esm({
7339
7333
  this.handleFrame(line);
7340
7334
  }
7341
7335
  });
7342
- stdout.on("end", () => resolve17());
7343
- stdout.on("error", () => resolve17());
7336
+ stdout.on("end", () => resolve18());
7337
+ stdout.on("error", () => resolve18());
7344
7338
  });
7345
7339
  }
7346
7340
  handleFrame(line) {
@@ -7427,7 +7421,7 @@ var init_Swarm = __esm({
7427
7421
  * Execute a parallel swarm with shadow auditing and optional sub-shell popups.
7428
7422
  */
7429
7423
  async execute(tasks, projectRoot) {
7430
- const promises = tasks.map(async (task) => {
7424
+ const promises2 = tasks.map(async (task) => {
7431
7425
  const audit = await this.shadow.verifyAction(task.prompt, `Swarm Task: ${task.name}`);
7432
7426
  if (!audit.approved) {
7433
7427
  return { taskId: task.id, workerId: "none", response: "", status: "blocked", auditNote: audit.reasoning };
@@ -7449,7 +7443,7 @@ var init_Swarm = __esm({
7449
7443
  return { taskId: task.id, workerId: task.id, response: e.message, status: "failed" };
7450
7444
  }
7451
7445
  });
7452
- return Promise.all(promises);
7446
+ return Promise.all(promises2);
7453
7447
  }
7454
7448
  /**
7455
7449
  * SYNTHESIS: Use a high-reasoning model to merge the safe swarm results.
@@ -7515,7 +7509,7 @@ function isTokenLike(str) {
7515
7509
  return str.length >= 20 && /^[A-Za-z0-9_\-\.]+$/.test(str);
7516
7510
  }
7517
7511
  async function promptPassword(prompt) {
7518
- return new Promise((resolve17) => {
7512
+ return new Promise((resolve18) => {
7519
7513
  const stdin = process.stdin;
7520
7514
  const stdout = process.stdout;
7521
7515
  stdout.write(prompt);
@@ -7531,12 +7525,12 @@ async function promptPassword(prompt) {
7531
7525
  stdin.setRawMode(wasRaw);
7532
7526
  stdin.removeListener("data", onData);
7533
7527
  stdout.write("\n");
7534
- resolve17(password);
7528
+ resolve18(password);
7535
7529
  } else if (char === "") {
7536
7530
  stdin.setRawMode(wasRaw);
7537
7531
  stdin.removeListener("data", onData);
7538
7532
  stdout.write("\n");
7539
- resolve17("");
7533
+ resolve18("");
7540
7534
  } else if (char === "\x7F" || char === "\b") {
7541
7535
  password = password.slice(0, -1);
7542
7536
  } else if (char >= " " && char <= "~") {
@@ -7547,7 +7541,7 @@ async function promptPassword(prompt) {
7547
7541
  });
7548
7542
  }
7549
7543
  async function promptTotp(prompt) {
7550
- return new Promise((resolve17) => {
7544
+ return new Promise((resolve18) => {
7551
7545
  const stdin = process.stdin;
7552
7546
  const stdout = process.stdout;
7553
7547
  stdout.write(prompt);
@@ -7563,12 +7557,12 @@ async function promptTotp(prompt) {
7563
7557
  stdin.setRawMode(wasRaw);
7564
7558
  stdin.removeListener("data", onData);
7565
7559
  stdout.write("\n");
7566
- resolve17(code);
7560
+ resolve18(code);
7567
7561
  } else if (char === "") {
7568
7562
  stdin.setRawMode(wasRaw);
7569
7563
  stdin.removeListener("data", onData);
7570
7564
  stdout.write("\n");
7571
- resolve17("");
7565
+ resolve18("");
7572
7566
  } else if (char === "\x7F" || char === "\b") {
7573
7567
  code = code.slice(0, -1);
7574
7568
  } else if (/^\d$/.test(char)) {
@@ -7657,7 +7651,7 @@ async function loginWithGithubDevice(context) {
7657
7651
  const deadline = Date.now() + expires_in * 1e3;
7658
7652
  let githubToken = null;
7659
7653
  while (Date.now() < deadline) {
7660
- await new Promise((resolve17) => setTimeout(resolve17, pollMs));
7654
+ await new Promise((resolve18) => setTimeout(resolve18, pollMs));
7661
7655
  let tokenResp;
7662
7656
  try {
7663
7657
  tokenResp = await fetch(GITHUB_TOKEN_URL, {
@@ -7680,7 +7674,7 @@ async function loginWithGithubDevice(context) {
7680
7674
  }
7681
7675
  if (tokenData.error === "authorization_pending") continue;
7682
7676
  if (tokenData.error === "slow_down") {
7683
- await new Promise((resolve17) => setTimeout(resolve17, 5e3));
7677
+ await new Promise((resolve18) => setTimeout(resolve18, 5e3));
7684
7678
  continue;
7685
7679
  }
7686
7680
  context.addMessage("system", `GitHub auth error: ${tokenData.error_description || tokenData.error}`);
@@ -7789,7 +7783,7 @@ var init_unlock = __esm({
7789
7783
 
7790
7784
  // src/commands/doctor.ts
7791
7785
  import { homedir as homedir9 } from "os";
7792
- import { join as join15 } from "path";
7786
+ import { join as join16 } from "path";
7793
7787
  import { existsSync as existsSync14 } from "fs";
7794
7788
  import { readFile as readFile13 } from "fs/promises";
7795
7789
  async function checkApiHealth(client) {
@@ -7816,7 +7810,7 @@ async function checkAuthStatus(client) {
7816
7810
  }
7817
7811
  }
7818
7812
  async function checkSettingsFile() {
7819
- const settingsPath = join15(homedir9(), ".msapling", "settings.json");
7813
+ const settingsPath = join16(homedir9(), ".msapling", "settings.json");
7820
7814
  try {
7821
7815
  if (!existsSync14(settingsPath)) {
7822
7816
  return { ok: false, message: `Not found: ${settingsPath}` };
@@ -8062,7 +8056,7 @@ var init_clear = __esm({
8062
8056
 
8063
8057
  // src/commands/mode.ts
8064
8058
  import { homedir as homedir10 } from "os";
8065
- import { join as join16 } from "path";
8059
+ import { join as join17 } from "path";
8066
8060
  import { existsSync as existsSync15 } from "fs";
8067
8061
  import { readFile as readFile14, writeFile as writeFile7, mkdir as mkdir7 } from "fs/promises";
8068
8062
  async function persistApprovalMode(mode, ttlMs) {
@@ -8080,7 +8074,7 @@ async function persistApprovalMode(mode, ttlMs) {
8080
8074
  ...ttlMs && { ttlMs }
8081
8075
  };
8082
8076
  existing.approvalMode = entry;
8083
- const settingsDir = join16(homedir10(), ".msapling");
8077
+ const settingsDir = join17(homedir10(), ".msapling");
8084
8078
  if (!existsSync15(settingsDir)) {
8085
8079
  await mkdir7(settingsDir, { recursive: true });
8086
8080
  }
@@ -8093,7 +8087,7 @@ var init_mode = __esm({
8093
8087
  "src/commands/mode.ts"() {
8094
8088
  "use strict";
8095
8089
  init_esm_shims();
8096
- SETTINGS_PATH = join16(homedir10(), ".msapling", "settings.json");
8090
+ SETTINGS_PATH = join17(homedir10(), ".msapling", "settings.json");
8097
8091
  modeCommand = {
8098
8092
  name: "mode",
8099
8093
  args: "[default|plan|acceptEdits|bypassPermissions] [...options]",
@@ -8367,7 +8361,7 @@ var init_compact = __esm({
8367
8361
  });
8368
8362
 
8369
8363
  // src/commands/init.ts
8370
- import { join as join17 } from "path";
8364
+ import { join as join18 } from "path";
8371
8365
  import { existsSync as existsSync16 } from "fs";
8372
8366
  import { writeFile as writeFile8 } from "fs/promises";
8373
8367
  var initCommand;
@@ -8382,7 +8376,7 @@ var init_init = __esm({
8382
8376
  handler: async (args2, context) => {
8383
8377
  try {
8384
8378
  const cwd = process.cwd();
8385
- const path2 = join17(cwd, "MSAPLING.md");
8379
+ const path2 = join18(cwd, "MSAPLING.md");
8386
8380
  if (existsSync16(path2)) {
8387
8381
  context.addMessage("error", "MSAPLING.md already exists in current directory.");
8388
8382
  return;
@@ -8525,12 +8519,12 @@ var init_swarm = __esm({
8525
8519
  import { parse as parseYaml } from "yaml";
8526
8520
  import { existsSync as existsSync18 } from "fs";
8527
8521
  import { readFile as readFile16 } from "fs/promises";
8528
- import { join as join18 } from "path";
8522
+ import { join as join19 } from "path";
8529
8523
  function findRecipe(name, cwd) {
8530
8524
  for (const dir of RECIPE_DIRS) {
8531
8525
  for (const suffix of NAME_SUFFIXES) {
8532
8526
  for (const ext of FILE_EXTS) {
8533
- const p = join18(cwd, dir, `${name}${suffix}${ext}`);
8527
+ const p = join19(cwd, dir, `${name}${suffix}${ext}`);
8534
8528
  if (existsSync18(p)) return p;
8535
8529
  }
8536
8530
  }
@@ -8638,7 +8632,7 @@ ${rendered}` : rendered;
8638
8632
  // src/commands/skill.ts
8639
8633
  import { existsSync as existsSync19, readdirSync as readdirSync2, statSync as statSync5 } from "fs";
8640
8634
  import { readFile as readFile17 } from "fs/promises";
8641
- import { join as join19, resolve as resolve14 } from "path";
8635
+ import { join as join20, resolve as resolve14 } from "path";
8642
8636
  function findSkillsRoot(cwd) {
8643
8637
  for (const candidate of SKILLS_DIRS) {
8644
8638
  const full = resolve14(cwd, candidate);
@@ -8655,7 +8649,7 @@ function listAllSkills(root) {
8655
8649
  return out;
8656
8650
  }
8657
8651
  for (const domain of domains) {
8658
- const dir = join19(root, domain);
8652
+ const dir = join20(root, domain);
8659
8653
  let s;
8660
8654
  try {
8661
8655
  s = statSync5(dir);
@@ -8671,7 +8665,7 @@ function listAllSkills(root) {
8671
8665
  }
8672
8666
  for (const f of files) {
8673
8667
  if (!f.endsWith(".md")) continue;
8674
- out.push({ domain, name: f.slice(0, -3), path: join19(dir, f) });
8668
+ out.push({ domain, name: f.slice(0, -3), path: join20(dir, f) });
8675
8669
  }
8676
8670
  }
8677
8671
  return out.sort(
@@ -8761,8 +8755,9 @@ ${prompt}`;
8761
8755
 
8762
8756
  // src/commands/benchmark.ts
8763
8757
  import { homedir as homedir11 } from "os";
8764
- import { join as join20 } from "path";
8765
- import { mkdirSync as mkdirSync4, writeFileSync } from "fs";
8758
+ import { join as join21 } from "path";
8759
+ import { mkdirSync as mkdirSync4 } from "fs";
8760
+ import * as fs2 from "fs";
8766
8761
  function parseArgs(args2) {
8767
8762
  let models = null;
8768
8763
  let rounds = 1;
@@ -8877,10 +8872,10 @@ HW at start: ${hw.cores}-core ${hw.platform} | CPU ${hw.cpuPct}% | RAM ${hw.ramP
8877
8872
  `[HW at run time: CPU ${hwAtEnd.cpuPct}% / RAM ${hwAtEnd.ramPct}% | ${hw.ramGiB} GiB RAM, ${hw.cores} cores]`
8878
8873
  );
8879
8874
  try {
8880
- const dir = join20(homedir11(), ".msapling", "benchmarks");
8875
+ const dir = join21(homedir11(), ".msapling", "benchmarks");
8881
8876
  mkdirSync4(dir, { recursive: true });
8882
8877
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 16);
8883
- const file = join20(dir, `${ts}.json`);
8878
+ const file = join21(dir, `${ts}.json`);
8884
8879
  const run = {
8885
8880
  ts: (/* @__PURE__ */ new Date()).toISOString(),
8886
8881
  rounds,
@@ -8890,7 +8885,7 @@ HW at start: ${hw.cores}-core ${hw.platform} | CPU ${hw.cpuPct}% | RAM ${hw.ramP
8890
8885
  hw_end: hwAtEnd,
8891
8886
  results
8892
8887
  };
8893
- writeFileSync(file, JSON.stringify(run, null, 2));
8888
+ await fs2.promises.writeFile(file, JSON.stringify(run, null, 2));
8894
8889
  context.addMessage("system", `Results saved to ${file}`);
8895
8890
  } catch (e) {
8896
8891
  context.addMessage("system", `Warning: could not save results \u2014 ${e?.message ?? e}`);
@@ -9126,12 +9121,12 @@ var init_theme = __esm({
9126
9121
  });
9127
9122
 
9128
9123
  // src/commands/theme.ts
9129
- import { join as join21 } from "path";
9124
+ import { join as join22 } from "path";
9130
9125
  import { homedir as homedir12 } from "os";
9131
9126
  import { existsSync as existsSync20 } from "fs";
9132
9127
  import { readFile as readFile18, writeFile as writeFile9 } from "fs/promises";
9133
9128
  async function persistTheme(storage, themeName) {
9134
- const settingsPath = join21(homedir12(), ".msapling", "settings.json");
9129
+ const settingsPath = join22(homedir12(), ".msapling", "settings.json");
9135
9130
  let existing = {};
9136
9131
  try {
9137
9132
  if (existsSync20(settingsPath)) {
@@ -9141,7 +9136,7 @@ async function persistTheme(storage, themeName) {
9141
9136
  } catch {
9142
9137
  }
9143
9138
  existing["theme"] = themeName;
9144
- ensureConfigDir(join21(homedir12(), ".msapling"));
9139
+ ensureConfigDir(join22(homedir12(), ".msapling"));
9145
9140
  await writeFile9(settingsPath, JSON.stringify(existing, null, 2), "utf8");
9146
9141
  }
9147
9142
  var VALID_THEMES, themeCommand;
@@ -9198,7 +9193,7 @@ Available themes: ${VALID_THEMES.join(", ")}`);
9198
9193
  });
9199
9194
 
9200
9195
  // src/commands/version.ts
9201
- import { join as join22 } from "path";
9196
+ import { join as join23 } from "path";
9202
9197
  import { existsSync as existsSync21 } from "fs";
9203
9198
  import { readFile as readFile19 } from "fs/promises";
9204
9199
  function row2(label, value) {
@@ -9227,8 +9222,8 @@ var init_version = __esm({
9227
9222
  category: "debug",
9228
9223
  handler: async (_args, context) => {
9229
9224
  const baseDir = typeof __dirname !== "undefined" ? __dirname : process.cwd();
9230
- const cliPkgPath = join22(baseDir, "..", "..", "package.json");
9231
- const corePkgPath = join22(baseDir, "..", "..", "..", "core", "package.json");
9225
+ const cliPkgPath = join23(baseDir, "..", "..", "package.json");
9226
+ const corePkgPath = join23(baseDir, "..", "..", "..", "core", "package.json");
9232
9227
  const [cliVersion, coreVersion] = await Promise.all([
9233
9228
  readPackageVersion(cliPkgPath),
9234
9229
  readPackageVersion(corePkgPath)
@@ -9253,13 +9248,13 @@ var init_version = __esm({
9253
9248
  });
9254
9249
 
9255
9250
  // src/commands/feedback.ts
9256
- import { join as join23 } from "path";
9251
+ import { join as join24 } from "path";
9257
9252
  import { existsSync as existsSync22 } from "fs";
9258
9253
  import { readFile as readFile20 } from "fs/promises";
9259
9254
  async function readCliVersion() {
9260
9255
  try {
9261
9256
  const baseDir = typeof __dirname !== "undefined" ? __dirname : process.cwd();
9262
- const pkgPath = join23(baseDir, "..", "..", "package.json");
9257
+ const pkgPath = join24(baseDir, "..", "..", "package.json");
9263
9258
  if (!existsSync22(pkgPath)) return "unknown";
9264
9259
  const text = await readFile20(pkgPath, "utf8");
9265
9260
  const json = JSON.parse(text);
@@ -9302,7 +9297,7 @@ var init_feedback = __esm({
9302
9297
 
9303
9298
  // src/commands/export.ts
9304
9299
  import { homedir as homedir13 } from "os";
9305
- import { join as join24 } from "path";
9300
+ import { join as join25 } from "path";
9306
9301
  import { writeFile as writeFile10, mkdir as mkdir8 } from "fs/promises";
9307
9302
  function formatTimestamp(date) {
9308
9303
  return date.toISOString().replace(/[:.]/g, "-").replace("T", "_").slice(0, 19);
@@ -9352,10 +9347,10 @@ var init_export = __esm({
9352
9347
  let outputPath;
9353
9348
  let content;
9354
9349
  if (arg === "" || arg === "json") {
9355
- outputPath = join24(homedir13(), `msapling-export-${timestamp}.json`);
9350
+ outputPath = join25(homedir13(), `msapling-export-${timestamp}.json`);
9356
9351
  content = buildJsonExport(history);
9357
9352
  } else if (arg === "markdown" || arg === "md") {
9358
- outputPath = join24(homedir13(), `msapling-export-${timestamp}.md`);
9353
+ outputPath = join25(homedir13(), `msapling-export-${timestamp}.md`);
9359
9354
  content = buildMarkdownExport(history);
9360
9355
  } else {
9361
9356
  outputPath = arg;
@@ -9367,7 +9362,7 @@ var init_export = __esm({
9367
9362
  }
9368
9363
  }
9369
9364
  try {
9370
- const dir = join24(outputPath, "..");
9365
+ const dir = join25(outputPath, "..");
9371
9366
  await mkdir8(dir, { recursive: true });
9372
9367
  await writeFile10(outputPath, content, "utf8");
9373
9368
  context.addMessage("system", `Exported to: ${outputPath}`);
@@ -9563,11 +9558,11 @@ var init_plan = __esm({
9563
9558
 
9564
9559
  // src/commands/note.ts
9565
9560
  import { homedir as homedir14 } from "os";
9566
- import { join as join25 } from "path";
9561
+ import { join as join26 } from "path";
9567
9562
  import { existsSync as existsSync23 } from "fs";
9568
9563
  import { readFile as readFile21, writeFile as writeFile11 } from "fs/promises";
9569
9564
  function getNotesFilePath() {
9570
- return join25(homedir14(), ".msapling", "notes.json");
9565
+ return join26(homedir14(), ".msapling", "notes.json");
9571
9566
  }
9572
9567
  async function readNotes(filePath = getNotesFilePath()) {
9573
9568
  try {
@@ -9581,7 +9576,7 @@ async function readNotes(filePath = getNotesFilePath()) {
9581
9576
  }
9582
9577
  }
9583
9578
  async function writeNotes(notes, filePath = getNotesFilePath()) {
9584
- const dir = join25(homedir14(), ".msapling");
9579
+ const dir = join26(homedir14(), ".msapling");
9585
9580
  ensureConfigDir(dir);
9586
9581
  await writeFile11(filePath, JSON.stringify(notes, null, 2), "utf8");
9587
9582
  }
@@ -9808,6 +9803,343 @@ var init_commands = __esm({
9808
9803
  }
9809
9804
  });
9810
9805
 
9806
+ // src/runtime/doctor.ts
9807
+ var doctor_exports = {};
9808
+ __export(doctor_exports, {
9809
+ runDoctor: () => runDoctor
9810
+ });
9811
+ import { homedir as homedir15, platform as platform2 } from "os";
9812
+ import { join as join27 } from "path";
9813
+ import { existsSync as existsSync25, statSync as statSync6, accessSync } from "fs";
9814
+ import { readdir as readdir3 } from "fs/promises";
9815
+ import { exec } from "child_process";
9816
+ import { promisify } from "util";
9817
+ function redactSecrets(text) {
9818
+ return text.replace(/token[=:]\s*['"]?[a-zA-Z0-9_-]+['"]?/gi, "token=***").replace(/password[=:]\s*['"]?[a-zA-Z0-9_-]+['"]?/gi, "password=***").replace(/api[_-]?key[=:]\s*['"]?[a-zA-Z0-9_-]+['"]?/gi, "api_key=***").replace(/secret[=:]\s*['"]?[a-zA-Z0-9_-]+['"]?/gi, "secret=***").replace(/MSAPLING_TOKEN=.*/gi, "MSAPLING_TOKEN=***").replace(/MSAPLING_API_KEY=.*/gi, "MSAPLING_API_KEY=***");
9819
+ }
9820
+ async function checkNodeVersion() {
9821
+ const version = process.version;
9822
+ const match = version.match(/v(\d+)/);
9823
+ const major = match ? parseInt(match[1], 10) : 0;
9824
+ if (major >= 18) {
9825
+ return {
9826
+ name: "Node version",
9827
+ status: "PASS",
9828
+ message: `${version} (>=18)`
9829
+ };
9830
+ }
9831
+ return {
9832
+ name: "Node version",
9833
+ status: "FAIL",
9834
+ message: `${version} (requires >=18)`,
9835
+ remediation: `Upgrade Node.js to v18+ from https://nodejs.org/`
9836
+ };
9837
+ }
9838
+ async function checkConfigDir() {
9839
+ const configDir = join27(homedir15(), ".msapling");
9840
+ if (!existsSync25(configDir)) {
9841
+ return {
9842
+ name: "Config directory",
9843
+ status: "WARN",
9844
+ message: `${configDir} does not exist`,
9845
+ remediation: `mkdir -p "${configDir}" && chmod 700 "${configDir}"`
9846
+ };
9847
+ }
9848
+ const stats = statSync6(configDir);
9849
+ if (!stats.isDirectory()) {
9850
+ return {
9851
+ name: "Config directory",
9852
+ status: "FAIL",
9853
+ message: `${configDir} exists but is not a directory`,
9854
+ remediation: `rm "${configDir}" && mkdir -p "${configDir}"`
9855
+ };
9856
+ }
9857
+ if (platform2() !== "win32") {
9858
+ const mode = stats.mode & 511;
9859
+ const safe = (mode & 63) === 0;
9860
+ if (!safe) {
9861
+ return {
9862
+ name: "Config directory",
9863
+ status: "WARN",
9864
+ message: `${configDir} has overly permissive perms (${(mode & 511).toString(8)})`,
9865
+ remediation: `chmod 700 "${configDir}"`
9866
+ };
9867
+ }
9868
+ }
9869
+ return {
9870
+ name: "Config directory",
9871
+ status: "PASS",
9872
+ message: `${configDir} exists and is readable`
9873
+ };
9874
+ }
9875
+ async function checkKeytar() {
9876
+ try {
9877
+ const keytar2 = await import("keytar");
9878
+ if (keytar2 && typeof keytar2.getPassword === "function") {
9879
+ return {
9880
+ name: "Keytar native binary",
9881
+ status: "PASS",
9882
+ message: "Keytar loadable and functional"
9883
+ };
9884
+ }
9885
+ } catch (e) {
9886
+ const msg = e instanceof Error ? e.message : String(e);
9887
+ return {
9888
+ name: "Keytar native binary",
9889
+ status: "WARN",
9890
+ message: `Keytar unavailable: ${msg}`,
9891
+ remediation: `Token will be stored in plaintext. Run 'npm rebuild keytar' or 'bun install --force' to rebuild native bindings.`
9892
+ };
9893
+ }
9894
+ return {
9895
+ name: "Keytar native binary",
9896
+ status: "WARN",
9897
+ message: "Keytar check inconclusive",
9898
+ remediation: `Run 'npm rebuild keytar' or 'bun install --force' to rebuild native bindings.`
9899
+ };
9900
+ }
9901
+ async function checkPathConflicts() {
9902
+ const pathEnv = process.env.PATH || "";
9903
+ const paths = pathEnv.split(platform2() === "win32" ? ";" : ":");
9904
+ const conflicts = [];
9905
+ for (const dir of paths) {
9906
+ if (!dir || !existsSync25(dir)) continue;
9907
+ try {
9908
+ const files = await readdir3(dir);
9909
+ for (const file of files) {
9910
+ if (file === "msapling" || file === "msapling.exe" || file === "msapling.py") {
9911
+ const fullPath = join27(dir, file);
9912
+ conflicts.push(fullPath);
9913
+ }
9914
+ }
9915
+ } catch {
9916
+ }
9917
+ }
9918
+ if (conflicts.length === 0) {
9919
+ return {
9920
+ name: "PATH conflicts",
9921
+ status: "PASS",
9922
+ message: "No conflicting msapling binaries found"
9923
+ };
9924
+ }
9925
+ if (conflicts.length === 1) {
9926
+ return {
9927
+ name: "PATH conflicts",
9928
+ status: "PASS",
9929
+ message: `Single msapling binary found: ${conflicts[0]}`
9930
+ };
9931
+ }
9932
+ return {
9933
+ name: "PATH conflicts",
9934
+ status: "WARN",
9935
+ message: `Multiple msapling binaries found in PATH`,
9936
+ remediation: `Found: ${conflicts.join(", ")}. Remove stale copies (especially .py or .exe).`
9937
+ };
9938
+ }
9939
+ async function checkNetworkReach() {
9940
+ const apiUrl = process.env.MSAPLING_API_URL || "https://api.msapling.com";
9941
+ const timeout = 5e3;
9942
+ try {
9943
+ const controller = new AbortController();
9944
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
9945
+ const response = await fetch(`${apiUrl}/api/health`, {
9946
+ method: "HEAD",
9947
+ signal: controller.signal
9948
+ });
9949
+ clearTimeout(timeoutId);
9950
+ if (response.ok) {
9951
+ return {
9952
+ name: "Network reach",
9953
+ status: "PASS",
9954
+ message: `${apiUrl} reachable`
9955
+ };
9956
+ }
9957
+ return {
9958
+ name: "Network reach",
9959
+ status: "WARN",
9960
+ message: `${apiUrl} returned status ${response.status}`,
9961
+ remediation: `Check your network connection or API server status.`
9962
+ };
9963
+ } catch (e) {
9964
+ const msg = e instanceof Error ? e.message : String(e);
9965
+ return {
9966
+ name: "Network reach",
9967
+ status: "WARN",
9968
+ message: `Cannot reach ${apiUrl}: ${msg}`,
9969
+ remediation: `Check your network connection and firewall settings.`
9970
+ };
9971
+ }
9972
+ }
9973
+ async function checkTokenValidity() {
9974
+ try {
9975
+ const keytar2 = await import("keytar");
9976
+ const KEYCHAIN_SERVICE = "msapling-cli";
9977
+ const KEYCHAIN_ACCOUNT = "auth_token";
9978
+ const token = await keytar2.getPassword(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT);
9979
+ if (!token) {
9980
+ return {
9981
+ name: "Token validity",
9982
+ status: "WARN",
9983
+ message: "No token stored in keychain",
9984
+ remediation: `Run 'msapling login' to authenticate.`
9985
+ };
9986
+ }
9987
+ if (typeof token === "string" && token.length > 10) {
9988
+ return {
9989
+ name: "Token validity",
9990
+ status: "PASS",
9991
+ message: `Token loaded (${token.length} chars)`
9992
+ };
9993
+ }
9994
+ return {
9995
+ name: "Token validity",
9996
+ status: "WARN",
9997
+ message: "Token present but appears invalid",
9998
+ remediation: `Run 'msapling login' to re-authenticate.`
9999
+ };
10000
+ } catch (e) {
10001
+ const msg = e instanceof Error ? e.message : String(e);
10002
+ return {
10003
+ name: "Token validity",
10004
+ status: "WARN",
10005
+ message: `Cannot check token: ${msg}`,
10006
+ remediation: `Run 'msapling login' to authenticate.`
10007
+ };
10008
+ }
10009
+ }
10010
+ async function checkOsSpecific() {
10011
+ if (platform2() === "win32") {
10012
+ try {
10013
+ const configDir = join27(homedir15(), ".msapling");
10014
+ const longPath = "A".repeat(260);
10015
+ const testPath = join27(configDir, longPath);
10016
+ try {
10017
+ accessSync(configDir);
10018
+ } catch {
10019
+ return {
10020
+ name: "OS-specific (Windows)",
10021
+ status: "WARN",
10022
+ message: "Cannot verify Windows long-path support",
10023
+ remediation: `Enable LongPathsEnabled in Registry or use 'fsutil 8dot3name set C: 0'.`
10024
+ };
10025
+ }
10026
+ return {
10027
+ name: "OS-specific (Windows)",
10028
+ status: "PASS",
10029
+ message: "Windows long-path support accessible"
10030
+ };
10031
+ } catch (e) {
10032
+ return {
10033
+ name: "OS-specific (Windows)",
10034
+ status: "WARN",
10035
+ message: "Windows long-path check failed",
10036
+ remediation: `Enable LongPathsEnabled in Registry or use 'fsutil 8dot3name set C: 0'.`
10037
+ };
10038
+ }
10039
+ }
10040
+ if (platform2() === "darwin") {
10041
+ return {
10042
+ name: "OS-specific (macOS)",
10043
+ status: "PASS",
10044
+ message: "macOS detected"
10045
+ };
10046
+ }
10047
+ if (platform2() === "linux") {
10048
+ try {
10049
+ await import("keytar");
10050
+ return {
10051
+ name: "OS-specific (Linux)",
10052
+ status: "PASS",
10053
+ message: "libsecret/keytar dependencies available"
10054
+ };
10055
+ } catch (e) {
10056
+ return {
10057
+ name: "OS-specific (Linux)",
10058
+ status: "WARN",
10059
+ message: "libsecret may not be installed",
10060
+ remediation: `Install libsecret: sudo apt-get install libsecret-1-dev (Ubuntu/Debian) or dnf install libsecret-devel (Fedora)`
10061
+ };
10062
+ }
10063
+ }
10064
+ return {
10065
+ name: "OS-specific",
10066
+ status: "PASS",
10067
+ message: `${platform2()} detected`
10068
+ };
10069
+ }
10070
+ function formatCheckResult(result, maxLabelWidth) {
10071
+ const indicator2 = result.status === "PASS" ? "\u2713" : result.status === "WARN" ? "\u26A0" : "\u2717";
10072
+ const paddedLabel = result.name.padEnd(maxLabelWidth);
10073
+ const statusStr = `[${indicator2} ${result.status}]`.padEnd(10);
10074
+ let output = ` ${paddedLabel} ${statusStr} ${result.message}`;
10075
+ if (result.remediation) {
10076
+ output += `
10077
+ \u2192 ${result.remediation}`;
10078
+ }
10079
+ return output;
10080
+ }
10081
+ function dumpEnv(debug) {
10082
+ if (!debug) return [];
10083
+ const lines = [];
10084
+ lines.push("");
10085
+ lines.push("\u2500".repeat(60));
10086
+ lines.push("Environment variables:");
10087
+ lines.push("\u2500".repeat(60));
10088
+ const env = { ...process.env };
10089
+ const keys = Object.keys(env).sort();
10090
+ for (const key of keys) {
10091
+ const value = env[key] || "";
10092
+ const redacted = redactSecrets(value);
10093
+ lines.push(`${key}=${redacted}`);
10094
+ }
10095
+ return lines;
10096
+ }
10097
+ async function runDoctor(debug = false) {
10098
+ const output = [];
10099
+ output.push("");
10100
+ output.push("MSapling Doctor \u2014 Health Check");
10101
+ output.push("\u2500".repeat(60));
10102
+ const checks = [];
10103
+ checks.push(await checkNodeVersion());
10104
+ checks.push(await checkConfigDir());
10105
+ checks.push(await checkKeytar());
10106
+ checks.push(await checkPathConflicts());
10107
+ checks.push(await checkNetworkReach());
10108
+ checks.push(await checkTokenValidity());
10109
+ checks.push(await checkOsSpecific());
10110
+ const maxLabelWidth = Math.max(...checks.map((c) => c.name.length));
10111
+ for (const check of checks) {
10112
+ output.push(formatCheckResult(check, maxLabelWidth));
10113
+ }
10114
+ output.push("");
10115
+ output.push("\u2500".repeat(60));
10116
+ const failCount = checks.filter((c) => c.status === "FAIL").length;
10117
+ const warnCount = checks.filter((c) => c.status === "WARN").length;
10118
+ if (failCount === 0 && warnCount === 0) {
10119
+ output.push("All checks passed! \u2713");
10120
+ } else {
10121
+ const msgs = [];
10122
+ if (failCount > 0) msgs.push(`${failCount} failed`);
10123
+ if (warnCount > 0) msgs.push(`${warnCount} warning(s)`);
10124
+ output.push(`Status: ${msgs.join(", ")}`);
10125
+ }
10126
+ output.push("");
10127
+ if (debug) {
10128
+ output.push(...dumpEnv(true));
10129
+ output.push("");
10130
+ }
10131
+ console.log(output.join("\n"));
10132
+ process.exit(failCount > 0 ? 1 : 0);
10133
+ }
10134
+ var execAsync;
10135
+ var init_doctor2 = __esm({
10136
+ "src/runtime/doctor.ts"() {
10137
+ "use strict";
10138
+ init_esm_shims();
10139
+ execAsync = promisify(exec);
10140
+ }
10141
+ });
10142
+
9811
10143
  // ../../node_modules/.bun/diff@9.0.0/node_modules/diff/libesm/diff/base.js
9812
10144
  var Diff;
9813
10145
  var init_base = __esm({
@@ -9894,13 +10226,13 @@ var init_base = __esm({
9894
10226
  editLength++;
9895
10227
  };
9896
10228
  if (callback) {
9897
- (function exec() {
10229
+ (function exec2() {
9898
10230
  setTimeout(function() {
9899
10231
  if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {
9900
10232
  return callback(void 0);
9901
10233
  }
9902
10234
  if (!execEditLength()) {
9903
- exec();
10235
+ exec2();
9904
10236
  }
9905
10237
  }, 0);
9906
10238
  })();
@@ -10984,17 +11316,17 @@ var init_registry_merger = __esm({
10984
11316
 
10985
11317
  // ../core/src/mcp/local_tools.ts
10986
11318
  import { spawn as spawn10 } from "child_process";
10987
- import { readdir as readdir3, stat as stat4, realpath as realpath2 } from "fs/promises";
10988
- import { resolve as resolve15 } from "path";
11319
+ import { readdir as readdir4, stat as stat4, realpath as realpath2 } from "fs/promises";
11320
+ import { resolve as resolve16 } from "path";
10989
11321
  function asResult(text, isError = false) {
10990
11322
  return { content: [{ type: "text", text }], ...isError ? { isError: true } : {} };
10991
11323
  }
10992
11324
  async function runCommand(command, cwd) {
10993
- return new Promise((resolve17) => {
11325
+ return new Promise((resolve18) => {
10994
11326
  let p;
10995
11327
  const timeout = setTimeout(() => {
10996
11328
  if (p) p.kill();
10997
- resolve17({ stdout: "", stderr: "Command timed out after 30s", exit_code: -1 });
11329
+ resolve18({ stdout: "", stderr: "Command timed out after 30s", exit_code: -1 });
10998
11330
  }, 3e4);
10999
11331
  try {
11000
11332
  p = spawn10("sh", ["-c", command], {
@@ -11012,15 +11344,15 @@ async function runCommand(command, cwd) {
11012
11344
  });
11013
11345
  p.on("error", (e) => {
11014
11346
  clearTimeout(timeout);
11015
- resolve17({ stdout, stderr: stderr + (e?.message ?? ""), exit_code: -1 });
11347
+ resolve18({ stdout, stderr: stderr + (e?.message ?? ""), exit_code: -1 });
11016
11348
  });
11017
11349
  p.on("exit", (code) => {
11018
11350
  clearTimeout(timeout);
11019
- resolve17({ stdout, stderr, exit_code: code });
11351
+ resolve18({ stdout, stderr, exit_code: code });
11020
11352
  });
11021
11353
  } catch (e) {
11022
11354
  clearTimeout(timeout);
11023
- resolve17({
11355
+ resolve18({
11024
11356
  stdout: "",
11025
11357
  stderr: e?.message ?? "Failed to spawn process",
11026
11358
  exit_code: -1
@@ -11030,7 +11362,7 @@ async function runCommand(command, cwd) {
11030
11362
  }
11031
11363
  async function listDirectory(path2, maxEntries = 100) {
11032
11364
  try {
11033
- const entries = await readdir3(path2, { withFileTypes: true });
11365
+ const entries = await readdir4(path2, { withFileTypes: true });
11034
11366
  const result = [];
11035
11367
  for (const entry of entries.slice(0, maxEntries)) {
11036
11368
  const item = {
@@ -11087,7 +11419,7 @@ async function callLocalTool(name, args2, projectRoot) {
11087
11419
  const command = String(args2.command ?? "");
11088
11420
  let cwd = projectRoot;
11089
11421
  if (args2.cwd) {
11090
- cwd = resolve15(projectRoot, String(args2.cwd));
11422
+ cwd = resolve16(projectRoot, String(args2.cwd));
11091
11423
  try {
11092
11424
  const resolvedCwd = await realpath2(cwd);
11093
11425
  const resolvedRoot = await realpath2(projectRoot);
@@ -11124,7 +11456,7 @@ ${res.stderr}`
11124
11456
  return asResult("path is required", true);
11125
11457
  }
11126
11458
  try {
11127
- const resolvedPath = await realpath2(resolve15(projectRoot, pathArg));
11459
+ const resolvedPath = await realpath2(resolve16(projectRoot, pathArg));
11128
11460
  const resolvedRoot = await realpath2(projectRoot);
11129
11461
  if (!resolvedPath.startsWith(resolvedRoot)) {
11130
11462
  return asResult("Error: path attempts to escape project root", true);
@@ -11143,7 +11475,7 @@ ${res.stderr}`
11143
11475
  }
11144
11476
  case "local_glob": {
11145
11477
  const pattern = String(args2.pattern ?? "");
11146
- let cwd = args2.cwd ? resolve15(projectRoot, String(args2.cwd)) : projectRoot;
11478
+ let cwd = args2.cwd ? resolve16(projectRoot, String(args2.cwd)) : projectRoot;
11147
11479
  if (!pattern) {
11148
11480
  return asResult("pattern is required", true);
11149
11481
  }
@@ -11172,7 +11504,7 @@ ${res.stderr}`
11172
11504
  }
11173
11505
  if (path2) {
11174
11506
  try {
11175
- const resolvedPath = await realpath2(resolve15(projectRoot, path2));
11507
+ const resolvedPath = await realpath2(resolve16(projectRoot, path2));
11176
11508
  const resolvedRoot = await realpath2(projectRoot);
11177
11509
  if (!resolvedPath.startsWith(resolvedRoot)) {
11178
11510
  return asResult("Error: path attempts to escape project root", true);
@@ -11192,7 +11524,7 @@ ${res.stderr}`
11192
11524
  return asResult("cwd is required", true);
11193
11525
  }
11194
11526
  try {
11195
- const resolvedCwd = await realpath2(resolve15(projectRoot, cwdArg));
11527
+ const resolvedCwd = await realpath2(resolve16(projectRoot, cwdArg));
11196
11528
  const resolvedRoot = await realpath2(projectRoot);
11197
11529
  if (!resolvedCwd.startsWith(resolvedRoot)) {
11198
11530
  return asResult("Error: cwd attempts to escape project root", true);
@@ -11218,7 +11550,7 @@ ${status.porcelain || "(clean)"}`
11218
11550
  return asResult("cwd is required", true);
11219
11551
  }
11220
11552
  try {
11221
- const resolvedCwd = await realpath2(resolve15(projectRoot, cwdArg));
11553
+ const resolvedCwd = await realpath2(resolve16(projectRoot, cwdArg));
11222
11554
  const resolvedRoot = await realpath2(projectRoot);
11223
11555
  if (!resolvedCwd.startsWith(resolvedRoot)) {
11224
11556
  return asResult("Error: cwd attempts to escape project root", true);
@@ -11333,8 +11665,8 @@ __export(server_exports, {
11333
11665
  runStdio: () => runStdio,
11334
11666
  runStdioWithRegistry: () => runStdioWithRegistry
11335
11667
  });
11336
- import { readdirSync as readdirSync3, readFileSync, statSync as statSync6 } from "fs";
11337
- import { join as join26, relative as relative14, resolve as resolve16 } from "path";
11668
+ import { readdirSync as readdirSync3, readFileSync, statSync as statSync7 } from "fs";
11669
+ import { join as join28, relative as relative14, resolve as resolve17 } from "path";
11338
11670
  function asResult2(text, isError = false) {
11339
11671
  return { content: [{ type: "text", text }], ...isError ? { isError: true } : {} };
11340
11672
  }
@@ -11354,10 +11686,10 @@ function buildFileTree(root, maxFiles) {
11354
11686
  for (const name of entries) {
11355
11687
  if (out.length >= maxFiles) break;
11356
11688
  if (SKIP_DIRS2.has(name)) continue;
11357
- const full = join26(dir, name);
11689
+ const full = join28(dir, name);
11358
11690
  let s;
11359
11691
  try {
11360
- s = statSync6(full);
11692
+ s = statSync7(full);
11361
11693
  } catch {
11362
11694
  continue;
11363
11695
  }
@@ -11771,7 +12103,7 @@ ${r.response ?? ""}`;
11771
12103
  return asResult2(JSON.stringify(result));
11772
12104
  }
11773
12105
  case "msapling_project_context": {
11774
- const root = resolve16(String(args2.path ?? "."));
12106
+ const root = resolve17(String(args2.path ?? "."));
11775
12107
  const maxFiles = Number.isFinite(args2.max_files) ? Number(args2.max_files) : 30;
11776
12108
  const maxKB = Number.isFinite(args2.max_file_size_kb) ? Number(args2.max_file_size_kb) : 50;
11777
12109
  const files = buildFileTree(root, maxFiles);
@@ -11867,7 +12199,10 @@ init_esm_shims();
11867
12199
  import { Box, Text } from "ink";
11868
12200
  import { jsx, jsxs } from "react/jsx-runtime";
11869
12201
  var Header = () => /* @__PURE__ */ jsxs(Box, { borderStyle: "single", borderColor: "cyan", paddingX: 1, marginBottom: 1, children: [
11870
- /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "\u25CF MSapling CLI v2.0.0" }),
12202
+ /* @__PURE__ */ jsxs(Text, { bold: true, color: "cyan", children: [
12203
+ "\u25CF MSapling CLI v",
12204
+ "2.3.6-beta.4"
12205
+ ] }),
11871
12206
  /* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "Platinum Tier Architecture" }) })
11872
12207
  ] });
11873
12208
 
@@ -12353,9 +12688,9 @@ ${prompt}` : prompt;
12353
12688
  if (proc.stderr) proc.stderr.on("data", (chunk) => {
12354
12689
  stderr += chunk.toString();
12355
12690
  });
12356
- await new Promise((resolve17, reject) => {
12691
+ await new Promise((resolve18, reject) => {
12357
12692
  proc.on("close", (code) => {
12358
- if (code === 0 || code === null) resolve17();
12693
+ if (code === 0 || code === null) resolve18();
12359
12694
  else reject(new Error(`Process exited with code ${code}`));
12360
12695
  });
12361
12696
  proc.on("error", reject);
@@ -12382,9 +12717,9 @@ ${prompt}` : prompt;
12382
12717
  for (const mention of fileMentions) {
12383
12718
  const filePath = mention.slice(1);
12384
12719
  try {
12385
- const { existsSync: existsSync25 } = await import("fs");
12720
+ const { existsSync: existsSync26 } = await import("fs");
12386
12721
  const { readFile: readFile23 } = await import("fs/promises");
12387
- if (existsSync25(filePath)) {
12722
+ if (existsSync26(filePath)) {
12388
12723
  const content = await readFile23(filePath, "utf8");
12389
12724
  const MAX_LEN = 32768;
12390
12725
  const truncated = content.length > MAX_LEN ? content.slice(0, MAX_LEN) + "\n...[TRUNCATED]" : content;
@@ -12451,9 +12786,9 @@ async function initSession(ctx) {
12451
12786
  ctx.setShellEscapeEnabled(settings.shellEscapeEnabled !== false);
12452
12787
  }
12453
12788
  try {
12454
- const { homedir: homedir15 } = await import("os");
12455
- const { join: join27 } = await import("path");
12456
- const userSettingsPath = join27(homedir15(), ".msapling", "settings.json");
12789
+ const { homedir: homedir16 } = await import("os");
12790
+ const { join: join29 } = await import("path");
12791
+ const userSettingsPath = join29(homedir16(), ".msapling", "settings.json");
12457
12792
  if (existsSync24(userSettingsPath)) {
12458
12793
  const userText = await readFile22(userSettingsPath, "utf8");
12459
12794
  const userJson = JSON.parse(userText);
@@ -12545,8 +12880,8 @@ var App = ({ compact: compact2 = false }) => {
12545
12880
  const storage = useRef(new StorageManager()).current;
12546
12881
  const client = useRef(new MSaplingClient()).current;
12547
12882
  const requestApproval = useCallback((request) => {
12548
- return new Promise((resolve17) => {
12549
- setPendingApproval({ request, resolve: resolve17 });
12883
+ return new Promise((resolve18) => {
12884
+ setPendingApproval({ request, resolve: resolve18 });
12550
12885
  });
12551
12886
  }, []);
12552
12887
  const agent = useRef(new Agent(client, process.cwd(), requestApproval)).current;
@@ -12758,11 +13093,25 @@ function handleCliArgs(args2) {
12758
13093
  console.log("Usage: msapling start interactive REPL");
12759
13094
  console.log(" msapling --compact start REPL in compact mode (no footer, thin separators)");
12760
13095
  console.log(" msapling mcp serve run as MCP stdio server (Claude Code / Cursor / Windsurf integration)");
13096
+ console.log(" msapling doctor run diagnostic health checks");
13097
+ console.log(" msapling doctor --debug run doctor with full environment dump");
12761
13098
  console.log(" msapling --version print version and exit");
12762
13099
  console.log(" msapling --help print this message");
12763
13100
  console.log("Inside the REPL: type /help for slash-command help.");
12764
13101
  process.exit(0);
12765
13102
  }
13103
+ if (args2[0] === "doctor") {
13104
+ (async () => {
13105
+ const { runDoctor: runDoctor2 } = await Promise.resolve().then(() => (init_doctor2(), doctor_exports));
13106
+ const debug = args2.includes("--debug");
13107
+ await runDoctor2(debug);
13108
+ })().catch((e) => {
13109
+ process.stderr.write(`[msapling-doctor] fatal: ${e?.message ?? e}
13110
+ `);
13111
+ process.exit(1);
13112
+ });
13113
+ return false;
13114
+ }
12766
13115
  if (args2[0] === "mcp" && args2[1] === "serve") {
12767
13116
  (async () => {
12768
13117
  const { MSaplingClient: MSaplingClient2 } = await Promise.resolve().then(() => (init_src(), src_exports));