@mtreeai/msapling-cli 2.3.6-beta.22 → 2.3.6-beta.24
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.
- package/dist/index.js +576 -6
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -266,8 +266,127 @@ var init_src = __esm({
|
|
|
266
266
|
body: JSON.stringify(symbol)
|
|
267
267
|
});
|
|
268
268
|
}
|
|
269
|
+
// CLI-OLLAMA-COMMANDS-01 (Iter 35): Ollama BYOK helpers. Per LAB ollama.py
|
|
270
|
+
// routes are GET/POST/DELETE under /api/ollama. The CLI uses these to wire
|
|
271
|
+
// up the user's local Ollama instance as a free-tier model provider.
|
|
272
|
+
async getOllamaStatus() {
|
|
273
|
+
return await this.request("/api/ollama/status");
|
|
274
|
+
}
|
|
275
|
+
async configureOllama(opts) {
|
|
276
|
+
return await this.request("/api/ollama/configure", {
|
|
277
|
+
method: "POST",
|
|
278
|
+
body: JSON.stringify({
|
|
279
|
+
base_url: opts.baseUrl,
|
|
280
|
+
enabled: opts.enabled,
|
|
281
|
+
action: opts.action,
|
|
282
|
+
model: opts.model
|
|
283
|
+
})
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
async testOllama(baseUrl) {
|
|
287
|
+
return await this.request("/api/ollama/test", {
|
|
288
|
+
method: "POST",
|
|
289
|
+
body: JSON.stringify({ base_url: baseUrl })
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
async deleteOllamaModel(modelName) {
|
|
293
|
+
return await this.request(`/api/ollama/models/${encodeURIComponent(modelName)}`, {
|
|
294
|
+
method: "DELETE"
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
async disableOllama() {
|
|
298
|
+
return await this.request("/api/ollama/disable", { method: "POST" });
|
|
299
|
+
}
|
|
300
|
+
// CLI-KEYS-BYOK-01 (Iter 35): BYOK provider-key management. Per LAB
|
|
301
|
+
// routers/keys.py — /api/keys/{status,save,{provider}}.
|
|
302
|
+
async getProviderKeys() {
|
|
303
|
+
return await this.request("/api/keys/status");
|
|
304
|
+
}
|
|
305
|
+
async saveProviderKey(provider, apiKey) {
|
|
306
|
+
return await this.request("/api/keys/save", {
|
|
307
|
+
method: "POST",
|
|
308
|
+
body: JSON.stringify({ provider, api_key: apiKey })
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
async deleteProviderKey(provider) {
|
|
312
|
+
return await this.request(`/api/keys/${encodeURIComponent(provider)}`, { method: "DELETE" });
|
|
313
|
+
}
|
|
314
|
+
// CLI-CHAT-LIFECYCLE-01 (Iter 35): rename/delete/fork/pin. Per LAB
|
|
315
|
+
// projects.py:404 (PATCH), 879 (DELETE), 534 (POST fork), 726 (PATCH pin).
|
|
316
|
+
async renameChat(chatId, title) {
|
|
317
|
+
return await this.request(`/api/projects/chat/${encodeURIComponent(chatId)}`, {
|
|
318
|
+
method: "PATCH",
|
|
319
|
+
body: JSON.stringify({ title })
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
async deleteChat(chatId) {
|
|
323
|
+
return await this.request(`/api/projects/chat/${encodeURIComponent(chatId)}`, { method: "DELETE" });
|
|
324
|
+
}
|
|
325
|
+
async forkChat(chatId, body) {
|
|
326
|
+
return await this.request(`/api/projects/chat/${encodeURIComponent(chatId)}/fork`, {
|
|
327
|
+
method: "POST",
|
|
328
|
+
body: JSON.stringify(body ?? {})
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
async pinChat(chatId, pinned) {
|
|
332
|
+
return await this.request(`/api/projects/chat/${encodeURIComponent(chatId)}/pin`, {
|
|
333
|
+
method: "PATCH",
|
|
334
|
+
body: JSON.stringify({ pinned })
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
// CLI-MEMORIES-01 (Iter 35): backend-managed memories (vs the local notes
|
|
338
|
+
// /memory currently surfaces). Per LAB memories.py — list / create / delete.
|
|
339
|
+
async listMemories() {
|
|
340
|
+
return await this.request("/api/memories");
|
|
341
|
+
}
|
|
342
|
+
async createMemory(content) {
|
|
343
|
+
return await this.request("/api/memories", {
|
|
344
|
+
method: "POST",
|
|
345
|
+
body: JSON.stringify({ content })
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
async deleteMemory(memoryId) {
|
|
349
|
+
return await this.request(`/api/memories/${encodeURIComponent(memoryId)}`, { method: "DELETE" });
|
|
350
|
+
}
|
|
351
|
+
// CLI-PROJECT-CREATE-01 (Iter 34): create a new project. Per LAB
|
|
352
|
+
// projects.py:239 — POST /api/projects/ with {project_name}.
|
|
353
|
+
async createProject(name) {
|
|
354
|
+
return await this.request("/api/projects/", {
|
|
355
|
+
method: "POST",
|
|
356
|
+
body: JSON.stringify({ project_name: name })
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
// CLI-CHAT-CREATE-01 (Iter 34): create a new chat in a project. Per LAB
|
|
360
|
+
// projects.py:365 — POST /api/projects/chat/new with
|
|
361
|
+
// {project_name, slot_label?, chat_name?, model?, client_type?}.
|
|
362
|
+
async createChat(opts) {
|
|
363
|
+
return await this.request("/api/projects/chat/new", {
|
|
364
|
+
method: "POST",
|
|
365
|
+
body: JSON.stringify({
|
|
366
|
+
project_name: opts.projectName,
|
|
367
|
+
slot_label: opts.title,
|
|
368
|
+
chat_name: opts.title,
|
|
369
|
+
model: opts.model,
|
|
370
|
+
client_type: "cli"
|
|
371
|
+
})
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
// CLI-BROADCAST-01 (Iter 34): broadcast a prompt to sibling chats in a
|
|
375
|
+
// project. Per LAB broadcast.py:145 — POST /api/broadcast/execute with
|
|
376
|
+
// {project_name, prompt, source_chat_id?, max_targets?}.
|
|
377
|
+
async broadcastExecute(opts) {
|
|
378
|
+
return await this.request("/api/broadcast/execute", {
|
|
379
|
+
method: "POST",
|
|
380
|
+
body: JSON.stringify({
|
|
381
|
+
project_name: opts.projectName,
|
|
382
|
+
prompt: opts.prompt,
|
|
383
|
+
source_chat_id: opts.sourceChatId,
|
|
384
|
+
max_targets: opts.maxTargets
|
|
385
|
+
})
|
|
386
|
+
});
|
|
387
|
+
}
|
|
269
388
|
async getModels() {
|
|
270
|
-
return await this.request("/api/models");
|
|
389
|
+
return await this.request("/api/benchmark/models");
|
|
271
390
|
}
|
|
272
391
|
/**
|
|
273
392
|
* Fetch the canonical tool registry from the backend.
|
|
@@ -8588,7 +8707,110 @@ function resolveChat(arg, chats) {
|
|
|
8588
8707
|
}
|
|
8589
8708
|
return { kind: "error", message: `no chat matches '${trimmed}'. Run /chat (no args) for the list.` };
|
|
8590
8709
|
}
|
|
8710
|
+
async function createChat(args2, context) {
|
|
8711
|
+
let title = "";
|
|
8712
|
+
let model;
|
|
8713
|
+
for (let i = 0; i < args2.length; i++) {
|
|
8714
|
+
if (args2[i] === "--model" && i + 1 < args2.length) {
|
|
8715
|
+
model = args2[i + 1];
|
|
8716
|
+
i++;
|
|
8717
|
+
} else {
|
|
8718
|
+
title += (title ? " " : "") + args2[i];
|
|
8719
|
+
}
|
|
8720
|
+
}
|
|
8721
|
+
try {
|
|
8722
|
+
const overview = await context.client.me();
|
|
8723
|
+
const currentId = context.getProjectId();
|
|
8724
|
+
const project = overview.projects.find((p) => p.id === currentId) ?? overview.projects[0];
|
|
8725
|
+
if (!project) {
|
|
8726
|
+
context.addMessage("error", "No active project. Use /project new <name> or /project <id> first.");
|
|
8727
|
+
return;
|
|
8728
|
+
}
|
|
8729
|
+
const result = await context.client.createChat({
|
|
8730
|
+
projectName: project.name,
|
|
8731
|
+
title: title || void 0,
|
|
8732
|
+
model: model || void 0
|
|
8733
|
+
});
|
|
8734
|
+
context.addMessage("system", `Created chat "${result.title}" (${result.chat_id}) using ${result.model}`);
|
|
8735
|
+
context.setActiveChatId(result.chat_id);
|
|
8736
|
+
await context.refreshOverview();
|
|
8737
|
+
} catch (e) {
|
|
8738
|
+
context.addMessage("error", `Failed to create chat: ${e.message}`);
|
|
8739
|
+
}
|
|
8740
|
+
}
|
|
8741
|
+
async function resolveChatId(rest, context) {
|
|
8742
|
+
const candidate = rest[0]?.trim();
|
|
8743
|
+
if (candidate && /^[0-9a-fA-F-]{32,}$/.test(candidate)) return candidate;
|
|
8744
|
+
return context.activeChatId ?? null;
|
|
8745
|
+
}
|
|
8746
|
+
async function lifecycleSub(args2, context) {
|
|
8747
|
+
const sub = args2[0]?.toLowerCase();
|
|
8748
|
+
const rest = args2.slice(1);
|
|
8749
|
+
try {
|
|
8750
|
+
if (sub === "rename") {
|
|
8751
|
+
const newTitle = rest.slice(1).join(" ").trim() || rest[0]?.trim();
|
|
8752
|
+
const chatId = await resolveChatId(rest, context);
|
|
8753
|
+
if (!chatId || !newTitle) {
|
|
8754
|
+
context.addMessage("system", "Usage: /chat rename [<chat_id>] <new title>");
|
|
8755
|
+
return;
|
|
8756
|
+
}
|
|
8757
|
+
const r = await context.client.renameChat(chatId, newTitle);
|
|
8758
|
+
context.addMessage("system", `Renamed to "${r.title}"`);
|
|
8759
|
+
return;
|
|
8760
|
+
}
|
|
8761
|
+
if (sub === "delete" || sub === "rm") {
|
|
8762
|
+
const chatId = await resolveChatId(rest, context);
|
|
8763
|
+
if (!chatId) {
|
|
8764
|
+
context.addMessage("system", "Usage: /chat delete [<chat_id>]");
|
|
8765
|
+
return;
|
|
8766
|
+
}
|
|
8767
|
+
await context.client.deleteChat(chatId);
|
|
8768
|
+
context.addMessage("system", `Deleted chat ${chatId}`);
|
|
8769
|
+
if (chatId === context.activeChatId) context.setActiveChatId(null);
|
|
8770
|
+
return;
|
|
8771
|
+
}
|
|
8772
|
+
if (sub === "fork") {
|
|
8773
|
+
const chatId = await resolveChatId(rest, context);
|
|
8774
|
+
if (!chatId) {
|
|
8775
|
+
context.addMessage("system", "Usage: /chat fork [<chat_id>]");
|
|
8776
|
+
return;
|
|
8777
|
+
}
|
|
8778
|
+
const r = await context.client.forkChat(chatId);
|
|
8779
|
+
context.addMessage("system", `Forked \u2192 ${r.chat_id ?? r.title ?? "(ok)"}`);
|
|
8780
|
+
if (r.chat_id) context.setActiveChatId(r.chat_id);
|
|
8781
|
+
return;
|
|
8782
|
+
}
|
|
8783
|
+
if (sub === "pin") {
|
|
8784
|
+
const chatId = await resolveChatId(rest, context);
|
|
8785
|
+
if (!chatId) {
|
|
8786
|
+
context.addMessage("system", "Usage: /chat pin [<chat_id>]");
|
|
8787
|
+
return;
|
|
8788
|
+
}
|
|
8789
|
+
await context.client.pinChat(chatId, true);
|
|
8790
|
+
context.addMessage("system", `Pinned ${chatId}`);
|
|
8791
|
+
return;
|
|
8792
|
+
}
|
|
8793
|
+
if (sub === "unpin") {
|
|
8794
|
+
const chatId = await resolveChatId(rest, context);
|
|
8795
|
+
if (!chatId) {
|
|
8796
|
+
context.addMessage("system", "Usage: /chat unpin [<chat_id>]");
|
|
8797
|
+
return;
|
|
8798
|
+
}
|
|
8799
|
+
await context.client.pinChat(chatId, false);
|
|
8800
|
+
context.addMessage("system", `Unpinned ${chatId}`);
|
|
8801
|
+
return;
|
|
8802
|
+
}
|
|
8803
|
+
} catch (e) {
|
|
8804
|
+
context.addMessage("error", `Chat ${sub}: ${e.message}`);
|
|
8805
|
+
}
|
|
8806
|
+
}
|
|
8591
8807
|
async function listChats(args2, context) {
|
|
8808
|
+
if (args2[0] === "new" || args2[0] === "create") {
|
|
8809
|
+
return createChat(args2.slice(1), context);
|
|
8810
|
+
}
|
|
8811
|
+
if (["rename", "delete", "rm", "fork", "pin", "unpin"].includes(args2[0])) {
|
|
8812
|
+
return lifecycleSub(args2, context);
|
|
8813
|
+
}
|
|
8592
8814
|
const arg = args2.join(" ").trim();
|
|
8593
8815
|
const result = await fetchChatsForCurrentProject(context);
|
|
8594
8816
|
if ("error" in result) {
|
|
@@ -8643,6 +8865,291 @@ var init_chat = __esm({
|
|
|
8643
8865
|
}
|
|
8644
8866
|
});
|
|
8645
8867
|
|
|
8868
|
+
// src/commands/broadcast.ts
|
|
8869
|
+
var broadcastCommand;
|
|
8870
|
+
var init_broadcast = __esm({
|
|
8871
|
+
"src/commands/broadcast.ts"() {
|
|
8872
|
+
"use strict";
|
|
8873
|
+
init_esm_shims();
|
|
8874
|
+
broadcastCommand = {
|
|
8875
|
+
name: "broadcast",
|
|
8876
|
+
aliases: ["bcast"],
|
|
8877
|
+
args: "[--max N] [--exclude-current] <prompt>",
|
|
8878
|
+
description: "Send a prompt to every sibling chat in the active project (rate-limited 10/min).",
|
|
8879
|
+
category: "chat",
|
|
8880
|
+
handler: async (args2, context) => {
|
|
8881
|
+
let maxTargets = 8;
|
|
8882
|
+
let excludeCurrent = false;
|
|
8883
|
+
const promptParts = [];
|
|
8884
|
+
for (let i = 0; i < args2.length; i++) {
|
|
8885
|
+
if (args2[i] === "--max" && i + 1 < args2.length) {
|
|
8886
|
+
const n = Number(args2[i + 1]);
|
|
8887
|
+
if (Number.isFinite(n) && n > 0) maxTargets = Math.min(32, Math.floor(n));
|
|
8888
|
+
i++;
|
|
8889
|
+
continue;
|
|
8890
|
+
}
|
|
8891
|
+
if (args2[i] === "--exclude-current") {
|
|
8892
|
+
excludeCurrent = true;
|
|
8893
|
+
continue;
|
|
8894
|
+
}
|
|
8895
|
+
promptParts.push(args2[i]);
|
|
8896
|
+
}
|
|
8897
|
+
const prompt4 = promptParts.join(" ").trim();
|
|
8898
|
+
if (!prompt4) {
|
|
8899
|
+
context.addMessage("system", "Usage: /broadcast [--max N] [--exclude-current] <prompt>");
|
|
8900
|
+
return;
|
|
8901
|
+
}
|
|
8902
|
+
try {
|
|
8903
|
+
const overview = await context.client.me();
|
|
8904
|
+
const currentId = context.getProjectId();
|
|
8905
|
+
const project = overview.projects.find((p) => p.id === currentId) ?? overview.projects[0];
|
|
8906
|
+
if (!project) {
|
|
8907
|
+
context.addMessage("error", "No active project. Use /project <id> first.");
|
|
8908
|
+
return;
|
|
8909
|
+
}
|
|
8910
|
+
const result = await context.client.broadcastExecute({
|
|
8911
|
+
projectName: project.name,
|
|
8912
|
+
prompt: prompt4,
|
|
8913
|
+
sourceChatId: excludeCurrent ? context.activeChatId ?? void 0 : void 0,
|
|
8914
|
+
maxTargets
|
|
8915
|
+
});
|
|
8916
|
+
context.addMessage(
|
|
8917
|
+
"system",
|
|
8918
|
+
`Broadcast queued: ${result.broadcast_id} \u2192 ${result.target_chat_ids?.length ?? 0} chat(s) in project '${project.name}'.`
|
|
8919
|
+
);
|
|
8920
|
+
if (Array.isArray(result.target_chat_ids) && result.target_chat_ids.length > 0) {
|
|
8921
|
+
for (const cid of result.target_chat_ids.slice(0, 8)) {
|
|
8922
|
+
context.addMessage("system", ` - ${cid}`);
|
|
8923
|
+
}
|
|
8924
|
+
if (result.target_chat_ids.length > 8) {
|
|
8925
|
+
context.addMessage("system", ` \u2026and ${result.target_chat_ids.length - 8} more.`);
|
|
8926
|
+
}
|
|
8927
|
+
}
|
|
8928
|
+
} catch (e) {
|
|
8929
|
+
context.addMessage("error", `Broadcast failed: ${e.message}`);
|
|
8930
|
+
}
|
|
8931
|
+
}
|
|
8932
|
+
};
|
|
8933
|
+
}
|
|
8934
|
+
});
|
|
8935
|
+
|
|
8936
|
+
// src/commands/ollama.ts
|
|
8937
|
+
function formatSize(bytes) {
|
|
8938
|
+
if (!bytes) return "?";
|
|
8939
|
+
const gb = bytes / 1e9;
|
|
8940
|
+
if (gb >= 1) return `${gb.toFixed(1)} GB`;
|
|
8941
|
+
const mb = bytes / 1e6;
|
|
8942
|
+
return `${mb.toFixed(0)} MB`;
|
|
8943
|
+
}
|
|
8944
|
+
var DEFAULT_BASE_URL, ollamaCommand;
|
|
8945
|
+
var init_ollama = __esm({
|
|
8946
|
+
"src/commands/ollama.ts"() {
|
|
8947
|
+
"use strict";
|
|
8948
|
+
init_esm_shims();
|
|
8949
|
+
DEFAULT_BASE_URL = "http://localhost:11434";
|
|
8950
|
+
ollamaCommand = {
|
|
8951
|
+
name: "ollama",
|
|
8952
|
+
args: "[status|configure|enable|disable|test|models|pull|delete] [...args]",
|
|
8953
|
+
description: "Configure local Ollama integration (BYOK free tier) and manage local models.",
|
|
8954
|
+
category: "config",
|
|
8955
|
+
handler: async (args2, context) => {
|
|
8956
|
+
const sub = (args2[0] ?? "status").toLowerCase();
|
|
8957
|
+
const rest = args2.slice(1);
|
|
8958
|
+
try {
|
|
8959
|
+
if (sub === "status" || sub === "models") {
|
|
8960
|
+
const s = await context.client.getOllamaStatus();
|
|
8961
|
+
context.addMessage("system", "=== Ollama Status ===");
|
|
8962
|
+
context.addMessage("system", ` Enabled: ${s.enabled ? "yes" : "no"}`);
|
|
8963
|
+
context.addMessage("system", ` Base URL: ${s.base_url}`);
|
|
8964
|
+
context.addMessage("system", ` Connected: ${s.connected ? "yes" : "no"}${s.connection_message ? " \u2014 " + s.connection_message : ""}`);
|
|
8965
|
+
if (s.models?.length) {
|
|
8966
|
+
context.addMessage("system", ` Models (${s.models.length}):`);
|
|
8967
|
+
for (const m of s.models) {
|
|
8968
|
+
context.addMessage("system", ` - ${m.id} (${formatSize(m.size)})`);
|
|
8969
|
+
}
|
|
8970
|
+
} else if (s.enabled) {
|
|
8971
|
+
context.addMessage("system", " Models: (none pulled \u2014 try /ollama pull <name>, e.g. llama3.2)");
|
|
8972
|
+
} else {
|
|
8973
|
+
context.addMessage("system", "");
|
|
8974
|
+
context.addMessage("system", " Run '/ollama configure' to enable.");
|
|
8975
|
+
}
|
|
8976
|
+
return;
|
|
8977
|
+
}
|
|
8978
|
+
if (sub === "configure" || sub === "enable") {
|
|
8979
|
+
const url = rest[0] || DEFAULT_BASE_URL;
|
|
8980
|
+
const res = await context.client.configureOllama({ baseUrl: url, enabled: true });
|
|
8981
|
+
context.addMessage("system", `Ollama enabled at ${url}: ${res.message ?? res.status}`);
|
|
8982
|
+
return;
|
|
8983
|
+
}
|
|
8984
|
+
if (sub === "disable") {
|
|
8985
|
+
const res = await context.client.disableOllama();
|
|
8986
|
+
context.addMessage("system", `Ollama disabled: ${res.message ?? res.status}`);
|
|
8987
|
+
return;
|
|
8988
|
+
}
|
|
8989
|
+
if (sub === "test") {
|
|
8990
|
+
const url = rest[0] || DEFAULT_BASE_URL;
|
|
8991
|
+
const res = await context.client.testOllama(url);
|
|
8992
|
+
context.addMessage("system", `Connection to ${url}: ${res.connected ? "OK" : "FAILED"} \u2014 ${res.message}`);
|
|
8993
|
+
if (res.models?.length) {
|
|
8994
|
+
context.addMessage("system", ` Found ${res.models.length} model(s):`);
|
|
8995
|
+
for (const m of res.models.slice(0, 12)) {
|
|
8996
|
+
context.addMessage("system", ` - ${m.id}`);
|
|
8997
|
+
}
|
|
8998
|
+
if (res.models.length > 12) context.addMessage("system", ` \u2026and ${res.models.length - 12} more.`);
|
|
8999
|
+
}
|
|
9000
|
+
return;
|
|
9001
|
+
}
|
|
9002
|
+
if (sub === "pull") {
|
|
9003
|
+
const model = rest[0];
|
|
9004
|
+
if (!model) {
|
|
9005
|
+
context.addMessage("system", "Usage: /ollama pull <model> (e.g. /ollama pull llama3.2)");
|
|
9006
|
+
return;
|
|
9007
|
+
}
|
|
9008
|
+
const status = await context.client.getOllamaStatus();
|
|
9009
|
+
const res = await context.client.configureOllama({
|
|
9010
|
+
baseUrl: status.base_url || DEFAULT_BASE_URL,
|
|
9011
|
+
enabled: status.enabled !== false,
|
|
9012
|
+
action: "pull",
|
|
9013
|
+
model
|
|
9014
|
+
});
|
|
9015
|
+
context.addMessage("system", res.message ?? res.status);
|
|
9016
|
+
return;
|
|
9017
|
+
}
|
|
9018
|
+
if (sub === "delete" || sub === "remove" || sub === "rm") {
|
|
9019
|
+
const model = rest[0];
|
|
9020
|
+
if (!model) {
|
|
9021
|
+
context.addMessage("system", "Usage: /ollama delete <model>");
|
|
9022
|
+
return;
|
|
9023
|
+
}
|
|
9024
|
+
const res = await context.client.deleteOllamaModel(model);
|
|
9025
|
+
context.addMessage("system", res.message ?? res.status);
|
|
9026
|
+
return;
|
|
9027
|
+
}
|
|
9028
|
+
context.addMessage("error", `Unknown /ollama subcommand '${sub}'. Try: status, configure, disable, test, pull, delete.`);
|
|
9029
|
+
} catch (e) {
|
|
9030
|
+
context.addMessage("error", `Ollama: ${e.message}`);
|
|
9031
|
+
}
|
|
9032
|
+
}
|
|
9033
|
+
};
|
|
9034
|
+
}
|
|
9035
|
+
});
|
|
9036
|
+
|
|
9037
|
+
// src/commands/keys.ts
|
|
9038
|
+
var keysCommand;
|
|
9039
|
+
var init_keys = __esm({
|
|
9040
|
+
"src/commands/keys.ts"() {
|
|
9041
|
+
"use strict";
|
|
9042
|
+
init_esm_shims();
|
|
9043
|
+
keysCommand = {
|
|
9044
|
+
name: "keys",
|
|
9045
|
+
args: "[list|add|delete] [...args]",
|
|
9046
|
+
description: "Manage BYOK provider API keys (openai, anthropic, google, openrouter, \u2026).",
|
|
9047
|
+
category: "config",
|
|
9048
|
+
handler: async (args2, context) => {
|
|
9049
|
+
const sub = (args2[0] ?? "list").toLowerCase();
|
|
9050
|
+
const rest = args2.slice(1);
|
|
9051
|
+
try {
|
|
9052
|
+
if (sub === "list" || sub === "status") {
|
|
9053
|
+
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}`);
|
|
9060
|
+
}
|
|
9061
|
+
if (providers.length === 0) {
|
|
9062
|
+
context.addMessage("system", " (none \u2014 add via /keys add <provider> <key>)");
|
|
9063
|
+
}
|
|
9064
|
+
return;
|
|
9065
|
+
}
|
|
9066
|
+
if (sub === "add" || sub === "save") {
|
|
9067
|
+
const provider = rest[0];
|
|
9068
|
+
const key = rest.slice(1).join(" ").trim();
|
|
9069
|
+
if (!provider || !key) {
|
|
9070
|
+
context.addMessage("system", "Usage: /keys add <provider> <key> (e.g. /keys add openai sk-...)");
|
|
9071
|
+
return;
|
|
9072
|
+
}
|
|
9073
|
+
const res = await context.client.saveProviderKey(provider, key);
|
|
9074
|
+
context.addMessage("system", `Saved key for ${provider}: ${res.message ?? res.status}`);
|
|
9075
|
+
return;
|
|
9076
|
+
}
|
|
9077
|
+
if (sub === "delete" || sub === "rm" || sub === "remove") {
|
|
9078
|
+
const provider = rest[0];
|
|
9079
|
+
if (!provider) {
|
|
9080
|
+
context.addMessage("system", "Usage: /keys delete <provider>");
|
|
9081
|
+
return;
|
|
9082
|
+
}
|
|
9083
|
+
const res = await context.client.deleteProviderKey(provider);
|
|
9084
|
+
context.addMessage("system", `Removed key for ${provider}: ${res.message ?? res.status}`);
|
|
9085
|
+
return;
|
|
9086
|
+
}
|
|
9087
|
+
context.addMessage("error", `Unknown /keys subcommand '${sub}'. Try: list, add, delete.`);
|
|
9088
|
+
} catch (e) {
|
|
9089
|
+
context.addMessage("error", `Keys: ${e.message}`);
|
|
9090
|
+
}
|
|
9091
|
+
}
|
|
9092
|
+
};
|
|
9093
|
+
}
|
|
9094
|
+
});
|
|
9095
|
+
|
|
9096
|
+
// src/commands/memories.ts
|
|
9097
|
+
var memoriesCommand;
|
|
9098
|
+
var init_memories = __esm({
|
|
9099
|
+
"src/commands/memories.ts"() {
|
|
9100
|
+
"use strict";
|
|
9101
|
+
init_esm_shims();
|
|
9102
|
+
memoriesCommand = {
|
|
9103
|
+
name: "memories",
|
|
9104
|
+
args: "[list|add|delete] [...args]",
|
|
9105
|
+
description: "Manage the user-scoped memory bank (used across all chats).",
|
|
9106
|
+
category: "project",
|
|
9107
|
+
handler: async (args2, context) => {
|
|
9108
|
+
const sub = (args2[0] ?? "list").toLowerCase();
|
|
9109
|
+
const rest = args2.slice(1);
|
|
9110
|
+
try {
|
|
9111
|
+
if (sub === "list" || sub === "show") {
|
|
9112
|
+
const items = await context.client.listMemories();
|
|
9113
|
+
if (!items || items.length === 0) {
|
|
9114
|
+
context.addMessage("system", "No memories yet. Add one via /memories add <text>.");
|
|
9115
|
+
return;
|
|
9116
|
+
}
|
|
9117
|
+
context.addMessage("system", `Memories (${items.length}):`);
|
|
9118
|
+
for (const m of items) {
|
|
9119
|
+
const when = m.created_at ? new Date(m.created_at).toISOString().slice(0, 10) : "";
|
|
9120
|
+
context.addMessage("system", ` ${m.id?.slice(0, 8)} \xB7 ${when} ${m.content}`);
|
|
9121
|
+
}
|
|
9122
|
+
return;
|
|
9123
|
+
}
|
|
9124
|
+
if (sub === "add" || sub === "save") {
|
|
9125
|
+
const content = rest.join(" ").trim();
|
|
9126
|
+
if (!content) {
|
|
9127
|
+
context.addMessage("system", "Usage: /memories add <content>");
|
|
9128
|
+
return;
|
|
9129
|
+
}
|
|
9130
|
+
const m = await context.client.createMemory(content);
|
|
9131
|
+
context.addMessage("system", `Saved (${m.id?.slice(0, 8)}).`);
|
|
9132
|
+
return;
|
|
9133
|
+
}
|
|
9134
|
+
if (sub === "delete" || sub === "rm" || sub === "remove") {
|
|
9135
|
+
const id = rest[0]?.trim();
|
|
9136
|
+
if (!id) {
|
|
9137
|
+
context.addMessage("system", "Usage: /memories delete <id>");
|
|
9138
|
+
return;
|
|
9139
|
+
}
|
|
9140
|
+
await context.client.deleteMemory(id);
|
|
9141
|
+
context.addMessage("system", `Deleted ${id.slice(0, 8)}.`);
|
|
9142
|
+
return;
|
|
9143
|
+
}
|
|
9144
|
+
context.addMessage("error", `Unknown /memories subcommand '${sub}'. Try: list, add, delete.`);
|
|
9145
|
+
} catch (e) {
|
|
9146
|
+
context.addMessage("error", `Memories: ${e.message}`);
|
|
9147
|
+
}
|
|
9148
|
+
}
|
|
9149
|
+
};
|
|
9150
|
+
}
|
|
9151
|
+
});
|
|
9152
|
+
|
|
8646
9153
|
// src/commands/clear.ts
|
|
8647
9154
|
var clearCommand;
|
|
8648
9155
|
var init_clear = __esm({
|
|
@@ -8800,8 +9307,47 @@ Current: ${current}`);
|
|
|
8800
9307
|
}
|
|
8801
9308
|
return;
|
|
8802
9309
|
}
|
|
8803
|
-
|
|
8804
|
-
|
|
9310
|
+
try {
|
|
9311
|
+
const models = await context.client.getModels();
|
|
9312
|
+
const list = models.filter((m) => !!m.id);
|
|
9313
|
+
const trimmed = newModel.trim();
|
|
9314
|
+
const exact = list.find((m) => m.id === trimmed);
|
|
9315
|
+
if (exact) {
|
|
9316
|
+
context.setModel(exact.id);
|
|
9317
|
+
context.addMessage("system", `Model switched to: ${exact.id}`);
|
|
9318
|
+
return;
|
|
9319
|
+
}
|
|
9320
|
+
if (/^\d+$/.test(trimmed)) {
|
|
9321
|
+
const idx = parseInt(trimmed, 10) - 1;
|
|
9322
|
+
if (idx >= 0 && idx < list.length && list[idx].id) {
|
|
9323
|
+
context.setModel(list[idx].id);
|
|
9324
|
+
context.addMessage("system", `Model switched to: ${list[idx].id}`);
|
|
9325
|
+
return;
|
|
9326
|
+
}
|
|
9327
|
+
}
|
|
9328
|
+
const lower = trimmed.toLowerCase();
|
|
9329
|
+
const subs = list.filter((m) => (m.id ?? "").toLowerCase().includes(lower));
|
|
9330
|
+
if (subs.length === 1) {
|
|
9331
|
+
context.setModel(subs[0].id);
|
|
9332
|
+
context.addMessage("system", `Model switched to: ${subs[0].id}`);
|
|
9333
|
+
return;
|
|
9334
|
+
}
|
|
9335
|
+
if (subs.length > 1 && subs.length <= 10) {
|
|
9336
|
+
context.addMessage(
|
|
9337
|
+
"error",
|
|
9338
|
+
`'${trimmed}' matches ${subs.length} models: ${subs.map((m) => m.id).join(", ")}`
|
|
9339
|
+
);
|
|
9340
|
+
return;
|
|
9341
|
+
}
|
|
9342
|
+
if (subs.length > 10) {
|
|
9343
|
+
context.addMessage("error", `'${trimmed}' matches ${subs.length} models \u2014 be more specific.`);
|
|
9344
|
+
return;
|
|
9345
|
+
}
|
|
9346
|
+
context.addMessage("error", `No model matches '${trimmed}'. Run /model (no args) for the list of ${list.length} models.`);
|
|
9347
|
+
} catch (e) {
|
|
9348
|
+
context.setModel(newModel);
|
|
9349
|
+
context.addMessage("system", `Model switched to: ${newModel} (unverified \u2014 model catalog unreachable: ${e.message})`);
|
|
9350
|
+
}
|
|
8805
9351
|
}
|
|
8806
9352
|
};
|
|
8807
9353
|
}
|
|
@@ -8946,6 +9492,22 @@ var init_project = __esm({
|
|
|
8946
9492
|
handler: async (args2, context) => {
|
|
8947
9493
|
const arg = args2.join(" ").trim();
|
|
8948
9494
|
const currentId = context.getProjectId() || null;
|
|
9495
|
+
if (args2[0] === "new" || args2[0] === "create") {
|
|
9496
|
+
const name = args2.slice(1).join(" ").trim();
|
|
9497
|
+
if (!name) {
|
|
9498
|
+
context.addMessage("system", "Usage: /project new <name>");
|
|
9499
|
+
return;
|
|
9500
|
+
}
|
|
9501
|
+
try {
|
|
9502
|
+
const result = await context.client.createProject(name);
|
|
9503
|
+
context.addMessage("system", `Created project "${result.project}" (${result.project_id})`);
|
|
9504
|
+
context.setProjectId(result.project_id);
|
|
9505
|
+
await context.refreshOverview();
|
|
9506
|
+
} catch (e) {
|
|
9507
|
+
context.addMessage("error", `Failed to create project: ${e.message}`);
|
|
9508
|
+
}
|
|
9509
|
+
return;
|
|
9510
|
+
}
|
|
8949
9511
|
let projects = [];
|
|
8950
9512
|
try {
|
|
8951
9513
|
const overview = await context.client.me();
|
|
@@ -9876,7 +10438,7 @@ var init_version = __esm({
|
|
|
9876
10438
|
description: "Show version information for CLI and core packages",
|
|
9877
10439
|
category: "debug",
|
|
9878
10440
|
handler: async (_args, context) => {
|
|
9879
|
-
const cliVersion = true ? "2.3.6-beta.
|
|
10441
|
+
const cliVersion = true ? "2.3.6-beta.24" : "(dev)";
|
|
9880
10442
|
const coreVersion = true ? "2.3.2" : "(dev)";
|
|
9881
10443
|
const runtime = process.version;
|
|
9882
10444
|
context.addMessage("system", "MSapling Version Info");
|
|
@@ -9885,7 +10447,7 @@ var init_version = __esm({
|
|
|
9885
10447
|
context.addMessage("system", row2("Core (@msapling/core)", coreVersion));
|
|
9886
10448
|
context.addMessage("system", row2("Runtime (Node/Bun)", runtime));
|
|
9887
10449
|
try {
|
|
9888
|
-
const ts = "2026-05-28T19:
|
|
10450
|
+
const ts = "2026-05-28T19:31:59.228Z";
|
|
9889
10451
|
if (ts && ts !== "__BUILD_TIMESTAMP__") {
|
|
9890
10452
|
context.addMessage("system", row2("Build Timestamp", ts));
|
|
9891
10453
|
}
|
|
@@ -10624,6 +11186,10 @@ var init_commands = __esm({
|
|
|
10624
11186
|
init_exit();
|
|
10625
11187
|
init_help();
|
|
10626
11188
|
init_chat();
|
|
11189
|
+
init_broadcast();
|
|
11190
|
+
init_ollama();
|
|
11191
|
+
init_keys();
|
|
11192
|
+
init_memories();
|
|
10627
11193
|
init_clear();
|
|
10628
11194
|
init_mode();
|
|
10629
11195
|
init_model();
|
|
@@ -10659,6 +11225,10 @@ var init_commands = __esm({
|
|
|
10659
11225
|
helpCommand,
|
|
10660
11226
|
chatCommand,
|
|
10661
11227
|
chatsCommand,
|
|
11228
|
+
broadcastCommand,
|
|
11229
|
+
ollamaCommand,
|
|
11230
|
+
keysCommand,
|
|
11231
|
+
memoriesCommand,
|
|
10662
11232
|
clearCommand,
|
|
10663
11233
|
modeCommand,
|
|
10664
11234
|
modelCommand,
|
|
@@ -14288,7 +14858,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
14288
14858
|
var Header = () => /* @__PURE__ */ jsxs(Box, { borderStyle: "single", borderColor: "cyan", paddingX: 1, marginBottom: 1, children: [
|
|
14289
14859
|
/* @__PURE__ */ jsxs(Text, { bold: true, color: "cyan", children: [
|
|
14290
14860
|
"\u25CF MSapling CLI v",
|
|
14291
|
-
"2.3.6-beta.
|
|
14861
|
+
"2.3.6-beta.24"
|
|
14292
14862
|
] }),
|
|
14293
14863
|
/* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "Platinum Tier Architecture" }) })
|
|
14294
14864
|
] });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mtreeai/msapling-cli",
|
|
3
|
-
"version": "2.3.6-beta.
|
|
3
|
+
"version": "2.3.6-beta.24",
|
|
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",
|