@mtreeai/msapling-cli 2.3.6-beta.24 → 2.3.6-beta.26

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 (2) hide show
  1. package/dist/index.js +323 -152
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -266,6 +266,43 @@ var init_src = __esm({
266
266
  body: JSON.stringify(symbol)
267
267
  });
268
268
  }
269
+ // CLI-MDRIVE-COMMANDS-01 (Iter 36): MDrive user-facing file CRUD. Per LAB
270
+ // routers/mdrive_files.py — all paths under /api/mdrive/ (assembled by
271
+ // mdrive_product.py).
272
+ async mdriveList(path2 = ".", limit = 1e3, offset = 0) {
273
+ const qs = new URLSearchParams({ path: path2, limit: String(limit), offset: String(offset) });
274
+ return await this.request(`/api/mdrive/list?${qs.toString()}`);
275
+ }
276
+ async mdriveRead(path2) {
277
+ return await this.request("/api/mdrive/read", {
278
+ method: "POST",
279
+ body: JSON.stringify({ path: path2 })
280
+ });
281
+ }
282
+ async mdriveWrite(path2, content) {
283
+ return await this.request("/api/mdrive/write", {
284
+ method: "POST",
285
+ body: JSON.stringify({ path: path2, content })
286
+ });
287
+ }
288
+ async mdriveDelete(path2) {
289
+ return await this.request("/api/mdrive/delete", {
290
+ method: "POST",
291
+ body: JSON.stringify({ path: path2 })
292
+ });
293
+ }
294
+ async mdriveRename(path2, newName) {
295
+ return await this.request("/api/mdrive/rename", {
296
+ method: "POST",
297
+ body: JSON.stringify({ path: path2, new_name: newName })
298
+ });
299
+ }
300
+ async mdriveMkdir(path2) {
301
+ return await this.request("/api/mdrive/mkdir", {
302
+ method: "POST",
303
+ body: JSON.stringify({ path: path2 })
304
+ });
305
+ }
269
306
  // CLI-OLLAMA-COMMANDS-01 (Iter 35): Ollama BYOK helpers. Per LAB ollama.py
270
307
  // routes are GET/POST/DELETE under /api/ollama. The CLI uses these to wire
271
308
  // up the user's local Ollama instance as a free-tier model provider.
@@ -1295,7 +1332,7 @@ var init_RunCommandTool = __esm({
1295
1332
  this.activeCommands++;
1296
1333
  return;
1297
1334
  }
1298
- return new Promise((resolve18) => this.queue.push(resolve18));
1335
+ return new Promise((resolve19) => this.queue.push(resolve19));
1299
1336
  }
