@mtreeai/msapling-cli 2.3.6-beta.15 → 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 +142 -101
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -581,15 +581,22 @@ var init_src = __esm({
581
581
  const controller = new AbortController();
582
582
  const timeout = setTimeout(() => controller.abort(), 3e4);
583
583
  try {
584
+ const headers = {
585
+ "Authorization": `Bearer ${this.token}`,
586
+ "Content-Type": "application/json"
587
+ };
588
+ if (this.cookies.size > 0) {
589
+ headers["Cookie"] = this.serializeCookies();
590
+ }
591
+ const csrf = this.cookies.get("msapling_csrftoken");
592
+ if (csrf) headers["X-CSRF-Token"] = csrf;
584
593
  const response = await fetch(`${this.apiUrl}/api/chat/message`, {
585
594
  method: "POST",
586
- headers: {
587
- "Authorization": `Bearer ${this.token}`,
588
- "Content-Type": "application/json"
589
- },
595
+ headers,
590
596
  body: JSON.stringify(params),
591
597
  signal: controller.signal
592
598
  });
599
+ this.updateCookiesFromResponse(response);
593
600
  clearTimeout(timeout);
594
601
  if (response.status === 423) {
595
602
  await new Promise((r) => setTimeout(r, 1e3));
@@ -3620,20 +3627,20 @@ async function copyDir(src, dst) {
3620
3627
  }
3621
3628
  async function backupFile(absPath) {
3622
3629
  try {
3623
- const { readFile: readFile22, writeFile: writeFile12, mkdir: mkdir9 } = await import("fs/promises");
3624
- const { homedir: homedir17 } = await import("os");
3625
- 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");
3626
3633
  const filename = absPath.split(/[\\/]/).pop() ?? "file";
3627
3634
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
3628
3635
  const suffix = randomBytes5(4).toString("hex");
3629
- const backupPath = join30(
3630
- homedir17(),
3636
+ const backupPath = join31(
3637
+ homedir18(),
3631
3638
  ".msapling",
3632
3639
  "backups",
3633
3640
  `${filename}.backup-${stamp}-${suffix}.bak`
3634
3641
  );
3635
- await mkdir9(join30(homedir17(), ".msapling", "backups"), { recursive: true });
3636
- const content = await readFile22(absPath, "utf8");
3642
+ await mkdir9(join31(homedir18(), ".msapling", "backups"), { recursive: true });
3643
+ const content = await readFile23(absPath, "utf8");
3637
3644
  await writeFile12(backupPath, content, "utf8");
3638
3645
  return backupPath;
3639
3646
  } catch {
@@ -3859,14 +3866,14 @@ var init_DeleteFileTool = __esm({
3859
3866
  let backedUpTo = null;
3860
3867
  if (isFile) {
3861
3868
  try {
3862
- const { readFile: readFile22, writeFile: writeFile12, mkdir: mkdir9 } = await import("fs/promises");
3863
- const { homedir: homedir17 } = await import("os");
3864
- 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");
3865
3872
  const filename = abs.split(/[\\/]/).pop() ?? "file";
3866
3873
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
3867
3874
  const suffix = randomBytes6(4).toString("hex");
3868
- const backupPath = join11(homedir17(), ".msapling", "backups", `${filename}.backup-${stamp}-${suffix}.bak`);
3869
- 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 });
3870
3877
  await writeFile12(backupPath, existingContent, "utf8");
3871
3878
  backedUpTo = backupPath;
3872
3879
  } catch {
@@ -5834,8 +5841,8 @@ var require_graceful_fs = __commonJS({
5834
5841
  fs4.createReadStream = createReadStream;
5835
5842
  fs4.createWriteStream = createWriteStream;
5836
5843
  var fs$readFile = fs4.readFile;
5837
- fs4.readFile = readFile22;
5838
- function readFile22(path2, options, cb) {
5844
+ fs4.readFile = readFile23;
5845
+ function readFile23(path2, options, cb) {
5839
5846
  if (typeof options === "function")
5840
5847
  cb = options, options = null;
5841
5848
  return go$readFile(path2, options, cb);
@@ -9684,7 +9691,7 @@ var init_version = __esm({
9684
9691
  description: "Show version information for CLI and core packages",
9685
9692
  category: "debug",
9686
9693
  handler: async (_args, context) => {
9687
- const cliVersion = true ? "2.3.6-beta.15" : "(dev)";
9694
+ const cliVersion = true ? "2.3.6-beta.17" : "(dev)";
9688
9695
  const coreVersion = true ? "2.3.2" : "(dev)";
9689
9696
  const runtime = process.version;
9690
9697
  context.addMessage("system", "MSapling Version Info");
@@ -9693,7 +9700,7 @@ var init_version = __esm({
9693
9700
  context.addMessage("system", row2("Core (@msapling/core)", coreVersion));
9694
9701
  context.addMessage("system", row2("Runtime (Node/Bun)", runtime));
9695
9702
  try {
9696
- const ts = "2026-05-28T14:58:50.319Z";
9703
+ const ts = "2026-05-28T16:29:43.918Z";
9697
9704
  if (ts && ts !== "__BUILD_TIMESTAMP__") {
9698
9705
  context.addMessage("system", row2("Build Timestamp", ts));
9699
9706
  }
@@ -10497,11 +10504,91 @@ var init_commands = __esm({
10497
10504
  }
10498
10505
  });
10499
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
+
10500
10567
  // src/runtime/exec.ts
10501
10568
  var exec_exports = {};
10502
10569
  __export(exec_exports, {
10503
10570
  runExec: () => runExec
10504
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
+ }
10505
10592
  async function runExec(rawInput) {
10506
10593
  const trimmed = (rawInput || "").trim();
10507
10594
  if (!trimmed) {
@@ -10524,7 +10611,9 @@ async function runExec(rawInput) {
10524
10611
  token: token || void 0
10525
10612
  });
10526
10613
  const stdout = process.stdout;
10527
- let mode = "default";
10614
+ const persisted = await loadPersistedSettings();
10615
+ if (persisted.theme) applyTheme(persisted.theme);
10616
+ let mode = persisted.mode;
10528
10617
  let model = process.env.MSAPLING_MODEL || "google/gemini-2.0-flash-001";
10529
10618
  let projectId = null;
10530
10619
  let activeChatId = null;
@@ -10576,6 +10665,8 @@ var init_exec = __esm({
10576
10665
  init_src();
10577
10666
  init_src3();
10578
10667
  init_commands();
10668
+ init_theme();
10669
+ init_parseApprovalMode();
10579
10670
  }
10580
10671
  });
10581
10672
 
@@ -10628,9 +10719,9 @@ var doctor_exports = {};
10628
10719
  __export(doctor_exports, {
10629
10720
  runDoctor: () => runDoctor
10630
10721
  });
10631
- import { homedir as homedir16, platform as platform3 } from "os";
10632
- import { join as join27 } from "path";
10633
- 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";
10634
10725
  import { readdir as readdir3 } from "fs/promises";
10635
10726
  import { exec } from "child_process";
10636
10727
  import { promisify } from "util";
@@ -10653,8 +10744,8 @@ async function checkNodeVersion() {
10653
10744
  };
10654
10745
  }
10655
10746
  async function checkConfigDir() {
10656
- const configDir = join27(homedir16(), ".msapling");
10657
- if (!existsSync25(configDir)) {
10747
+ const configDir = join28(homedir17(), ".msapling");
10748
+ if (!existsSync26(configDir)) {
10658
10749
  return {
10659
10750
  name: "Config directory",
10660
10751
  status: "WARN",
@@ -10720,12 +10811,12 @@ async function checkPathConflicts() {
10720
10811
  const paths = pathEnv.split(platform3() === "win32" ? ";" : ":");
10721
10812
  const conflicts = [];
10722
10813
  for (const dir of paths) {
10723
- if (!dir || !existsSync25(dir)) continue;
10814
+ if (!dir || !existsSync26(dir)) continue;
10724
10815
  try {
10725
10816
  const files = await readdir3(dir);
10726
10817
  for (const file of files) {
10727
10818
  if (file === "msapling" || file === "msapling.exe" || file === "msapling.py") {
10728
- const fullPath = join27(dir, file);
10819
+ const fullPath = join28(dir, file);
10729
10820
  conflicts.push(fullPath);
10730
10821
  }
10731
10822
  }
@@ -10827,9 +10918,9 @@ async function checkTokenValidity() {
10827
10918
  async function checkOsSpecific() {
10828
10919
  if (platform3() === "win32") {
10829
10920
  try {
10830
- const configDir = join27(homedir16(), ".msapling");
10921
+ const configDir = join28(homedir17(), ".msapling");
10831
10922
  const longPath = "A".repeat(260);
10832
- const testPath = join27(configDir, longPath);
10923
+ const testPath = join28(configDir, longPath);
10833
10924
  try {
10834
10925
  accessSync(configDir);
10835
10926
  } catch {
@@ -12491,7 +12582,7 @@ __export(server_exports, {
12491
12582
  runStdioWithRegistry: () => runStdioWithRegistry
12492
12583
  });
12493
12584
  import { readdirSync as readdirSync4, readFileSync as readFileSync2, statSync as statSync7 } from "fs";
12494
- 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";
12495
12586
  function asResult2(text, isError = false) {
12496
12587
  return { content: [{ type: "text", text }], ...isError ? { isError: true } : {} };
12497
12588
  }
@@ -12511,7 +12602,7 @@ function buildFileTree(root, maxFiles) {
12511
12602
  for (const name of entries) {
12512
12603
  if (out.length >= maxFiles) break;
12513
12604
  if (SKIP_DIRS2.has(name)) continue;
12514
- const full = join28(dir, name);
12605
+ const full = join29(dir, name);
12515
12606
  let s;
12516
12607
  try {
12517
12608
  s = statSync7(full);
@@ -13277,7 +13368,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
13277
13368
  var Header = () => /* @__PURE__ */ jsxs(Box, { borderStyle: "single", borderColor: "cyan", paddingX: 1, marginBottom: 1, children: [
13278
13369
  /* @__PURE__ */ jsxs(Text, { bold: true, color: "cyan", children: [
13279
13370
  "\u25CF MSapling CLI v",
13280
- "2.3.6-beta.15"
13371
+ "2.3.6-beta.17"
13281
13372
  ] }),
13282
13373
  /* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "Platinum Tier Architecture" }) })
13283
13374
  ] });
@@ -13800,10 +13891,10 @@ ${prompt}` : prompt;
13800
13891
  for (const mention of fileMentions) {
13801
13892
  const filePath = mention.slice(1);
13802
13893
  try {
13803
- const { existsSync: existsSync26 } = await import("fs");
13804
- const { readFile: readFile22 } = await import("fs/promises");
13805
- if (existsSync26(filePath)) {
13806
- 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");
13807
13898
  const MAX_LEN = 32768;
13808
13899
  const truncated = content.length > MAX_LEN ? content.slice(0, MAX_LEN) + "\n...[TRUNCATED]" : content;
13809
13900
  finalCmd += `
@@ -13854,67 +13945,9 @@ ${finalCmd}`;
13854
13945
  // src/state/initSession.ts
13855
13946
  init_esm_shims();
13856
13947
  init_src3();
13948
+ init_parseApprovalMode();
13857
13949
  import { readFile as readFile21 } from "fs/promises";
13858
13950
  import { existsSync as existsSync24 } from "fs";
13859
-
13860
- // src/state/parseApprovalMode.ts
13861
- init_esm_shims();
13862
- var VALID_MODES = [
13863
- "default",
13864
- "plan",
13865
- "acceptEdits",
13866
- "bypassPermissions"
13867
- ];
13868
- function parseApprovalMode(raw, now) {
13869
- if (!raw || typeof raw !== "object") {
13870
- return { kind: "invalid", error: "settings file is not a JSON object" };
13871
- }
13872
- const block = raw.approvalMode;
13873
- if (block === void 0) return { kind: "absent" };
13874
- if (typeof block === "string") {
13875
- if (!VALID_MODES.includes(block)) {
13876
- return { kind: "invalid", error: `unknown approvalMode "${block}"` };
13877
- }
13878
- return { kind: "ok", mode: block };
13879
- }
13880
- if (typeof block !== "object" || block === null) {
13881
- return {
13882
- kind: "invalid",
13883
- error: `approvalMode must be a string or object, got ${typeof block}`
13884
- };
13885
- }
13886
- const obj = block;
13887
- const mode = obj.mode;
13888
- if (typeof mode !== "string" || !VALID_MODES.includes(mode)) {
13889
- return { kind: "invalid", error: `approvalMode.mode invalid: ${JSON.stringify(mode)}` };
13890
- }
13891
- if (obj.ttlMs === void 0 && obj.timestamp === void 0) {
13892
- return { kind: "ok", mode };
13893
- }
13894
- if (typeof obj.ttlMs !== "number" || !Number.isFinite(obj.ttlMs) || obj.ttlMs <= 0) {
13895
- return {
13896
- kind: "invalid",
13897
- error: `approvalMode.ttlMs must be a positive number, got ${JSON.stringify(obj.ttlMs)}`
13898
- };
13899
- }
13900
- if (typeof obj.timestamp !== "number" || !Number.isFinite(obj.timestamp) || obj.timestamp <= 0) {
13901
- return {
13902
- kind: "invalid",
13903
- error: `approvalMode.timestamp must be a positive number, got ${JSON.stringify(obj.timestamp)}`
13904
- };
13905
- }
13906
- if (mode !== "bypassPermissions") {
13907
- return { kind: "ok", mode };
13908
- }
13909
- const age = now - obj.timestamp;
13910
- if (age > obj.ttlMs) {
13911
- return { kind: "expired", mode: "default", agedMs: age };
13912
- }
13913
- const remainingMs = obj.ttlMs - age;
13914
- return { kind: "ok", mode: "bypassPermissions", ttl: { remainingMs } };
13915
- }
13916
-
13917
- // src/state/initSession.ts
13918
13951
  async function initSession(ctx) {
13919
13952
  try {
13920
13953
  const { settings } = await loadSettings(
@@ -13928,9 +13961,9 @@ async function initSession(ctx) {
13928
13961
  ctx.setShellEscapeEnabled(settings.shellEscapeEnabled !== false);
13929
13962
  }
13930
13963
  try {
13931
- const { homedir: homedir17 } = await import("os");
13932
- const { join: join30 } = await import("path");
13933
- 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");
13934
13967
  if (existsSync24(userSettingsPath)) {
13935
13968
  const userText = await readFile21(userSettingsPath, "utf8");
13936
13969
  let parsed;
@@ -13964,6 +13997,14 @@ async function initSession(ctx) {
13964
13997
  break;
13965
13998
  }
13966
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
+ }
13967
14008
  }
13968
14009
  } catch {
13969
14010
  }
@@ -14229,12 +14270,12 @@ var App = ({ compact: compact2 = false }) => {
14229
14270
  init_esm_shims();
14230
14271
  import { readFileSync as readFileSync3 } from "fs";
14231
14272
  import { fileURLToPath as fileURLToPath2 } from "url";
14232
- import { dirname as dirname3, join as join29 } from "path";
14273
+ import { dirname as dirname3, join as join30 } from "path";
14233
14274
  function readCliVersion2() {
14234
14275
  const here = dirname3(fileURLToPath2(import.meta.url));
14235
14276
  for (const rel of ["../package.json", "../../package.json"]) {
14236
14277
  try {
14237
- const pkg = JSON.parse(readFileSync3(join29(here, rel), "utf8"));
14278
+ const pkg = JSON.parse(readFileSync3(join30(here, rel), "utf8"));
14238
14279
  if (pkg.name && pkg.version) {
14239
14280
  return { name: pkg.name, version: pkg.version };
14240
14281
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mtreeai/msapling-cli",
3
- "version": "2.3.6-beta.15",
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",