@mtreeai/msapling-cli 2.3.6-beta.20 → 2.3.6-beta.22

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 +190 -45
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -171,15 +171,20 @@ var init_src = __esm({
171
171
  }
172
172
  }
173
173
  async me() {
174
- const data = await this.request("/api/projects/overview");
174
+ const [overviewData, billingData] = await Promise.all([
175
+ this.request("/api/projects/overview"),
176
+ this.request("/api/billing/settings").catch(() => null)
177
+ ]);
178
+ const data = overviewData;
179
+ const fuel = billingData?.fuel ?? {};
175
180
  return {
176
181
  user: {
177
182
  id: data.user_id,
178
183
  email: data.email,
179
- tier: data.tier,
184
+ tier: billingData?.tier ?? data.tier,
180
185
  is_pro: data.is_pro,
181
- fuel_credits: data.fuel_credits,
182
- fuel_credits_purchased: data.fuel_credits_purchased || 0,
186
+ fuel_credits: typeof fuel.total === "number" ? fuel.total : data.fuel_credits,
187
+ fuel_credits_purchased: typeof fuel.purchased === "number" ? fuel.purchased : data.fuel_credits_purchased || 0,
183
188
  monthly_spending_limit: data.monthly_spending_limit || null,
184
189
  cost_byok: data.cost_byok || 0,
185
190
  tokens_byok: data.tokens_byok || 0,
@@ -203,14 +208,19 @@ var init_src = __esm({
203
208
  };
204
209
  }
205
210
  async getLiveUsage() {
206
- const data = await this.request("/api/usage/live");
211
+ const [billingData, overviewData] = await Promise.all([
212
+ this.request("/api/billing/settings").catch(() => null),
213
+ this.request("/api/projects/overview").catch(() => ({}))
214
+ ]);
215
+ const fuel = billingData?.fuel ?? {};
216
+ const data = overviewData;
207
217
  return {
208
218
  id: data.user_id,
209
219
  email: data.email,
210
- tier: data.tier,
220
+ tier: billingData?.tier ?? data.tier,
211
221
  is_pro: data.is_pro,
212
- fuel_credits: data.fuel_credits,
213
- fuel_credits_purchased: data.fuel_credits_purchased || 0,
222
+ fuel_credits: typeof fuel.total === "number" ? fuel.total : data.fuel_credits,
223
+ fuel_credits_purchased: typeof fuel.purchased === "number" ? fuel.purchased : data.fuel_credits_purchased || 0,
214
224
  monthly_spending_limit: data.monthly_spending_limit || null,
215
225
  cost_byok: data.cost_byok || 0,
216
226
  tokens_byok: data.tokens_byok || 0,
@@ -8534,26 +8544,101 @@ var init_help = __esm({
8534
8544
  });
8535
8545
 
8536
8546
  // src/commands/chat.ts
8537
- var chatCommand;
8547
+ function labelFor(i) {
8548
+ return i < 9 ? String(i + 1) : LETTERS[i - 9] ?? `#${i + 1}`;
8549
+ }
8550
+ async function fetchChatsForCurrentProject(context) {
8551
+ try {
8552
+ const data = await context.client.request("/api/projects/");
8553
+ const currentId = context.getProjectId() || null;
8554
+ const overview = await context.client.me();
8555
+ const activeProject = overview.projects.find((p) => p.id === currentId) ?? overview.projects[0];
8556
+ if (!activeProject) return { error: "No active project; use /project first." };
8557
+ const bucket = data.projects?.[activeProject.name];
8558
+ return {
8559
+ projectName: activeProject.name,
8560
+ chats: bucket?.chats ?? []
8561
+ };
8562
+ } catch (e) {
8563
+ return { error: `Failed to fetch chats: ${e.message}` };
8564
+ }
8565
+ }
8566
+ function resolveChat(arg, chats) {
8567
+ const trimmed = arg.trim();
8568
+ if (!trimmed) return { kind: "error", message: "empty argument" };
8569
+ const uuidHit = chats.find((c) => c.id === trimmed);
8570
+ if (uuidHit) return { kind: "ok", id: uuidHit.id, title: uuidHit.title };
8571
+ if (/^\d+$/.test(trimmed)) {
8572
+ const n = parseInt(trimmed, 10);
8573
+ if (n >= 1 && n <= chats.length) return { kind: "ok", id: chats[n - 1].id, title: chats[n - 1].title };
8574
+ return { kind: "error", message: `no chat at index ${n} (have ${chats.length})` };
8575
+ }
8576
+ if (/^[a-zA-Z]$/.test(trimmed)) {
8577
+ const idx = 9 + LETTERS.indexOf(trimmed.toLowerCase());
8578
+ if (idx >= 9 && idx < chats.length) return { kind: "ok", id: chats[idx].id, title: chats[idx].title };
8579
+ }
8580
+ const lower = trimmed.toLowerCase();
8581
+ const matches2 = chats.filter((c) => (c.title ?? "").toLowerCase().includes(lower));
8582
+ if (matches2.length === 1) return { kind: "ok", id: matches2[0].id, title: matches2[0].title };
8583
+ if (matches2.length > 1) {
8584
+ return {
8585
+ kind: "error",
8586
+ message: `'${trimmed}' matches ${matches2.length} chats: ${matches2.map((m) => m.title).join(", ")}`
8587
+ };
8588
+ }
8589
+ return { kind: "error", message: `no chat matches '${trimmed}'. Run /chat (no args) for the list.` };
8590
+ }
8591
+ async function listChats(args2, context) {
8592
+ const arg = args2.join(" ").trim();
8593
+ const result = await fetchChatsForCurrentProject(context);
8594
+ if ("error" in result) {
8595
+ context.addMessage("error", result.error);
8596
+ return;
8597
+ }
8598
+ const { projectName, chats } = result;
8599
+ if (!arg) {
8600
+ if (chats.length === 0) {
8601
+ context.addMessage("system", `No chats in project '${projectName}'. Send a message to start one.`);
8602
+ return;
8603
+ }
8604
+ context.addMessage("system", `Chats in '${projectName}':`);
8605
+ chats.forEach((c, i) => {
8606
+ const label = labelFor(i);
8607
+ const star = c.id === context.activeChatId ? " \u2605" : "";
8608
+ const model = c.model ? ` [${c.model}]` : "";
8609
+ context.addMessage("system", ` ${label}. ${c.title ?? c.id}${model}${star}`);
8610
+ });
8611
+ context.addMessage("system", "");
8612
+ context.addMessage("system", "Switch via /chat <number|letter|title> (e.g. /chat 1 or /chat audit)");
8613
+ return;
8614
+ }
8615
+ const resolved = resolveChat(arg, chats);
8616
+ if (resolved.kind === "error") {
8617
+ context.addMessage("error", resolved.message);
8618
+ return;
8619
+ }
8620
+ context.setActiveChatId(resolved.id);
8621
+ context.addMessage("system", `Switched to chat: ${resolved.title ?? resolved.id}`);
8622
+ await context.refreshOverview();
8623
+ }
8624
+ var LETTERS, chatCommand, chatsCommand;
8538
8625
  var init_chat = __esm({
8539
8626
  "src/commands/chat.ts"() {
8540
8627
  "use strict";
8541
8628
  init_esm_shims();
8629
+ LETTERS = "abcdefghijklmnopqrstuvwxyz";
8542
8630
  chatCommand = {
8543
8631
  name: "chat",
8544
- args: "<chat_id>",
8545
- description: "Switch to a specific chat session",
8632
+ args: "[number|letter|title|id]",
8633
+ description: "List chats in the current project, or switch to one",
8546
8634
  category: "chat",
8547
- handler: async (args2, context) => {
8548
- const chatId = args2[0];
8549
- if (!chatId) {
8550
- context.addMessage("system", "Usage: /chat <chat_id>");
8551
- return;
8552
- }
8553
- context.setActiveChatId(chatId);
8554
- context.addMessage("system", `Switched to chat: ${chatId}`);
8555
- await context.refreshOverview();
8556
- }
8635
+ handler: async (args2, context) => listChats(args2, context)
8636
+ };
8637
+ chatsCommand = {
8638
+ name: "chats",
8639
+ description: "List chats in the current project (alias for /chat with no args)",
8640
+ category: "chat",
8641
+ handler: async (_args, context) => listChats([], context)
8557
8642
  };
8558
8643
  }
8559
8644
  });
@@ -8819,34 +8904,80 @@ var init_memory = __esm({
8819
8904
  });
8820
8905
 
8821
8906
  // src/commands/project.ts
8822
- var projectCommand;
8907
+ function labelFor2(i) {
8908
+ return i < 9 ? String(i + 1) : LETTERS2[i - 9] ?? `#${i + 1}`;
8909
+ }
8910
+ function resolveProject(arg, list) {
8911
+ const trimmed = arg.trim();
8912
+ if (!trimmed) return { kind: "error", message: "empty argument" };
8913
+ const uuidHit = list.find((p) => p.id === trimmed);
8914
+ if (uuidHit) return { kind: "ok", id: uuidHit.id };
8915
+ if (/^\d+$/.test(trimmed)) {
8916
+ const n = parseInt(trimmed, 10);
8917
+ if (n >= 1 && n <= list.length) return { kind: "ok", id: list[n - 1].id };
8918
+ return { kind: "error", message: `no project at index ${n} (have ${list.length})` };
8919
+ }
8920
+ if (/^[a-zA-Z]$/.test(trimmed)) {
8921
+ const idx = 9 + LETTERS2.indexOf(trimmed.toLowerCase());
8922
+ if (idx >= 9 && idx < list.length) return { kind: "ok", id: list[idx].id };
8923
+ }
8924
+ const lower = trimmed.toLowerCase();
8925
+ const matches2 = list.filter((p) => (p.name ?? "").toLowerCase().includes(lower));
8926
+ if (matches2.length === 1) return { kind: "ok", id: matches2[0].id };
8927
+ if (matches2.length > 1) {
8928
+ return {
8929
+ kind: "error",
8930
+ message: `'${trimmed}' matches ${matches2.length} projects: ${matches2.map((m) => m.name).join(", ")}`
8931
+ };
8932
+ }
8933
+ return { kind: "error", message: `no project matches '${trimmed}'. Run /project (no args) for the list.` };
8934
+ }
8935
+ var LETTERS2, projectCommand;
8823
8936
  var init_project = __esm({
8824
8937
  "src/commands/project.ts"() {
8825
8938
  "use strict";
8826
8939
  init_esm_shims();
8940
+ LETTERS2 = "abcdefghijklmnopqrstuvwxyz";
8827
8941
  projectCommand = {
8828
8942
  name: "project",
8829
- args: "[project_id]",
8943
+ args: "[number|letter|name|id]",
8830
8944
  description: "List or switch active project",
8831
8945
  category: "project",
8832
8946
  handler: async (args2, context) => {
8833
- const newProjectId = args2[0];
8834
- if (!newProjectId) {
8835
- try {
8836
- const overview = await context.client.me();
8837
- context.addMessage("system", "Available Projects:");
8838
- for (const p of overview.projects) {
8839
- context.addMessage("system", ` - ${p.id} (${p.name})`);
8840
- }
8841
- context.addMessage("system", `
8842
- Current Project: ${context.getProjectId() || "none"}`);
8843
- } catch (e) {
8844
- context.addMessage("error", `Failed to fetch projects: ${e.message}`);
8947
+ const arg = args2.join(" ").trim();
8948
+ const currentId = context.getProjectId() || null;
8949
+ let projects = [];
8950
+ try {
8951
+ const overview = await context.client.me();
8952
+ projects = overview.projects;
8953
+ } catch (e) {
8954
+ context.addMessage("error", `Failed to fetch projects: ${e.message}`);
8955
+ return;
8956
+ }
8957
+ if (!arg) {
8958
+ if (projects.length === 0) {
8959
+ context.addMessage("system", "No projects found.");
8960
+ return;
8845
8961
  }
8962
+ context.addMessage("system", "Available Projects:");
8963
+ projects.forEach((p, i) => {
8964
+ const label = labelFor2(i);
8965
+ const star = p.id === currentId ? " \u2605" : "";
8966
+ const usage = p.chat_count != null && p.chat_limit != null ? ` (${p.chat_count}/${p.chat_limit} chats)` : "";
8967
+ context.addMessage("system", ` ${label}. ${p.name ?? p.id}${usage}${star}`);
8968
+ });
8969
+ context.addMessage("system", "");
8970
+ context.addMessage("system", "Switch via /project <number|letter|name> (e.g. /project 2 or /project audit)");
8846
8971
  return;
8847
8972
  }
8848
- context.setProjectId(newProjectId);
8849
- context.addMessage("system", `Project switched to: ${newProjectId}`);
8973
+ const resolved = resolveProject(arg, projects);
8974
+ if (resolved.kind === "error") {
8975
+ context.addMessage("error", resolved.message);
8976
+ return;
8977
+ }
8978
+ const picked = projects.find((p) => p.id === resolved.id);
8979
+ context.setProjectId(resolved.id);
8980
+ context.addMessage("system", `Project switched to: ${picked.name ?? resolved.id}`);
8850
8981
  await context.refreshOverview();
8851
8982
  }
8852
8983
  };
@@ -9341,7 +9472,7 @@ var init_benchmark = __esm({
9341
9472
  let models = modelArg ?? [];
9342
9473
  if (!models.length) {
9343
9474
  try {
9344
- const resp = await context.client.get("/api/models");
9475
+ const resp = await context.client.request("/api/benchmark/models");
9345
9476
  const list = Array.isArray(resp) ? resp : resp?.models ?? [];
9346
9477
  models = list.slice(0, 4).map((m) => m.id ?? m.model_id ?? "").filter(Boolean);
9347
9478
  } catch {
@@ -9567,14 +9698,14 @@ var init_status = __esm({
9567
9698
  context.addMessage("error", `Health check failed: ${e.message}`);
9568
9699
  }
9569
9700
  try {
9570
- const countData = await context.client["request"]("/api/stream/active-count");
9701
+ const countData = await context.client["request"]("/api/chat/stream/active-count");
9571
9702
  const count = countData?.count ?? countData?.active_count ?? 0;
9572
9703
  context.addMessage("system", `[INFO] Active Streams: ${count}`);
9573
9704
  } catch (e) {
9574
9705
  context.addMessage("system", ` Active Streams: unavailable (${e.message})`);
9575
9706
  }
9576
9707
  try {
9577
- const providerData = await context.client["request"]("/api/admin/provider-health");
9708
+ const providerData = await context.client["request"]("/api/provider/circuit-summary");
9578
9709
  const providers = providerData?.providers ?? (Array.isArray(providerData) ? providerData : []);
9579
9710
  if (providers.length > 0) {
9580
9711
  context.addMessage("system", " Provider Circuits:");
@@ -9745,7 +9876,7 @@ var init_version = __esm({
9745
9876
  description: "Show version information for CLI and core packages",
9746
9877
  category: "debug",
9747
9878
  handler: async (_args, context) => {
9748
- const cliVersion = true ? "2.3.6-beta.20" : "(dev)";
9879
+ const cliVersion = true ? "2.3.6-beta.22" : "(dev)";
9749
9880
  const coreVersion = true ? "2.3.2" : "(dev)";
9750
9881
  const runtime = process.version;
9751
9882
  context.addMessage("system", "MSapling Version Info");
@@ -9754,7 +9885,7 @@ var init_version = __esm({
9754
9885
  context.addMessage("system", row2("Core (@msapling/core)", coreVersion));
9755
9886
  context.addMessage("system", row2("Runtime (Node/Bun)", runtime));
9756
9887
  try {
9757
- const ts = "2026-05-28T18:54:30.369Z";
9888
+ const ts = "2026-05-28T19:10:28.448Z";
9758
9889
  if (ts && ts !== "__BUILD_TIMESTAMP__") {
9759
9890
  context.addMessage("system", row2("Build Timestamp", ts));
9760
9891
  }
@@ -10527,6 +10658,7 @@ var init_commands = __esm({
10527
10658
  exitCommand,
10528
10659
  helpCommand,
10529
10660
  chatCommand,
10661
+ chatsCommand,
10530
10662
  clearCommand,
10531
10663
  modeCommand,
10532
10664
  modelCommand,
@@ -10752,9 +10884,22 @@ async function apiFetch(path2, opts = {}) {
10752
10884
  return fetch(`${getBaseURL()}${path2}`, { ...opts, headers, body });
10753
10885
  }
10754
10886
  async function fetchBalance() {
10755
- const res = await apiFetch("/api/billing/balance");
10887
+ const res = await apiFetch("/api/billing/settings");
10756
10888
  if (!res.ok) throw new Error(`Balance fetch failed: ${res.status}`);
10757
- return res.json();
10889
+ const data = await res.json();
10890
+ return {
10891
+ tier: data.tier ?? "free",
10892
+ is_pro: data.tier && !["free", "guest"].includes(String(data.tier).toLowerCase()),
10893
+ is_founder: false,
10894
+ fuel_credits: Number(data?.fuel?.total ?? 0),
10895
+ fuel_credits_purchased: Number(data?.fuel?.purchased ?? 0),
10896
+ auto_topup: {
10897
+ enabled: !!data?.auto_topup?.enabled,
10898
+ threshold_usd: Number(data?.auto_topup?.threshold_usd ?? 0),
10899
+ amount_usd: Number(data?.auto_topup?.amount_usd ?? 0),
10900
+ max_per_month_usd: Number(data?.auto_topup?.max_per_month_usd ?? 0)
10901
+ }
10902
+ };
10758
10903
  }
10759
10904
  async function fetchFounderStatus() {
10760
10905
  const res = await apiFetch("/api/billing/founder-status");
@@ -14143,7 +14288,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
14143
14288
  var Header = () => /* @__PURE__ */ jsxs(Box, { borderStyle: "single", borderColor: "cyan", paddingX: 1, marginBottom: 1, children: [
14144
14289
  /* @__PURE__ */ jsxs(Text, { bold: true, color: "cyan", children: [
14145
14290
  "\u25CF MSapling CLI v",
14146
- "2.3.6-beta.20"
14291
+ "2.3.6-beta.22"
14147
14292
  ] }),
14148
14293
  /* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "Platinum Tier Architecture" }) })
14149
14294
  ] });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mtreeai/msapling-cli",
3
- "version": "2.3.6-beta.20",
3
+ "version": "2.3.6-beta.22",
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",