@mtreeai/msapling-cli 2.3.6-beta.16 → 2.3.6-beta.17

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 +131 -94
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3627,20 +3627,20 @@ async function copyDir(src, dst) {
3627
3627
  }
3628
3628
  async function backupFile(absPath) {
3629
3629
  try {
3630
- const { readFile: readFile22, writeFile: writeFile12, mkdir: mkdir9 } = await import("fs/promises");
3631
- const { homedir: homedir17 } = await import("os");
3632
- const { join: join30 } = await import("path");
3630
+ const { readFile: readFile23, writeFile: writeFile12, mkdir: mkdir9 } = await import("fs/promises");
3631
+ const { homedir: homedir18 } = await import("os");
3632
+ const { join: join31 } = await import("path");
3633
3633
  const filename = absPath.split(/[\\/]/).pop() ?? "file";
3634
3634
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
3635
3635
  const suffix = randomBytes5(4).toString("hex");
3636
- const backupPath = join30(
3637
- homedir17(),
3636
+ const backupPath = join31(
3637
+ homedir18(),
3638
3638
  ".msapling",
3639
3639
  "backups",
3640
3640
  `${filename}.backup-${stamp}-${suffix}.bak`
3641
3641
  );
3642
- await mkdir9(join30(homedir17(), ".msapling", "backups"), { recursive: true });
3643
- const content = await readFile22(absPath, "utf8");
3642
+ await mkdir9(join31(homedir18(), ".msapling", "backups"), { recursive: true });
3643
+ const content = await readFile23(absPath, "utf8");
3644
3644
  await writeFile12(backupPath, content, "utf8");
3645
3645
  return backupPath;
3646
3646
  } catch {
@@ -3866,14 +3866,14 @@ var init_DeleteFileTool = __esm({
3866
3866
  let backedUpTo = null;
3867
3867
  if (isFile) {
3868
3868
  try {
3869
- const { readFile: readFile22, writeFile: writeFile12, mkdir: mkdir9 } = await import("fs/promises");
3870
- const { homedir: homedir17 } = await import("os");
3871
- const existingContent = await readFile22(abs, "utf8");
3869
+ const { readFile: readFile23, writeFile: writeFile12, mkdir: mkdir9 } = await import("fs/promises");
3870
+ const { homedir: homedir18 } = await import("os");
3871
+ const existingContent = await readFile23(abs, "utf8");
3872
3872
  const filename = abs.split(/[\\/]/).pop() ?? "file";
3873
3873
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
3874
3874
  const suffix = randomBytes6(4).toString("hex");
3875
- const backupPath = join11(homedir17(), ".msapling", "backups", `${filename}.backup-${stamp}-${suffix}.bak`);
3876
- await mkdir9(join11(homedir17(), ".msapling", "backups"), { recursive: true });
3875
+ const backupPath = join11(homedir18(), ".msapling", "backups", `${filename}.backup-${stamp}-${suffix}.bak`);
3876
+ await mkdir9(join11(homedir18(), ".msapling", "backups"), { recursive: true });
3877
3877
  await writeFile12(backupPath, existingContent, "utf8");
3878
3878
  backedUpTo = backupPath;
3879
3879
  } catch {
@@ -5841,8 +5841,8 @@ var require_graceful_fs = __commonJS({
5841
5841
  fs4.createReadStream = createReadStream;
5842
5842
  fs4.createWriteStream = createWriteStream;
5843
5843
  var fs$readFile = fs4.readFile;
5844
- fs4.readFile = readFile22;
5845
- function readFile22(path2, options, cb) {
5844
+ fs4.readFile = readFile23;
5845
+ function readFile23(path2, options, cb) {
5846
5846
  if (typeof options === "function")
5847
5847
  cb = options, options = null;
5848
5848
  return go$readFile(path2, options, cb);
@@ -9691,7 +9691,7 @@ var init_version = __esm({
9691
9691
  description: "Show version information for CLI and core packages",
9692
9692
  category: "debug",
9693
9693
  handler: async (_args, context) => {
9694
- const cliVersion = true ? "2.3.6-beta.16" : "(dev)";
9694
+ const cliVersion = true ? "2.3.6-beta.17" : "(dev)";
9695
9695
  const coreVersion = true ? "2.3.2" : "(dev)";
9696
9696
  const runtime = process.version;
9697
9697
  context.addMessage("system", "MSapling Version Info");
@@ -9700,7 +9700,7 @@ var init_version = __esm({
9700
9700
  context.addMessage("system", row2("Core (@msapling/core)", coreVersion));
9701
9701
  context.addMessage("system", row2("Runtime (Node/Bun)", runtime));
9702
9702
  try {
9703
- const ts = "2026-05-28T15:34:41.643Z";
9703
+ const ts = "2026-05-28T16:29:43.918Z";
9704
9704
  if (ts && ts !== "__BUILD_TIMESTAMP__") {
9705
9705
  context.addMessage("system", row2("Build Timestamp", ts));
9706
9706
  }
@@ -10504,11 +10504,91 @@ var init_commands = __esm({
10504
10504
  }
10505
10505
  });
10506
10506
 
10507
+ // src/state/parseApprovalMode.ts
10508
+ function parseApprovalMode(raw, now) {
10509
+ if (!raw || typeof raw !== "object") {
10510
+ return { kind: "invalid", error: "settings file is not a JSON object" };
10511
+ }
10512
+ const block = raw.approvalMode;
10513
+ if (block === void 0) return { kind: "absent" };
10514
+ if (typeof block === "string") {
10515
+ if (!VALID_MODES.includes(block)) {
10516
+ return { kind: "invalid", error: `unknown approvalMode "${block}"` };
10517
+ }
10518
+ return { kind: "ok", mode: block };
10519
+ }
10520
+ if (typeof block !== "object" || block === null) {
10521
+ return {
10522
+ kind: "invalid",
10523
+ error: `approvalMode must be a string or object, got ${typeof block}`
10524
+ };
10525
+ }
10526
+ const obj = block;
10527
+ const mode = obj.mode;
10528
+ if (typeof mode !== "string" || !VALID_MODES.includes(mode)) {
10529
+ return { kind: "invalid", error: `approvalMode.mode invalid: ${JSON.stringify(mode)}` };
10530
+ }
10531
+ if (mode !== "bypassPermissions") {
10532
+ return { kind: "ok", mode };
10533
+ }
10534
+ if (typeof obj.ttlMs !== "number" || !Number.isFinite(obj.ttlMs) || obj.ttlMs <= 0) {
10535
+ return {
10536
+ kind: "invalid",
10537
+ error: `approvalMode.ttlMs must be a positive number, got ${JSON.stringify(obj.ttlMs)}`
10538
+ };
10539
+ }
10540
+ if (typeof obj.timestamp !== "number" || !Number.isFinite(obj.timestamp) || obj.timestamp <= 0) {
10541
+ return {
10542
+ kind: "invalid",
10543
+ error: `approvalMode.timestamp must be a positive number, got ${JSON.stringify(obj.timestamp)}`
10544
+ };
10545
+ }
10546
+ const age = now - obj.timestamp;
10547
+ if (age > obj.ttlMs) {
10548
+ return { kind: "expired", mode: "default", agedMs: age };
10549
+ }
10550
+ const remainingMs = obj.ttlMs - age;
10551
+ return { kind: "ok", mode: "bypassPermissions", ttl: { remainingMs } };
10552
+ }
10553
+ var VALID_MODES;
10554
+ var init_parseApprovalMode = __esm({
10555
+ "src/state/parseApprovalMode.ts"() {
10556
+ "use strict";
10557
+ init_esm_shims();
10558
+ VALID_MODES = [
10559
+ "default",
10560
+ "plan",
10561
+ "acceptEdits",
10562
+ "bypassPermissions"
10563
+ ];
10564
+ }
10565
+ });
10566
+
10507
10567
  // src/runtime/exec.ts
10508
10568
  var exec_exports = {};
10509
10569
  __export(exec_exports, {
10510
10570
  runExec: () => runExec
10511
10571
  });
10572
+ import { existsSync as existsSync25 } from "fs";
10573
+ import { readFile as readFile22 } from "fs/promises";
10574
+ import { homedir as homedir16 } from "os";
10575
+ import { join as join27 } from "path";
10576
+ async function loadPersistedSettings() {
10577
+ const out = { mode: "default", theme: null };
10578
+ try {
10579
+ const p = join27(homedir16(), ".msapling", "settings.json");
10580
+ if (!existsSync25(p)) return out;
10581
+ const raw = JSON.parse(await readFile22(p, "utf8"));
10582
+ const parsed = parseApprovalMode(raw, Date.now());
10583
+ if (parsed.kind === "ok") out.mode = parsed.mode;
10584
+ const themeRaw = raw?.theme;
10585
+ if (themeRaw === "diamond" || themeRaw === "onyx" || themeRaw === "mono") {
10586
+ out.theme = themeRaw;
10587
+ }
10588
+ } catch {
10589
+ }
10590
+ return out;
10591
+ }
10512
10592
  async function runExec(rawInput) {
10513
10593
  const trimmed = (rawInput || "").trim();
10514
10594
  if (!trimmed) {
@@ -10531,7 +10611,9 @@ async function runExec(rawInput) {
10531
10611
  token: token || void 0
10532
10612
  });
10533
10613
  const stdout = process.stdout;
10534
- let mode = "default";
10614
+ const persisted = await loadPersistedSettings();
10615
+ if (persisted.theme) applyTheme(persisted.theme);
10616
+ let mode = persisted.mode;
10535
10617
  let model = process.env.MSAPLING_MODEL || "google/gemini-2.0-flash-001";
10536
10618
  let projectId = null;
10537
10619
  let activeChatId = null;
@@ -10583,6 +10665,8 @@ var init_exec = __esm({
10583
10665
  init_src();
10584
10666
  init_src3();
10585
10667
  init_commands();
10668
+ init_theme();
10669
+ init_parseApprovalMode();
10586
10670
  }
10587
10671
  });
10588
10672
 
@@ -10635,9 +10719,9 @@ var doctor_exports = {};
10635
10719
  __export(doctor_exports, {
10636
10720
  runDoctor: () => runDoctor
10637
10721
  });
10638
- import { homedir as homedir16, platform as platform3 } from "os";
10639
- import { join as join27 } from "path";
10640
- import { existsSync as existsSync25, statSync as statSync6, accessSync } from "fs";
10722
+ import { homedir as homedir17, platform as platform3 } from "os";
10723
+ import { join as join28 } from "path";
10724
+ import { existsSync as existsSync26, statSync as statSync6, accessSync } from "fs";
10641
10725
  import { readdir as readdir3 } from "fs/promises";
10642
10726
  import { exec } from "child_process";
10643
10727
  import { promisify } from "util";
@@ -10660,8 +10744,8 @@ async function checkNodeVersion() {
10660
10744
  };
10661
10745
  }
10662
10746
  async function checkConfigDir() {
10663
- const configDir = join27(homedir16(), ".msapling");
10664
- if (!existsSync25(configDir)) {
10747
+ const configDir = join28(homedir17(), ".msapling");
10748
+ if (!existsSync26(configDir)) {
10665
10749
  return {
10666
10750
  name: "Config directory",
10667
10751
  status: "WARN",
@@ -10727,12 +10811,12 @@ async function checkPathConflicts() {
10727
10811
  const paths = pathEnv.split(platform3() === "win32" ? ";" : ":");
10728
10812
  const conflicts = [];
10729
10813
  for (const dir of paths) {
10730
- if (!dir || !existsSync25(dir)) continue;
10814
+ if (!dir || !existsSync26(dir)) continue;
10731
10815
  try {
10732
10816
  const files = await readdir3(dir);
10733
10817
  for (const file of files) {
10734
10818
  if (file === "msapling" || file === "msapling.exe" || file === "msapling.py") {
10735
- const fullPath = join27(dir, file);
10819
+ const fullPath = join28(dir, file);
10736
10820
  conflicts.push(fullPath);
10737
10821
  }
10738
10822
  }
@@ -10834,9 +10918,9 @@ async function checkTokenValidity() {
10834
10918
  async function checkOsSpecific() {
10835
10919
  if (platform3() === "win32") {
10836
10920
  try {
10837
- const configDir = join27(homedir16(), ".msapling");
10921
+ const configDir = join28(homedir17(), ".msapling");
10838
10922
  const longPath = "A".repeat(260);
10839
- const testPath = join27(configDir, longPath);
10923
+ const testPath = join28(configDir, longPath);
10840
10924
  try {
10841
10925
  accessSync(configDir);
10842
10926
  } catch {
@@ -12498,7 +12582,7 @@ __export(server_exports, {
12498
12582
  runStdioWithRegistry: () => runStdioWithRegistry
12499
12583
  });
12500
12584
  import { readdirSync as readdirSync4, readFileSync as readFileSync2, statSync as statSync7 } from "fs";
12501
- import { join as join28, relative as relative14, resolve as resolve17 } from "path";
12585
+ import { join as join29, relative as relative14, resolve as resolve17 } from "path";
12502
12586
  function asResult2(text, isError = false) {
12503
12587
  return { content: [{ type: "text", text }], ...isError ? { isError: true } : {} };
12504
12588
  }
@@ -12518,7 +12602,7 @@ function buildFileTree(root, maxFiles) {
12518
12602
  for (const name of entries) {
12519
12603
  if (out.length >= maxFiles) break;
12520
12604
  if (SKIP_DIRS2.has(name)) continue;
12521
- const full = join28(dir, name);
12605
+ const full = join29(dir, name);
12522
12606
  let s;
12523
12607
  try {
12524
12608
  s = statSync7(full);
@@ -13284,7 +13368,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
13284
13368
  var Header = () => /* @__PURE__ */ jsxs(Box, { borderStyle: "single", borderColor: "cyan", paddingX: 1, marginBottom: 1, children: [
13285
13369
  /* @__PURE__ */ jsxs(Text, { bold: true, color: "cyan", children: [
13286
13370
  "\u25CF MSapling CLI v",
13287
- "2.3.6-beta.16"
13371
+ "2.3.6-beta.17"
13288
13372
  ] }),
13289
13373
  /* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "Platinum Tier Architecture" }) })
13290
13374
  ] });
@@ -13807,10 +13891,10 @@ ${prompt}` : prompt;
13807
13891
  for (const mention of fileMentions) {
13808
13892
  const filePath = mention.slice(1);
13809
13893
  try {
13810
- const { existsSync: existsSync26 } = await import("fs");
13811
- const { readFile: readFile22 } = await import("fs/promises");
13812
- if (existsSync26(filePath)) {
13813
- const content = await readFile22(filePath, "utf8");
13894
+ const { existsSync: existsSync27 } = await import("fs");
13895
+ const { readFile: readFile23 } = await import("fs/promises");
13896
+ if (existsSync27(filePath)) {
13897
+ const content = await readFile23(filePath, "utf8");
13814
13898
  const MAX_LEN = 32768;
13815
13899
  const truncated = content.length > MAX_LEN ? content.slice(0, MAX_LEN) + "\n...[TRUNCATED]" : content;
13816
13900
  finalCmd += `
@@ -13861,64 +13945,9 @@ ${finalCmd}`;
13861
13945
  // src/state/initSession.ts
13862
13946
  init_esm_shims();
13863
13947
  init_src3();
13948
+ init_parseApprovalMode();
13864
13949
  import { readFile as readFile21 } from "fs/promises";
13865
13950
  import { existsSync as existsSync24 } from "fs";
13866
-
13867
- // src/state/parseApprovalMode.ts
13868
- init_esm_shims();
13869
- var VALID_MODES = [
13870
- "default",
13871
- "plan",
13872
- "acceptEdits",
13873
- "bypassPermissions"
13874
- ];
13875
- function parseApprovalMode(raw, now) {
13876
- if (!raw || typeof raw !== "object") {
13877
- return { kind: "invalid", error: "settings file is not a JSON object" };
13878
- }
13879
- const block = raw.approvalMode;
13880
- if (block === void 0) return { kind: "absent" };
13881
- if (typeof block === "string") {
13882
- if (!VALID_MODES.includes(block)) {
13883
- return { kind: "invalid", error: `unknown approvalMode "${block}"` };
13884
- }
13885
- return { kind: "ok", mode: block };
13886
- }
13887
- if (typeof block !== "object" || block === null) {
13888
- return {
13889
- kind: "invalid",
13890
- error: `approvalMode must be a string or object, got ${typeof block}`
13891
- };
13892
- }
13893
- const obj = block;
13894
- const mode = obj.mode;
13895
- if (typeof mode !== "string" || !VALID_MODES.includes(mode)) {
13896
- return { kind: "invalid", error: `approvalMode.mode invalid: ${JSON.stringify(mode)}` };
13897
- }
13898
- if (mode !== "bypassPermissions") {
13899
- return { kind: "ok", mode };
13900
- }
13901
- if (typeof obj.ttlMs !== "number" || !Number.isFinite(obj.ttlMs) || obj.ttlMs <= 0) {
13902
- return {
13903
- kind: "invalid",
13904
- error: `approvalMode.ttlMs must be a positive number, got ${JSON.stringify(obj.ttlMs)}`
13905
- };
13906
- }
13907
- if (typeof obj.timestamp !== "number" || !Number.isFinite(obj.timestamp) || obj.timestamp <= 0) {
13908
- return {
13909
- kind: "invalid",
13910
- error: `approvalMode.timestamp must be a positive number, got ${JSON.stringify(obj.timestamp)}`
13911
- };
13912
- }
13913
- const age = now - obj.timestamp;
13914
- if (age > obj.ttlMs) {
13915
- return { kind: "expired", mode: "default", agedMs: age };
13916
- }
13917
- const remainingMs = obj.ttlMs - age;
13918
- return { kind: "ok", mode: "bypassPermissions", ttl: { remainingMs } };
13919
- }
13920
-
13921
- // src/state/initSession.ts
13922
13951
  async function initSession(ctx) {
13923
13952
  try {
13924
13953
  const { settings } = await loadSettings(
@@ -13932,9 +13961,9 @@ async function initSession(ctx) {
13932
13961
  ctx.setShellEscapeEnabled(settings.shellEscapeEnabled !== false);
13933
13962
  }
13934
13963
  try {
13935
- const { homedir: homedir17 } = await import("os");
13936
- const { join: join30 } = await import("path");
13937
- const userSettingsPath = join30(homedir17(), ".msapling", "settings.json");
13964
+ const { homedir: homedir18 } = await import("os");
13965
+ const { join: join31 } = await import("path");
13966
+ const userSettingsPath = join31(homedir18(), ".msapling", "settings.json");
13938
13967
  if (existsSync24(userSettingsPath)) {
13939
13968
  const userText = await readFile21(userSettingsPath, "utf8");
13940
13969
  let parsed;
@@ -13968,6 +13997,14 @@ async function initSession(ctx) {
13968
13997
  break;
13969
13998
  }
13970
13999
  ctx.setMode(modeToApply);
14000
+ const themeRaw = parsed?.theme;
14001
+ if (themeRaw === "diamond" || themeRaw === "onyx" || themeRaw === "mono") {
14002
+ try {
14003
+ const { applyTheme: applyTheme2 } = await Promise.resolve().then(() => (init_theme(), theme_exports));
14004
+ applyTheme2(themeRaw);
14005
+ } catch {
14006
+ }
14007
+ }
13971
14008
  }
13972
14009
  } catch {
13973
14010
  }
@@ -14233,12 +14270,12 @@ var App = ({ compact: compact2 = false }) => {
14233
14270
  init_esm_shims();
14234
14271
  import { readFileSync as readFileSync3 } from "fs";
14235
14272
  import { fileURLToPath as fileURLToPath2 } from "url";
14236
- import { dirname as dirname3, join as join29 } from "path";
14273
+ import { dirname as dirname3, join as join30 } from "path";
14237
14274
  function readCliVersion2() {
14238
14275
  const here = dirname3(fileURLToPath2(import.meta.url));
14239
14276
  for (const rel of ["../package.json", "../../package.json"]) {
14240
14277
  try {
14241
- const pkg = JSON.parse(readFileSync3(join29(here, rel), "utf8"));
14278
+ const pkg = JSON.parse(readFileSync3(join30(here, rel), "utf8"));
14242
14279
  if (pkg.name && pkg.version) {
14243
14280
  return { name: pkg.name, version: pkg.version };
14244
14281
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mtreeai/msapling-cli",
3
- "version": "2.3.6-beta.16",
3
+ "version": "2.3.6-beta.17",
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",