1300
1337
  static releaseLock() {
1301
1338
  if (this.queue.length > 0) {
@@ -1374,9 +1411,9 @@ var init_RunCommandTool = __esm({
1374
1411
  const chunks = { stdout: [], stderr: [] };
1375
1412
  proc.stdout?.on("data", (chunk) => chunks.stdout.push(chunk));
1376
1413
  proc.stderr?.on("data", (chunk) => chunks.stderr.push(chunk));
1377
- const exitCode = await new Promise((resolve18) => {
1378
- proc.on("exit", (code) => resolve18(code ?? 1));
1379
- proc.on("error", () => resolve18(1));
1414
+ const exitCode = await new Promise((resolve19) => {
1415
+ proc.on("exit", (code) => resolve19(code ?? 1));
1416
+ proc.on("error", () => resolve19(1));
1380
1417
  });
1381
1418
  const stdout = Buffer.concat(chunks.stdout).toString("utf-8");
1382
1419
  const stderr = Buffer.concat(chunks.stderr).toString("utf-8");
@@ -1487,9 +1524,9 @@ var init_src2 = __esm({
1487
1524
  const messages = this.parser.parse(value);
1488
1525
  for (const msg of messages) {
1489
1526
  if (msg.id !== void 0 && this.pendingRequests.has(Number(msg.id))) {
1490
- const resolve18 = this.pendingRequests.get(Number(msg.id));
1491
- if (resolve18) {
1492
- resolve18(msg.result || msg.error);
1527
+ const resolve19 = this.pendingRequests.get(Number(msg.id));
1528
+ if (resolve19) {
1529
+ resolve19(msg.result || msg.error);
1493
1530
  this.pendingRequests.delete(Number(msg.id));
1494
1531
  }
1495
1532
  }
@@ -1504,8 +1541,8 @@ var init_src2 = __esm({
1504
1541
  const message = `Content-Length: ${Buffer.byteLength(content, "utf8")}\r
1505
1542
  \r
1506
1543
  ${content}`;
1507
- return new Promise((resolve18) => {
1508
- this.pendingRequests.set(id, resolve18);
1544
+ return new Promise((resolve19) => {
1545
+ this.pendingRequests.set(id, resolve19);
1509
1546
  this.process.stdin.write(message);
1510
1547
  this.process.stdin.flush();
1511
1548
  });
@@ -1637,9 +1674,9 @@ var init_SubShellTool = __esm({
1637
1674
  }
1638
1675
  throw e;
1639
1676
  }
1640
- await new Promise((resolve18) => {
1641
- proc.on("exit", () => resolve18());
1642
- proc.on("error", () => resolve18());
1677
+ await new Promise((resolve19) => {
1678
+ proc.on("exit", () => resolve19());
1679
+ proc.on("error", () => resolve19());
1643
1680
  });
1644
1681
  return { content: `Successfully launched separate window for ${args2.worker_id}` };
1645
1682
  }
@@ -1722,13 +1759,13 @@ async function findRg() {
1722
1759
  const candidates = ["rg", "C:\\Program Files\\ripgrep\\rg.exe"];
1723
1760
  for (const bin of candidates) {
1724
1761
  try {
1725
- const exited = await new Promise((resolve18) => {
1762
+ const exited = await new Promise((resolve19) => {
1726
1763
  try {
1727
1764
  const p = spawn4(bin, ["--version"], { stdio: ["ignore", "pipe", "pipe"] });
1728
- p.on("error", () => resolve18(null));
1729
- p.on("exit", (code) => resolve18(code));
1765
+ p.on("error", () => resolve19(null));
1766
+ p.on("exit", (code) => resolve19(code));
1730
1767
  } catch {
1731
- resolve18(null);
1768
+ resolve19(null);
1732
1769
  }
1733
1770
  });
1734
1771
  if (exited === 0) return bin;
@@ -1738,7 +1775,7 @@ async function findRg() {
1738
1775
  return null;
1739
1776
  }
1740
1777
  function runRg(bin, args2) {
1741
- return new Promise((resolve18) => {
1778
+ return new Promise((resolve19) => {
1742
1779
  const p = spawn4(bin, args2, { stdio: ["ignore", "pipe", "pipe"] });
1743
1780
  let stdout = "";
1744
1781
  let stderr = "";
@@ -1749,10 +1786,10 @@ function runRg(bin, args2) {
1749
1786
  stderr += d.toString("utf8");
1750
1787
  });
1751
1788
  p.on("error", (e) => {
1752
- resolve18({ stdout, stderr: stderr + (e?.message ?? ""), exitCode: -1 });
1789
+ resolve19({ stdout, stderr: stderr + (e?.message ?? ""), exitCode: -1 });
1753
1790
  });
1754
1791
  p.on("exit", (code) => {
1755
- resolve18({ stdout, stderr, exitCode: code });
1792
+ resolve19({ stdout, stderr, exitCode: code });
1756
1793
  });
1757
1794
  });
1758
1795
  }
@@ -3004,12 +3041,12 @@ Command: ${command}`,
3004
3041
  proc.stdout?.on("data", (chunk) => chunks.stdout.push(chunk));
3005
3042
  proc.stderr?.on("data", (chunk) => chunks.stderr.push(chunk));
3006
3043
  const timeoutPromise = new Promise(
3007
- (resolve18) => setTimeout(() => resolve18("timeout"), timeoutMs)
3044
+ (resolve19) => setTimeout(() => resolve19("timeout"), timeoutMs)
3008
3045
  );
3009
3046
  const processPromise = (async () => {
3010
- const exitCode2 = await new Promise((resolve18) => {
3011
- proc.on("exit", (code) => resolve18(code ?? 1));
3012
- proc.on("error", () => resolve18(1));
3047
+ const exitCode2 = await new Promise((resolve19) => {
3048
+ proc.on("exit", (code) => resolve19(code ?? 1));
3049
+ proc.on("error", () => resolve19(1));
3013
3050
  });
3014
3051
  const stdout2 = Buffer.concat(chunks.stdout).toString("utf-8");
3015
3052
  const stderr2 = Buffer.concat(chunks.stderr).toString("utf-8");
@@ -3756,7 +3793,7 @@ async function copyDir(src, dst) {
3756
3793
  }
3757
3794
  async function backupFile(absPath) {
3758
3795
  try {
3759
- const { readFile: readFile23, writeFile: writeFile12, mkdir: mkdir9 } = await import("fs/promises");
3796
+ const { readFile: readFile24, writeFile: writeFile13, mkdir: mkdir9 } = await import("fs/promises");
3760
3797
  const { homedir: homedir18 } = await import("os");
3761
3798
  const { join: join31 } = await import("path");
3762
3799
  const filename = absPath.split(/[\\/]/).pop() ?? "file";
@@ -3769,8 +3806,8 @@ async function backupFile(absPath) {
3769
3806
  `${filename}.backup-${stamp}-${suffix}.bak`
3770
3807
  );
3771
3808
  await mkdir9(join31(homedir18(), ".msapling", "backups"), { recursive: true });
3772
- const content = await readFile23(absPath, "utf8");
3773
- await writeFile12(backupPath, content, "utf8");
3809
+ const content = await readFile24(absPath, "utf8");
3810
+ await writeFile13(backupPath, content, "utf8");
3774
3811
  return backupPath;
3775
3812
  } catch {
3776
3813
  return null;
@@ -3995,15 +4032,15 @@ var init_DeleteFileTool = __esm({
3995
4032
  let backedUpTo = null;
3996
4033
  if (isFile) {
3997
4034
  try {
3998
- const { readFile: readFile23, writeFile: writeFile12, mkdir: mkdir9 } = await import("fs/promises");
4035
+ const { readFile: readFile24, writeFile: writeFile13, mkdir: mkdir9 } = await import("fs/promises");
3999
4036
  const { homedir: homedir18 } = await import("os");
4000
- const existingContent = await readFile23(abs, "utf8");
4037
+ const existingContent = await readFile24(abs, "utf8");
4001
4038
  const filename = abs.split(/[\\/]/).pop() ?? "file";
4002
4039
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
4003
4040
  const suffix = randomBytes6(4).toString("hex");
4004
4041
  const backupPath = join11(homedir18(), ".msapling", "backups", `${filename}.backup-${stamp}-${suffix}.bak`);
4005
4042
  await mkdir9(join11(homedir18(), ".msapling", "backups"), { recursive: true });
4006
- await writeFile12(backupPath, existingContent, "utf8");
4043
+ await writeFile13(backupPath, existingContent, "utf8");
4007
4044
  backedUpTo = backupPath;
4008
4045
  } catch {
4009
4046
  }
@@ -4342,10 +4379,10 @@ var init_Voice = __esm({
4342
4379
  `;
4343
4380
  try {
4344
4381
  if (process.platform === "win32") {
4345
- await new Promise((resolve18, reject) => {
4382
+ await new Promise((resolve19, reject) => {
4346
4383
  try {
4347
4384
  const proc = spawn6("powershell", ["-Command", psCommand]);
4348
- proc.on("exit", () => resolve18());
4385
+ proc.on("exit", () => resolve19());
4349
4386
  proc.on("error", reject);
4350
4387
  } catch (e) {
4351
4388
  reject(e);
@@ -4459,7 +4496,7 @@ function matches(entry, ctx) {
4459
4496
  async function runOne(entry, ctx) {
4460
4497
  const timeoutMs = entry.timeoutMs ?? DEFAULT_TIMEOUT_MS3;
4461
4498
  const command = entry.command;
4462
- return new Promise((resolve18) => {
4499
+ return new Promise((resolve19) => {
4463
4500
  const isWindows = process.platform === "win32";
4464
4501
  const child = spawn7(isWindows ? "cmd.exe" : "sh", isWindows ? ["/c", command] : ["-c", command], {
4465
4502
  cwd: ctx.cwd ?? process.cwd(),
@@ -4474,7 +4511,7 @@ async function runOne(entry, ctx) {
4474
4511
  settled = true;
4475
4512
  clearTimeout(killer);
4476
4513
  const blocked = !!entry.blocking && (exitCode === null || exitCode !== 0);
4477
- resolve18({ command, exitCode, stdout, stderr, timedOut, blocked });
4514
+ resolve19({ command, exitCode, stdout, stderr, timedOut, blocked });
4478
4515
  };
4479
4516
  const killer = setTimeout(() => {
4480
4517
  timedOut = true;
@@ -5339,8 +5376,8 @@ var init_Mutex = __esm({
5339
5376
  */
5340
5377
  acquire() {
5341
5378
  let release2;
5342
- const next = new Promise((resolve18) => {
5343
- release2 = resolve18;
5379
+ const next = new Promise((resolve19) => {
5380
+ release2 = resolve19;
5344
5381
  });
5345
5382
  const entry = this._queue.then(() => release2);
5346
5383
  this._queue = this._queue.then(() => next);
@@ -5980,8 +6017,8 @@ var require_graceful_fs = __commonJS({
5980
6017
  fs4.createReadStream = createReadStream;
5981
6018
  fs4.createWriteStream = createWriteStream;
5982
6019
  var fs$readFile = fs4.readFile;
5983
- fs4.readFile = readFile23;
5984
- function readFile23(path2, options, cb) {
6020
+ fs4.readFile = readFile24;
6021
+ function readFile24(path2, options, cb) {
5985
6022
  if (typeof options === "function")
5986
6023
  cb = options, options = null;
5987
6024
  return go$readFile(path2, options, cb);
@@ -5997,8 +6034,8 @@ var require_graceful_fs = __commonJS({
5997
6034
  }
5998
6035
  }
5999
6036
  var fs$writeFile = fs4.writeFile;
6000
- fs4.writeFile = writeFile12;
6001
- function writeFile12(path2, data, options, cb) {
6037
+ fs4.writeFile = writeFile13;
6038
+ function writeFile13(path2, data, options, cb) {
6002
6039
  if (typeof options === "function")
6003
6040
  cb = options, options = null;
6004
6041
  return go$writeFile(path2, data, options, cb);
@@ -7000,12 +7037,12 @@ var require_adapter = __commonJS({
7000
7037
  return newFs;
7001
7038
  }
7002
7039
  function toPromise(method) {
7003
- return (...args2) => new Promise((resolve18, reject) => {
7040
+ return (...args2) => new Promise((resolve19, reject) => {
7004
7041
  args2.push((err, result) => {
7005
7042
  if (err) {
7006
7043
  reject(err);
7007
7044
  } else {
7008
- resolve18(result);
7045
+ resolve19(result);
7009
7046
  }
7010
7047
  });
7011
7048
  method(...args2);
@@ -7933,7 +7970,7 @@ var init_client = __esm({
7933
7970
  if (!this.proc) throw new MCPClientError(`MCP server "${this.name}" not started`);
7934
7971
  const id = this.nextId++;
7935
7972
  const frame = { jsonrpc: "2.0", id, method, params };
7936
- return new Promise((resolve18, reject) => {
7973
+ return new Promise((resolve19, reject) => {
7937
7974
  const timer = setTimeout(() => {
7938
7975
  this.pending.delete(id);
7939
7976
  reject(new MCPClientError(`MCP request ${method} timed out after ${timeoutMs}ms`));
@@ -7941,7 +7978,7 @@ var init_client = __esm({
7941
7978
  this.pending.set(id, {
7942
7979
  resolve: (v) => {
7943
7980
  clearTimeout(timer);
7944
- resolve18(v);
7981
+ resolve19(v);
7945
7982
  },
7946
7983
  reject: (e) => {
7947
7984
  clearTimeout(timer);
@@ -7968,7 +8005,7 @@ var init_client = __esm({
7968
8005
  if (!this.proc?.stdout) return;
7969
8006
  const stdout = this.proc.stdout;
7970
8007
  const decoder = new TextDecoder();
7971
- return new Promise((resolve18) => {
8008
+ return new Promise((resolve19) => {
7972
8009
  stdout.on("data", (chunk) => {
7973
8010
  this.buffer += decoder.decode(chunk, { stream: true });
7974
8011
  let idx;
@@ -7979,8 +8016,8 @@ var init_client = __esm({
7979
8016
  this.handleFrame(line);
7980
8017
  }
7981
8018
  });
7982
- stdout.on("end", () => resolve18());
7983
- stdout.on("error", () => resolve18());
8019
+ stdout.on("end", () => resolve19());
8020
+ stdout.on("error", () => resolve19());
7984
8021
  });
7985
8022
  }
7986
8023
  handleFrame(line) {
@@ -8204,7 +8241,7 @@ function setRawModeGuarded(stdin, mode) {
8204
8241
  }
8205
8242
  }
8206
8243
  async function promptPassword(prompt4) {
8207
- return new Promise((resolve18) => {
8244
+ return new Promise((resolve19) => {
8208
8245
  const stdin = process.stdin;
8209
8246
  const stdout = process.stdout;
8210
8247
  stdout.write(prompt4);
@@ -8217,12 +8254,12 @@ async function promptPassword(prompt4) {
8217
8254
  setRawModeGuarded(stdin, wasRaw);
8218
8255
  stdin.removeListener("data", onData);
8219
8256
  stdout.write("\n");
8220
- resolve18(password);
8257
+ resolve19(password);
8221
8258
  } else if (char === "") {
8222
8259
  setRawModeGuarded(stdin, wasRaw);
8223
8260
  stdin.removeListener("data", onData);
8224
8261
  stdout.write("\n");
8225
- resolve18("");
8262
+ resolve19("");
8226
8263
  } else if (char === "\x7F" || char === "\b") {
8227
8264
  password = password.slice(0, -1);
8228
8265
  } else if (char >= " " && char <= "~") {
@@ -8301,7 +8338,7 @@ async function loginWithGithubDevice(context) {
8301
8338
  const deadline = Date.now() + expires_in * 1e3;
8302
8339
  let githubToken = null;
8303
8340
  while (Date.now() < deadline) {
8304
- await new Promise((resolve18) => setTimeout(resolve18, pollMs));
8341
+ await new Promise((resolve19) => setTimeout(resolve19, pollMs));
8305
8342
  let tokenResp;
8306
8343
  try {
8307
8344
  tokenResp = await fetch(GITHUB_TOKEN_URL, {
@@ -8325,7 +8362,7 @@ async function loginWithGithubDevice(context) {
8325
8362
  if (tokenData.error === "authorization_pending") continue;
8326
8363
  if (tokenData.error === "slow_down") {
8327
8364
  pollMs += 5e3;
8328
- await new Promise((resolve18) => setTimeout(resolve18, 5e3));
8365
+ await new Promise((resolve19) => setTimeout(resolve19, 5e3));
8329
8366
  continue;
8330
8367
  }
8331
8368
  context.addMessage("system", `GitHub auth error: ${tokenData.error_description || tokenData.error}`);
@@ -9051,15 +9088,18 @@ var init_keys = __esm({
9051
9088
  try {
9052
9089
  if (sub === "list" || sub === "status") {
9053
9090
  const s = await context.client.getProviderKeys();
9054
- const providers = s.providers ?? [];
9055
- context.addMessage("system", `Provider Keys (${providers.length}):`);
9056
- for (const p of providers) {
9057
- const tag = p.configured ? "\u2713" : " ";
9058
- const prefix = p.key_prefix ? ` (${p.key_prefix}\u2026)` : "";
9059
- context.addMessage("system", ` [${tag}] ${p.provider}${prefix}`);
9091
+ const entries = Object.entries(s).filter(
9092
+ ([k]) => !["providers", "status"].includes(k)
9093
+ );
9094
+ const configured = entries.filter(([, v]) => v?.has_key).length;
9095
+ context.addMessage("system", `Provider Keys (${configured}/${entries.length} configured):`);
9096
+ for (const [provider, info] of entries) {
9097
+ const tag = info?.has_key ? "\u2713" : " ";
9098
+ const masked = info?.masked ? ` (${info.masked})` : "";
9099
+ context.addMessage("system", ` [${tag}] ${provider}${masked}`);
9060
9100
  }
9061
- if (providers.length === 0) {
9062
- context.addMessage("system", " (none \u2014 add via /keys add <provider> <key>)");
9101
+ if (entries.length === 0) {
9102
+ context.addMessage("system", " (no providers returned by backend)");
9063
9103
  }
9064
9104
  return;
9065
9105
  }
@@ -9150,6 +9190,135 @@ var init_memories = __esm({
9150
9190
  }
9151
9191
  });
9152
9192
 
9193
+ // src/commands/mdrive.ts
9194
+ import { readFile as readFile14, writeFile as writeFile7 } from "fs/promises";
9195
+ import { existsSync as existsSync15 } from "fs";
9196
+ import { basename, resolve as resolve14 } from "path";
9197
+ function formatBytes(b) {
9198
+ if (!b) return "0";
9199
+ if (b < 1024) return `${b}`;
9200
+ if (b < 1024 * 1024) return `${(b / 1024).toFixed(1)}K`;
9201
+ return `${(b / 1024 / 1024).toFixed(1)}M`;
9202
+ }
9203
+ var mdriveCommand;
9204
+ var init_mdrive = __esm({
9205
+ "src/commands/mdrive.ts"() {
9206
+ "use strict";
9207
+ init_esm_shims();
9208
+ mdriveCommand = {
9209
+ name: "mdrive",
9210
+ args: "[ls|cat|put|get|rm|mv|mkdir] [...args]",
9211
+ description: "Browse and manage files on MSapling Drive (your AI-native context storage).",
9212
+ category: "project",
9213
+ handler: async (args2, context) => {
9214
+ const sub = (args2[0] ?? "ls").toLowerCase();
9215
+ const rest = args2.slice(1);
9216
+ try {
9217
+ if (sub === "ls" || sub === "list") {
9218
+ const path2 = rest[0] || ".";
9219
+ const res = await context.client.mdriveList(path2);
9220
+ const entries = res.entries ?? res.files ?? res.items ?? [];
9221
+ context.addMessage("system", `MDrive: ${path2} (${entries.length} entries)`);
9222
+ for (const e of entries) {
9223
+ const type = e.is_dir || e.type === "dir" ? "d" : "-";
9224
+ const size = e.size != null ? formatBytes(e.size).padStart(6) : " -";
9225
+ const name = e.name ?? e.path ?? "?";
9226
+ context.addMessage("system", ` ${type} ${size} ${name}`);
9227
+ }
9228
+ return;
9229
+ }
9230
+ if (sub === "cat" || sub === "read") {
9231
+ const p = rest[0];
9232
+ if (!p) {
9233
+ context.addMessage("system", "Usage: /mdrive cat <path>");
9234
+ return;
9235
+ }
9236
+ const res = await context.client.mdriveRead(p);
9237
+ context.addMessage("system", res.content ?? res.body ?? "(no content)");
9238
+ return;
9239
+ }
9240
+ if (sub === "put" || sub === "upload" || sub === "write") {
9241
+ const local = rest[0];
9242
+ const remote = rest[1] || (local ? basename(local) : "");
9243
+ if (!local || !remote) {
9244
+ context.addMessage("system", "Usage: /mdrive put <local> [<remote>]");
9245
+ return;
9246
+ }
9247
+ const absLocal = resolve14(local);
9248
+ if (!existsSync15(absLocal)) {
9249
+ context.addMessage("error", `Local file not found: ${absLocal}`);
9250
+ return;
9251
+ }
9252
+ const content = await readFile14(absLocal, "utf8");
9253
+ const res = await context.client.mdriveWrite(remote, content);
9254
+ context.addMessage("system", `Uploaded ${absLocal} \u2192 mdrive:${remote} (${formatBytes(content.length)}, hash=${res?.hash?.slice(0, 12) ?? "?"})`);
9255
+ return;
9256
+ }
9257
+ if (sub === "get" || sub === "download" || sub === "pull") {
9258
+ const remote = rest[0];
9259
+ const local = rest[1];
9260
+ if (!remote) {
9261
+ context.addMessage("system", "Usage: /mdrive get <remote> [<local>]");
9262
+ return;
9263
+ }
9264
+ const res = await context.client.mdriveRead(remote);
9265
+ const content = res.content ?? res.body ?? "";
9266
+ if (local) {
9267
+ await writeFile7(resolve14(local), content, "utf8");
9268
+ context.addMessage("system", `Wrote ${resolve14(local)} (${formatBytes(content.length)})`);
9269
+ } else {
9270
+ context.addMessage("system", content);
9271
+ }
9272
+ return;
9273
+ }
9274
+ if (sub === "rm" || sub === "delete" || sub === "del") {
9275
+ const p = rest[0];
9276
+ if (!p) {
9277
+ context.addMessage("system", "Usage: /mdrive rm <path>");
9278
+ return;
9279
+ }
9280
+ await context.client.mdriveDelete(p);
9281
+ context.addMessage("system", `Deleted mdrive:${p}`);
9282
+ return;
9283
+ }
9284
+ if (sub === "mv" || sub === "rename") {
9285
+ const p = rest[0];
9286
+ const newName = rest[1];
9287
+ if (!p || !newName) {
9288
+ context.addMessage("system", "Usage: /mdrive mv <path> <new-name>");
9289
+ return;
9290
+ }
9291
+ await context.client.mdriveRename(p, newName);
9292
+ context.addMessage("system", `Renamed mdrive:${p} \u2192 ${newName}`);
9293
+ return;
9294
+ }
9295
+ if (sub === "mkdir") {
9296
+ const p = rest[0];
9297
+ if (!p) {
9298
+ context.addMessage("system", "Usage: /mdrive mkdir <path>");
9299
+ return;
9300
+ }
9301
+ await context.client.mdriveMkdir(p);
9302
+ context.addMessage("system", `Created mdrive:${p}/`);
9303
+ return;
9304
+ }
9305
+ context.addMessage("error", `Unknown /mdrive subcommand '${sub}'. Try: ls, cat, put, get, rm, mv, mkdir.`);
9306
+ } catch (e) {
9307
+ const msg = String(e?.message ?? e);
9308
+ if (msg.includes("Invalid or revoked API key") || msg.includes("401")) {
9309
+ context.addMessage(
9310
+ "error",
9311
+ 'MDrive requires a paid account + MDrive API key. Generate one at https://msapling.com/settings \u2192 API Keys \u2192 "Create MDrive Key", then run /keys add mdrive <key>.'
9312
+ );
9313
+ } else {
9314
+ context.addMessage("error", `MDrive: ${msg}`);
9315
+ }
9316
+ }
9317
+ }
9318
+ };
9319
+ }
9320
+ });
9321
+
9153
9322
  // src/commands/clear.ts
9154
9323
  var clearCommand;
9155
9324
  var init_clear = __esm({
@@ -9175,13 +9344,13 @@ var init_clear = __esm({
9175
9344
  // src/commands/mode.ts
9176
9345
  import { homedir as homedir10 } from "os";
9177
9346
  import { join as join17 } from "path";
9178
- import { existsSync as existsSync15 } from "fs";
9179
- import { readFile as readFile14, writeFile as writeFile7, mkdir as mkdir7 } from "fs/promises";
9347
+ import { existsSync as existsSync16 } from "fs";
9348
+ import { readFile as readFile15, writeFile as writeFile8, mkdir as mkdir7 } from "fs/promises";
9180
9349
  async function persistApprovalMode(mode, ttlMs) {
9181
9350
  try {
9182
9351
  let existing = {};
9183
- if (existsSync15(SETTINGS_PATH)) {
9184
- const text = await readFile14(SETTINGS_PATH, "utf8");
9352
+ if (existsSync16(SETTINGS_PATH)) {
9353
+ const text = await readFile15(SETTINGS_PATH, "utf8");
9185
9354
  if (text.trim()) {
9186
9355
  existing = JSON.parse(text);
9187
9356
  }
@@ -9193,10 +9362,10 @@ async function persistApprovalMode(mode, ttlMs) {
9193
9362
  };
9194
9363
  existing.approvalMode = entry;
9195
9364
  const settingsDir = join17(homedir10(), ".msapling");
9196
- if (!existsSync15(settingsDir)) {
9365
+ if (!existsSync16(settingsDir)) {
9197
9366
  await mkdir7(settingsDir, { recursive: true });
9198
9367
  }
9199
- await writeFile7(SETTINGS_PATH, JSON.stringify(existing, null, 2), "utf8");
9368
+ await writeFile8(SETTINGS_PATH, JSON.stringify(existing, null, 2), "utf8");
9200
9369
  } catch {
9201
9370
  }
9202
9371
  }
@@ -9581,8 +9750,8 @@ var init_compact = __esm({
9581
9750
 
9582
9751
  // src/commands/init.ts
9583
9752
  import { join as join18 } from "path";
9584
- import { existsSync as existsSync16 } from "fs";
9585
- import { writeFile as writeFile8 } from "fs/promises";
9753
+ import { existsSync as existsSync17 } from "fs";
9754
+ import { writeFile as writeFile9 } from "fs/promises";
9586
9755
  var initCommand;
9587
9756
  var init_init = __esm({
9588
9757
  "src/commands/init.ts"() {
@@ -9596,7 +9765,7 @@ var init_init = __esm({
9596
9765
  try {
9597
9766
  const cwd = process.cwd();
9598
9767
  const path2 = join18(cwd, "MSAPLING.md");
9599
- if (existsSync16(path2)) {
9768
+ if (existsSync17(path2)) {
9600
9769
  context.addMessage("error", "MSAPLING.md already exists in current directory.");
9601
9770
  return;
9602
9771
  }
@@ -9611,7 +9780,7 @@ var init_init = __esm({
9611
9780
  ## Guidelines
9612
9781
  - Follow existing code style.
9613
9782
  `;
9614
- await writeFile8(path2, content, "utf8");
9783
+ await writeFile9(path2, content, "utf8");
9615
9784
  context.addMessage("system", `Created MSAPLING.md at ${path2}`);
9616
9785
  } catch (e) {
9617
9786
  context.addMessage("error", `Failed to initialize project: ${e.message}`);
@@ -9622,8 +9791,8 @@ var init_init = __esm({
9622
9791
  });
9623
9792
 
9624
9793
  // src/commands/review.ts
9625
- import { existsSync as existsSync17 } from "fs";
9626
- import { readFile as readFile15 } from "fs/promises";
9794
+ import { existsSync as existsSync18 } from "fs";
9795
+ import { readFile as readFile16 } from "fs/promises";
9627
9796
  var reviewCommand;
9628
9797
  var init_review = __esm({
9629
9798
  "src/commands/review.ts"() {
@@ -9642,8 +9811,8 @@ var init_review = __esm({
9642
9811
  }
9643
9812
  let content = "";
9644
9813
  try {
9645
- if (existsSync17(target)) {
9646
- content = await readFile15(target, "utf8");
9814
+ if (existsSync18(target)) {
9815
+ content = await readFile16(target, "utf8");
9647
9816
  } else {
9648
9817
  content = `Review target: ${target}`;
9649
9818
  }
@@ -9736,15 +9905,15 @@ var init_swarm = __esm({
9736
9905
 
9737
9906
  // src/commands/recipe.ts
9738
9907
  import { parse as parseYaml } from "yaml";
9739
- import { existsSync as existsSync18 } from "fs";
9740
- import { readFile as readFile16 } from "fs/promises";
9908
+ import { existsSync as existsSync19 } from "fs";
9909
+ import { readFile as readFile17 } from "fs/promises";
9741
9910
  import { join as join19 } from "path";
9742
9911
  function findRecipe(name, cwd) {
9743
9912
  for (const dir of RECIPE_DIRS) {
9744
9913
  for (const suffix of NAME_SUFFIXES) {
9745
9914
  for (const ext of FILE_EXTS) {
9746
9915
  const p = join19(cwd, dir, `${name}${suffix}${ext}`);
9747
- if (existsSync18(p)) return p;
9916
+ if (existsSync19(p)) return p;
9748
9917
  }
9749
9918
  }
9750
9919
  }
@@ -9803,7 +9972,7 @@ var init_recipe = __esm({
9803
9972
  let text;
9804
9973
  let recipe;
9805
9974
  try {
9806
- text = await readFile16(path2, "utf8");
9975
+ text = await readFile17(path2, "utf8");
9807
9976
  recipe = parseYaml(text);
9808
9977
  } catch (e) {
9809
9978
  context.addMessage("error", `Failed to load ${path2}: ${e.message}`);
@@ -9857,13 +10026,13 @@ ${rendered}` : rendered;
9857
10026
  });
9858
10027
 
9859
10028
  // src/commands/skill.ts
9860
- import { existsSync as existsSync19, readdirSync as readdirSync2, statSync as statSync5 } from "fs";
9861
- import { readFile as readFile17 } from "fs/promises";
9862
- import { join as join20, resolve as resolve14 } from "path";
10029
+ import { existsSync as existsSync20, readdirSync as readdirSync2, statSync as statSync5 } from "fs";
10030
+ import { readFile as readFile18 } from "fs/promises";
10031
+ import { join as join20, resolve as resolve15 } from "path";
9863
10032
  function findSkillsRoot(cwd) {
9864
10033
  for (const candidate of SKILLS_DIRS) {
9865
- const full = resolve14(cwd, candidate);
9866
- if (existsSync19(full) && statSync5(full).isDirectory()) return full;
10034
+ const full = resolve15(cwd, candidate);
10035
+ if (existsSync20(full) && statSync5(full).isDirectory()) return full;
9867
10036
  }
9868
10037
  return null;
9869
10038
  }
@@ -9957,7 +10126,7 @@ var init_skill = __esm({
9957
10126
  }
9958
10127
  let body;
9959
10128
  try {
9960
- body = await readFile17(skill.path, "utf8");
10129
+ body = await readFile18(skill.path, "utf8");
9961
10130
  } catch (e) {
9962
10131
  context.addMessage("error", `Failed to load skill ${skill.path}: ${e.message}`);
9963
10132
  return;
@@ -10353,21 +10522,21 @@ var init_theme = __esm({
10353
10522
  // src/commands/theme.ts
10354
10523
  import { join as join22 } from "path";
10355
10524
  import { homedir as homedir12 } from "os";
10356
- import { existsSync as existsSync20 } from "fs";
10357
- import { readFile as readFile18, writeFile as writeFile9 } from "fs/promises";
10525
+ import { existsSync as existsSync21 } from "fs";
10526
+ import { readFile as readFile19, writeFile as writeFile10 } from "fs/promises";
10358
10527
  async function persistTheme(storage, themeName) {
10359
10528
  const settingsPath = join22(homedir12(), ".msapling", "settings.json");
10360
10529
  let existing = {};
10361
10530
  try {
10362
- if (existsSync20(settingsPath)) {
10363
- const text = await readFile18(settingsPath, "utf8");
10531
+ if (existsSync21(settingsPath)) {
10532
+ const text = await readFile19(settingsPath, "utf8");
10364
10533
  if (text.trim()) existing = JSON.parse(text);
10365
10534
  }
10366
10535
  } catch {
10367
10536
  }
10368
10537
  existing["theme"] = themeName;
10369
10538
  ensureConfigDir(join22(homedir12(), ".msapling"));
10370
- await writeFile9(settingsPath, JSON.stringify(existing, null, 2), "utf8");
10539
+ await writeFile10(settingsPath, JSON.stringify(existing, null, 2), "utf8");
10371
10540
  }
10372
10541
  var VALID_THEMES, themeCommand;
10373
10542
  var init_theme2 = __esm({
@@ -10438,7 +10607,7 @@ var init_version = __esm({
10438
10607
  description: "Show version information for CLI and core packages",
10439
10608
  category: "debug",
10440
10609
  handler: async (_args, context) => {
10441
- const cliVersion = true ? "2.3.6-beta.24" : "(dev)";
10610
+ const cliVersion = true ? "2.3.6-beta.26" : "(dev)";
10442
10611
  const coreVersion = true ? "2.3.2" : "(dev)";
10443
10612
  const runtime = process.version;
10444
10613
  context.addMessage("system", "MSapling Version Info");
@@ -10447,7 +10616,7 @@ var init_version = __esm({
10447
10616
  context.addMessage("system", row2("Core (@msapling/core)", coreVersion));
10448
10617
  context.addMessage("system", row2("Runtime (Node/Bun)", runtime));
10449
10618
  try {
10450
- const ts = "2026-05-28T19:31:59.228Z";
10619
+ const ts = "2026-05-28T23:01:36.725Z";
10451
10620
  if (ts && ts !== "__BUILD_TIMESTAMP__") {
10452
10621
  context.addMessage("system", row2("Build Timestamp", ts));
10453
10622
  }
@@ -10461,14 +10630,14 @@ var init_version = __esm({
10461
10630
 
10462
10631
  // src/commands/feedback.ts
10463
10632
  import { join as join23 } from "path";
10464
- import { existsSync as existsSync21 } from "fs";
10465
- import { readFile as readFile19 } from "fs/promises";
10633
+ import { existsSync as existsSync22 } from "fs";
10634
+ import { readFile as readFile20 } from "fs/promises";
10466
10635
  async function readCliVersion() {
10467
10636
  try {
10468
10637
  const baseDir = typeof __dirname !== "undefined" ? __dirname : process.cwd();
10469
10638
  const pkgPath = join23(baseDir, "..", "..", "package.json");
10470
- if (!existsSync21(pkgPath)) return "unknown";
10471
- const text = await readFile19(pkgPath, "utf8");
10639
+ if (!existsSync22(pkgPath)) return "unknown";
10640
+ const text = await readFile20(pkgPath, "utf8");
10472
10641
  const json = JSON.parse(text);
10473
10642
  return json.version ?? "unknown";
10474
10643
  } catch {
@@ -10510,7 +10679,7 @@ var init_feedback = __esm({
10510
10679
  // src/commands/export.ts
10511
10680
  import { homedir as homedir13 } from "os";
10512
10681
  import { join as join24 } from "path";
10513
- import { writeFile as writeFile10, mkdir as mkdir8 } from "fs/promises";
10682
+ import { writeFile as writeFile11, mkdir as mkdir8 } from "fs/promises";
10514
10683
  function formatTimestamp(date) {
10515
10684
  return date.toISOString().replace(/[:.]/g, "-").replace("T", "_").slice(0, 19);
10516
10685
  }
@@ -10576,7 +10745,7 @@ var init_export = __esm({
10576
10745
  try {
10577
10746
  const dir = join24(outputPath, "..");
10578
10747
  await mkdir8(dir, { recursive: true });
10579
- await writeFile10(outputPath, content, "utf8");
10748
+ await writeFile11(outputPath, content, "utf8");
10580
10749
  context.addMessage("system", `Exported to: ${outputPath}`);
10581
10750
  } catch (e) {
10582
10751
  context.addMessage("error", `Failed to export: ${e.message}`);
@@ -10771,15 +10940,15 @@ var init_plan = __esm({
10771
10940
  // src/commands/note.ts
10772
10941
  import { homedir as homedir14 } from "os";
10773
10942
  import { join as join25 } from "path";
10774
- import { existsSync as existsSync22 } from "fs";
10775
- import { readFile as readFile20, writeFile as writeFile11 } from "fs/promises";
10943
+ import { existsSync as existsSync23 } from "fs";
10944
+ import { readFile as readFile21, writeFile as writeFile12 } from "fs/promises";
10776
10945
  function getNotesFilePath() {
10777
10946
  return join25(homedir14(), ".msapling", "notes.json");
10778
10947
  }
10779
10948
  async function readNotes(filePath = getNotesFilePath()) {
10780
10949
  try {
10781
- if (!existsSync22(filePath)) return [];
10782
- const raw = await readFile20(filePath, "utf8");
10950
+ if (!existsSync23(filePath)) return [];
10951
+ const raw = await readFile21(filePath, "utf8");
10783
10952
  const parsed = JSON.parse(raw);
10784
10953
  if (!Array.isArray(parsed)) return [];
10785
10954
  return parsed;
@@ -10790,7 +10959,7 @@ async function readNotes(filePath = getNotesFilePath()) {
10790
10959
  async function writeNotes(notes, filePath = getNotesFilePath()) {
10791
10960
  const dir = join25(homedir14(), ".msapling");
10792
10961
  ensureConfigDir(dir);
10793
- await writeFile11(filePath, JSON.stringify(notes, null, 2), "utf8");
10962
+ await writeFile12(filePath, JSON.stringify(notes, null, 2), "utf8");
10794
10963
  }
10795
10964
  function formatTimestamp2(iso) {
10796
10965
  const d = new Date(iso);
@@ -10935,8 +11104,8 @@ var init_todo = __esm({
10935
11104
 
10936
11105
  // src/commands/outputStyle.ts
10937
11106
  import { homedir as homedir15 } from "os";
10938
- import { join as join26, basename, extname as extname3 } from "path";
10939
- import { existsSync as existsSync23, mkdirSync as mkdirSync5, readdirSync as readdirSync3, readFileSync, writeFileSync as writeFileSync2 } from "fs";
11107
+ import { join as join26, basename as basename2, extname as extname3 } from "path";
11108
+ import { existsSync as existsSync24, mkdirSync as mkdirSync5, readdirSync as readdirSync3, readFileSync, writeFileSync as writeFileSync2 } from "fs";
10940
11109
  function stylesDir() {
10941
11110
  return join26(homedir15(), ".msapling", "output-styles");
10942
11111
  }
@@ -10962,7 +11131,7 @@ function parseStyleFile(text) {
10962
11131
  }
10963
11132
  function listUserStyles() {
10964
11133
  const dir = stylesDir();
10965
- if (!existsSync23(dir)) return [];
11134
+ if (!existsSync24(dir)) return [];
10966
11135
  const out = [];
10967
11136
  for (const entry of readdirSync3(dir)) {
10968
11137
  if (extname3(entry).toLowerCase() !== ".md") continue;
@@ -10971,7 +11140,7 @@ function listUserStyles() {
10971
11140
  const text = readFileSync(full, "utf8");
10972
11141
  const { description, body } = parseStyleFile(text);
10973
11142
  out.push({
10974
- name: basename(entry, ".md"),
11143
+ name: basename2(entry, ".md"),
10975
11144
  description,
10976
11145
  body,
10977
11146
  source: "user",
@@ -10994,7 +11163,7 @@ function findStyle(name) {
10994
11163
  function getActiveStyleName() {
10995
11164
  try {
10996
11165
  const f = activeFile();
10997
- if (!existsSync23(f)) return "default";
11166
+ if (!existsSync24(f)) return "default";
10998
11167
  return readFileSync(f, "utf8").trim() || "default";
10999
11168
  } catch {
11000
11169
  return "default";
@@ -11002,7 +11171,7 @@ function getActiveStyleName() {
11002
11171
  }
11003
11172
  function setActiveStyleName(name) {
11004
11173
  const dir = stylesDir();
11005
- if (!existsSync23(dir)) mkdirSync5(dir, { recursive: true });
11174
+ if (!existsSync24(dir)) mkdirSync5(dir, { recursive: true });
11006
11175
  writeFileSync2(activeFile(), `${name}
11007
11176
  `, "utf8");
11008
11177
  }
@@ -11015,7 +11184,7 @@ function createUserStyle(name, description, body) {
11015
11184
  throw new Error(`Invalid style name "${name}" \u2014 use letters, digits, _ and - only.`);
11016
11185
  }
11017
11186
  const dir = stylesDir();
11018
- if (!existsSync23(dir)) mkdirSync5(dir, { recursive: true });
11187
+ if (!existsSync24(dir)) mkdirSync5(dir, { recursive: true });
11019
11188
  const target = join26(dir, `${name}.md`);
11020
11189
  const frontmatter = `---
11021
11190
  description: ${description.replace(/\n/g, " ")}
@@ -11190,6 +11359,7 @@ var init_commands = __esm({
11190
11359
  init_ollama();
11191
11360
  init_keys();
11192
11361
  init_memories();
11362
+ init_mdrive();
11193
11363
  init_clear();
11194
11364
  init_mode();
11195
11365
  init_model();
@@ -11229,6 +11399,7 @@ var init_commands = __esm({
11229
11399
  ollamaCommand,
11230
11400
  keysCommand,
11231
11401
  memoriesCommand,
11402
+ mdriveCommand,
11232
11403
  clearCommand,
11233
11404
  modeCommand,
11234
11405
  modelCommand,
@@ -11325,16 +11496,16 @@ var exec_exports = {};
11325
11496
  __export(exec_exports, {
11326
11497
  runExec: () => runExec
11327
11498
  });
11328
- import { existsSync as existsSync25 } from "fs";
11329
- import { readFile as readFile22 } from "fs/promises";
11499
+ import { existsSync as existsSync26 } from "fs";
11500
+ import { readFile as readFile23 } from "fs/promises";
11330
11501
  import { homedir as homedir16 } from "os";
11331
11502
  import { join as join27 } from "path";
11332
11503
  async function loadPersistedSettings() {
11333
11504
  const out = { mode: "default", theme: null };
11334
11505
  try {
11335
11506
  const p = join27(homedir16(), ".msapling", "settings.json");
11336
- if (!existsSync25(p)) return out;
11337
- const raw = JSON.parse(await readFile22(p, "utf8"));
11507
+ if (!existsSync26(p)) return out;
11508
+ const raw = JSON.parse(await readFile23(p, "utf8"));
11338
11509
  const parsed = parseApprovalMode(raw, Date.now());
11339
11510
  if (parsed.kind === "ok") out.mode = parsed.mode;
11340
11511
  const themeRaw = raw?.theme;
@@ -11584,13 +11755,13 @@ async function openBrowser(url) {
11584
11755
  cmd = "xdg-open";
11585
11756
  args2 = [url];
11586
11757
  }
11587
- return new Promise((resolve18) => {
11758
+ return new Promise((resolve19) => {
11588
11759
  try {
11589
11760
  const child = spawn10(cmd, args2, { stdio: "ignore", detached: true });
11590
11761
  child.unref();
11591
11762
  } catch {
11592
11763
  }
11593
- resolve18();
11764
+ resolve19();
11594
11765
  });
11595
11766
  }
11596
11767
  var init_open_browser = __esm({
@@ -11680,7 +11851,7 @@ var init_checkout = __esm({
11680
11851
  // src/commands/billing/sub.ts
11681
11852
  import * as readline from "readline";
11682
11853
  function prompt(rl, question) {
11683
- return new Promise((resolve18) => rl.question(question, resolve18));
11854
+ return new Promise((resolve19) => rl.question(question, resolve19));
11684
11855
  }
11685
11856
  async function runSub(argv) {
11686
11857
  const subCmd = argv[0] ?? "";
@@ -11809,11 +11980,11 @@ var init_sub = __esm({
11809
11980
  // src/commands/billing/topup.ts
11810
11981
  import * as readline2 from "readline";
11811
11982
  function prompt2(rl, question) {
11812
- return new Promise((resolve18) => rl.question(question, resolve18));
11983
+ return new Promise((resolve19) => rl.question(question, resolve19));
11813
11984
  }
11814
11985
  function promptDefault(rl, question, defaultVal) {
11815
11986
  return new Promise(
11816
- (resolve18) => rl.question(`${question} [${defaultVal}]: `, (ans) => resolve18(ans.trim() || defaultVal))
11987
+ (resolve19) => rl.question(`${question} [${defaultVal}]: `, (ans) => resolve19(ans.trim() || defaultVal))
11817
11988
  );
11818
11989
  }
11819
11990
  async function runTopup(argv) {
@@ -11954,7 +12125,7 @@ var init_redeem = __esm({
11954
12125
  // src/commands/billing/gift.ts
11955
12126
  import * as readline3 from "readline";
11956
12127
  function prompt3(rl, question) {
11957
- return new Promise((resolve18) => rl.question(question, resolve18));
12128
+ return new Promise((resolve19) => rl.question(question, resolve19));
11958
12129
  }
11959
12130
  async function runGift(argv) {
11960
12131
  const subCmd = argv[0] ?? "";
@@ -12211,7 +12382,7 @@ __export(doctor_exports, {
12211
12382
  });
12212
12383
  import { homedir as homedir17, platform as platform3 } from "os";
12213
12384
  import { join as join28 } from "path";
12214
- import { existsSync as existsSync26, statSync as statSync6, accessSync } from "fs";
12385
+ import { existsSync as existsSync27, statSync as statSync6, accessSync } from "fs";
12215
12386
  import { readdir as readdir3 } from "fs/promises";
12216
12387
  import { exec } from "child_process";
12217
12388
  import { promisify } from "util";
@@ -12235,7 +12406,7 @@ async function checkNodeVersion() {
12235
12406
  }
12236
12407
  async function checkConfigDir() {
12237
12408
  const configDir = join28(homedir17(), ".msapling");
12238
- if (!existsSync26(configDir)) {
12409
+ if (!existsSync27(configDir)) {
12239
12410
  return {
12240
12411
  name: "Config directory",
12241
12412
  status: "WARN",
@@ -12301,7 +12472,7 @@ async function checkPathConflicts() {
12301
12472
  const paths = pathEnv.split(platform3() === "win32" ? ";" : ":");
12302
12473
  const conflicts = [];
12303
12474
  for (const dir of paths) {
12304
- if (!dir || !existsSync26(dir)) continue;
12475
+ if (!dir || !existsSync27(dir)) continue;
12305
12476
  try {
12306
12477
  const files = await readdir3(dir);
12307
12478
  for (const file of files) {
@@ -13723,16 +13894,16 @@ var init_registry_merger = __esm({
13723
13894
  // ../core/src/mcp/local_tools.ts
13724
13895
  import { spawn as spawn11 } from "child_process";
13725
13896
  import { readdir as readdir4, stat as stat4, realpath as realpath2 } from "fs/promises";
13726
- import { resolve as resolve16 } from "path";
13897
+ import { resolve as resolve17 } from "path";
13727
13898
  function asResult(text, isError = false) {
13728
13899
  return { content: [{ type: "text", text }], ...isError ? { isError: true } : {} };
13729
13900
  }
13730
13901
  async function runCommand(command, cwd) {
13731
- return new Promise((resolve18) => {
13902
+ return new Promise((resolve19) => {
13732
13903
  let p;
13733
13904
  const timeout = setTimeout(() => {
13734
13905
  if (p) p.kill();
13735
- resolve18({ stdout: "", stderr: "Command timed out after 30s", exit_code: -1 });
13906
+ resolve19({ stdout: "", stderr: "Command timed out after 30s", exit_code: -1 });
13736
13907
  }, 3e4);
13737
13908
  try {
13738
13909
  p = spawn11("sh", ["-c", command], {
@@ -13750,15 +13921,15 @@ async function runCommand(command, cwd) {
13750
13921
  });
13751
13922
  p.on("error", (e) => {
13752
13923
  clearTimeout(timeout);
13753
- resolve18({ stdout, stderr: stderr + (e?.message ?? ""), exit_code: -1 });
13924
+ resolve19({ stdout, stderr: stderr + (e?.message ?? ""), exit_code: -1 });
13754
13925
  });
13755
13926
  p.on("exit", (code) => {
13756
13927
  clearTimeout(timeout);
13757
- resolve18({ stdout, stderr, exit_code: code });
13928
+ resolve19({ stdout, stderr, exit_code: code });
13758
13929
  });
13759
13930
  } catch (e) {
13760
13931
  clearTimeout(timeout);
13761
- resolve18({
13932
+ resolve19({
13762
13933
  stdout: "",
13763
13934
  stderr: e?.message ?? "Failed to spawn process",
13764
13935
  exit_code: -1
@@ -13825,7 +13996,7 @@ async function callLocalTool(name, args2, projectRoot) {
13825
13996
  const command = String(args2.command ?? "");
13826
13997
  let cwd = projectRoot;
13827
13998
  if (args2.cwd) {
13828
- cwd = resolve16(projectRoot, String(args2.cwd));
13999
+ cwd = resolve17(projectRoot, String(args2.cwd));
13829
14000
  try {
13830
14001
  const resolvedCwd = await realpath2(cwd);
13831
14002
  const resolvedRoot = await realpath2(projectRoot);
@@ -13862,7 +14033,7 @@ ${res.stderr}`
13862
14033
  return asResult("path is required", true);
13863
14034
  }
13864
14035
  try {
13865
- const resolvedPath = await realpath2(resolve16(projectRoot, pathArg));
14036
+ const resolvedPath = await realpath2(resolve17(projectRoot, pathArg));
13866
14037
  const resolvedRoot = await realpath2(projectRoot);
13867
14038
  if (!resolvedPath.startsWith(resolvedRoot)) {
13868
14039
  return asResult("Error: path attempts to escape project root", true);
@@ -13881,7 +14052,7 @@ ${res.stderr}`
13881
14052
  }
13882
14053
  case "local_glob": {
13883
14054
  const pattern = String(args2.pattern ?? "");
13884
- let cwd = args2.cwd ? resolve16(projectRoot, String(args2.cwd)) : projectRoot;
14055
+ let cwd = args2.cwd ? resolve17(projectRoot, String(args2.cwd)) : projectRoot;
13885
14056
  if (!pattern) {
13886
14057
  return asResult("pattern is required", true);
13887
14058
  }
@@ -13910,7 +14081,7 @@ ${res.stderr}`
13910
14081
  }
13911
14082
  if (path2) {
13912
14083
  try {
13913
- const resolvedPath = await realpath2(resolve16(projectRoot, path2));
14084
+ const resolvedPath = await realpath2(resolve17(projectRoot, path2));
13914
14085
  const resolvedRoot = await realpath2(projectRoot);
13915
14086
  if (!resolvedPath.startsWith(resolvedRoot)) {
13916
14087
  return asResult("Error: path attempts to escape project root", true);
@@ -13930,7 +14101,7 @@ ${res.stderr}`
13930
14101
  return asResult("cwd is required", true);
13931
14102
  }
13932
14103
  try {
13933
- const resolvedCwd = await realpath2(resolve16(projectRoot, cwdArg));
14104
+ const resolvedCwd = await realpath2(resolve17(projectRoot, cwdArg));
13934
14105
  const resolvedRoot = await realpath2(projectRoot);
13935
14106
  if (!resolvedCwd.startsWith(resolvedRoot)) {
13936
14107
  return asResult("Error: cwd attempts to escape project root", true);
@@ -13956,7 +14127,7 @@ ${status.porcelain || "(clean)"}`
13956
14127
  return asResult("cwd is required", true);
13957
14128
  }
13958
14129
  try {
13959
- const resolvedCwd = await realpath2(resolve16(projectRoot, cwdArg));
14130
+ const resolvedCwd = await realpath2(resolve17(projectRoot, cwdArg));
13960
14131
  const resolvedRoot = await realpath2(projectRoot);
13961
14132
  if (!resolvedCwd.startsWith(resolvedRoot)) {
13962
14133
  return asResult("Error: cwd attempts to escape project root", true);
@@ -14072,7 +14243,7 @@ __export(server_exports, {
14072
14243
  runStdioWithRegistry: () => runStdioWithRegistry
14073
14244
  });
14074
14245
  import { readdirSync as readdirSync4, readFileSync as readFileSync2, statSync as statSync7 } from "fs";
14075
- import { join as join29, relative as relative14, resolve as resolve17 } from "path";
14246
+ import { join as join29, relative as relative14, resolve as resolve18 } from "path";
14076
14247
  function asResult2(text, isError = false) {
14077
14248
  return { content: [{ type: "text", text }], ...isError ? { isError: true } : {} };
14078
14249
  }
@@ -14430,13 +14601,13 @@ var init_server = __esm({
14430
14601
  if (inflight === 0) {
14431
14602
  return [];
14432
14603
  }
14433
- const forcedResponses = await new Promise((resolve18) => {
14434
- this._drainResolve = () => resolve18([]);
14604
+ const forcedResponses = await new Promise((resolve19) => {
14605
+ this._drainResolve = () => resolve19([]);
14435
14606
  setTimeout(() => {
14436
14607
  this._drainResolve = null;
14437
14608
  const remaining = Array.from(this._inflightCalls.values());
14438
14609
  if (remaining.length === 0) {
14439
- resolve18([]);
14610
+ resolve19([]);
14440
14611
  return;
14441
14612
  }
14442
14613
  process.stderr.write(
@@ -14452,7 +14623,7 @@ var init_server = __esm({
14452
14623
  }
14453
14624
  }));
14454
14625
  this._inflightCalls.clear();
14455
- resolve18(errorResponses);
14626
+ resolve19(errorResponses);
14456
14627
  }, DRAIN_TIMEOUT_MS);
14457
14628
  });
14458
14629
  return forcedResponses;
@@ -14730,7 +14901,7 @@ ${r.response ?? ""}`;
14730
14901
  return asResult2(JSON.stringify(result));
14731
14902
  }
14732
14903
  case "msapling_project_context": {
14733
- const root = resolve17(String(args2.path ?? "."));
14904
+ const root = resolve18(String(args2.path ?? "."));
14734
14905
  const maxFiles = Number.isFinite(args2.max_files) ? Number(args2.max_files) : 30;
14735
14906
  const maxKB = Number.isFinite(args2.max_file_size_kb) ? Number(args2.max_file_size_kb) : 50;
14736
14907
  const files = buildFileTree(root, maxFiles);
@@ -14858,7 +15029,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
14858
15029
  var Header = () => /* @__PURE__ */ jsxs(Box, { borderStyle: "single", borderColor: "cyan", paddingX: 1, marginBottom: 1, children: [
14859
15030
  /* @__PURE__ */ jsxs(Text, { bold: true, color: "cyan", children: [
14860
15031
  "\u25CF MSapling CLI v",
14861
- "2.3.6-beta.24"
15032
+ "2.3.6-beta.26"
14862
15033
  ] }),
14863
15034
  /* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "Platinum Tier Architecture" }) })
14864
15035
  ] });
@@ -15352,9 +15523,9 @@ ${prompt4}` : prompt4;
15352
15523
  if (proc.stderr) proc.stderr.on("data", (chunk) => {
15353
15524
  stderr += chunk.toString();
15354
15525
  });
15355
- await new Promise((resolve18, reject) => {
15526
+ await new Promise((resolve19, reject) => {
15356
15527
  proc.on("close", (code) => {
15357
- if (code === 0 || code === null) resolve18();
15528
+ if (code === 0 || code === null) resolve19();
15358
15529
  else reject(new Error(`Process exited with code ${code}`));
15359
15530
  });
15360
15531
  proc.on("error", reject);
@@ -15381,10 +15552,10 @@ ${prompt4}` : prompt4;
15381
15552
  for (const mention of fileMentions) {
15382
15553
  const filePath = mention.slice(1);
15383
15554
  try {
15384
- const { existsSync: existsSync27 } = await import("fs");
15385
- const { readFile: readFile23 } = await import("fs/promises");
15386
- if (existsSync27(filePath)) {
15387
- const content = await readFile23(filePath, "utf8");
15555
+ const { existsSync: existsSync28 } = await import("fs");
15556
+ const { readFile: readFile24 } = await import("fs/promises");
15557
+ if (existsSync28(filePath)) {
15558
+ const content = await readFile24(filePath, "utf8");
15388
15559
  const MAX_LEN = 32768;
15389
15560
  const truncated = content.length > MAX_LEN ? content.slice(0, MAX_LEN) + "\n...[TRUNCATED]" : content;
15390
15561
  finalCmd += `
@@ -15436,8 +15607,8 @@ ${finalCmd}`;
15436
15607
  init_esm_shims();
15437
15608
  init_src3();
15438
15609
  init_parseApprovalMode();
15439
- import { readFile as readFile21 } from "fs/promises";
15440
- import { existsSync as existsSync24 } from "fs";
15610
+ import { readFile as readFile22 } from "fs/promises";
15611
+ import { existsSync as existsSync25 } from "fs";
15441
15612
  async function initSession(ctx) {
15442
15613
  try {
15443
15614
  const { settings } = await loadSettings(
@@ -15454,8 +15625,8 @@ async function initSession(ctx) {
15454
15625
  const { homedir: homedir18 } = await import("os");
15455
15626
  const { join: join31 } = await import("path");
15456
15627
  const userSettingsPath = join31(homedir18(), ".msapling", "settings.json");
15457
- if (existsSync24(userSettingsPath)) {
15458
- const userText = await readFile21(userSettingsPath, "utf8");
15628
+ if (existsSync25(userSettingsPath)) {
15629
+ const userText = await readFile22(userSettingsPath, "utf8");
15459
15630
  let parsed;
15460
15631
  try {
15461
15632
  parsed = JSON.parse(userText);
@@ -15555,8 +15726,8 @@ var App = ({ compact: compact2 = false }) => {
15555
15726
  const storage = useRef(new StorageManager()).current;
15556
15727
  const client = useRef(new MSaplingClient()).current;
15557
15728
  const requestApproval = useCallback((request) => {
15558
- return new Promise((resolve18) => {
15559
- setPendingApproval({ request, resolve: resolve18 });
15729
+ return new Promise((resolve19) => {
15730
+ setPendingApproval({ request, resolve: resolve19 });
15560
15731
  });
15561
15732
  }, []);
15562
15733
  const agent = useRef(new Agent(client, process.cwd(), requestApproval)).current;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mtreeai/msapling-cli",
3
- "version": "2.3.6-beta.24",
3
+ "version": "2.3.6-beta.26",
4
4
  "description": "MSapling CLI — React/Ink terminal client for the MSapling backend (chat, projects, MDrive, agent tools). Proprietary; redistribution prohibited.",
5
5
  "license": "UNLICENSED",
6
6
  "author": "MSapling Team",