@mtreeai/msapling-cli 2.3.6-beta.27 → 2.3.6-beta.28

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 +695 -7
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -356,6 +356,98 @@ var init_src = __esm({
356
356
  async disableOllama() {
357
357
  return await this.request("/api/ollama/disable", { method: "POST" });
358
358
  }
359
+ // Parity Task Card implementations
360
+ // Card 1: Usage Tracking (synced from /api/usage/sync-offline)
361
+ async syncOfflineUsage() {
362
+ return await this.request("/api/usage/sync-offline", { method: "POST" });
363
+ }
364
+ // Card 2: Budget Buckets (7 bucket types)
365
+ async getBillingBuckets() {
366
+ return await this.request("/api/billing/buckets");
367
+ }
368
+ // Card 4: Image Generation
369
+ async generateImage(prompt4, model) {
370
+ return await this.request("/api/image/generate", {
371
+ method: "POST",
372
+ body: JSON.stringify({ prompt: prompt4, model })
373
+ });
374
+ }
375
+ // Card 5: Voice/Audio Operations
376
+ async listVoices() {
377
+ return await this.request("/api/audio/voices");
378
+ }
379
+ async speak(text, voice) {
380
+ return await this.request("/api/audio/speak", {
381
+ method: "POST",
382
+ body: JSON.stringify({ text, voice })
383
+ });
384
+ }
385
+ // Card 8: Chat Sharing
386
+ async shareChat(chatId, expiryDays) {
387
+ return await this.request(`/api/share/chat/${encodeURIComponent(chatId)}/share`, {
388
+ method: "POST",
389
+ body: JSON.stringify({ expiry_days: expiryDays })
390
+ });
391
+ }
392
+ async listShares() {
393
+ return await this.request("/api/share");
394
+ }
395
+ async fetchSharedChat(token) {
396
+ return await this.request(`/api/shared/${encodeURIComponent(token)}`);
397
+ }
398
+ // Card 9: Notifications (preferences only)
399
+ async getNotificationPreferences() {
400
+ return await this.request("/api/notifications/preferences");
401
+ }
402
+ async setNotificationPreferences(prefs) {
403
+ return await this.request("/api/notifications/preferences", {
404
+ method: "PATCH",
405
+ body: JSON.stringify(prefs)
406
+ });
407
+ }
408
+ // Card 10: MLineage Events List
409
+ async listMLineageEvents() {
410
+ return await this.request("/api/mlineage/events");
411
+ }
412
+ // Card 11: Per-Project Model Config
413
+ async setProjectModel(projectId, model) {
414
+ return await this.request(`/api/projects/${encodeURIComponent(projectId)}`, {
415
+ method: "PATCH",
416
+ body: JSON.stringify({ default_model: model })
417
+ });
418
+ }
419
+ // Card 12: MFA/TOTP
420
+ async enrollMFA(method) {
421
+ return await this.request("/api/mfa/enroll", {
422
+ method: "POST",
423
+ body: JSON.stringify({ method })
424
+ });
425
+ }
426
+ async verifyMFA(code) {
427
+ return await this.request("/api/mfa/verify", {
428
+ method: "POST",
429
+ body: JSON.stringify({ code })
430
+ });
431
+ }
432
+ // Card 13: MCP Client Surface
433
+ async mcpConnect(serverUrl) {
434
+ return await this.request("/api/mcp/connect", {
435
+ method: "POST",
436
+ body: JSON.stringify({ server_url: serverUrl })
437
+ });
438
+ }
439
+ async mcpTools() {
440
+ return await this.request("/api/mcp/tools");
441
+ }
442
+ async mcpInvoke(method, args2) {
443
+ return await this.request("/api/mcp/invoke", {
444
+ method: "POST",
445
+ body: JSON.stringify({ method, args: args2 })
446
+ });
447
+ }
448
+ async mcpDisconnect() {
449
+ return await this.request("/api/mcp/disconnect", { method: "POST" });
450
+ }
359
451
  // CLI-KEYS-BYOK-01 (Iter 35): BYOK provider-key management. Per LAB
360
452
  // routers/keys.py — /api/keys/{status,save,{provider}}.
361
453
  async getProviderKeys() {
@@ -732,6 +824,32 @@ var init_src = __esm({
732
824
  async getActiveTasks() {
733
825
  return this.request("/api/task-monitor/active");
734
826
  }
827
+ /**
828
+ * Webhook Management (LAB-WEBHOOK-CRUD-01)
829
+ */
830
+ async listWebhooks() {
831
+ return this.request("/api/webhooks");
832
+ }
833
+ async createWebhook(url, events) {
834
+ return this.request("/api/webhooks", {
835
+ method: "POST",
836
+ body: JSON.stringify({ url, events })
837
+ });
838
+ }
839
+ async deleteWebhook(id) {
840
+ await this.request(`/api/webhooks/${encodeURIComponent(id)}`, {
841
+ method: "DELETE"
842
+ });
843
+ }
844
+ async listWebhookDeliveries(webhookId) {
845
+ const path2 = webhookId ? `/api/webhooks/deliveries?webhook_id=${encodeURIComponent(webhookId)}` : "/api/webhooks/deliveries";
846
+ return this.request(path2);
847
+ }
848
+ async retryWebhookDelivery(deliveryId) {
849
+ return this.request(`/api/webhooks/deliveries/${encodeURIComponent(deliveryId)}/retry`, {
850
+ method: "POST"
851
+ });
852
+ }
735
853
  /**
736
854
  * Wakeup Management (LAB-CHAT-PARITY-04)
737
855
  */
@@ -9575,11 +9693,19 @@ var init_usage = __esm({
9575
9693
  init_esm_shims();
9576
9694
  usageCommand = {
9577
9695
  name: "usage",
9578
- description: "Show detailed usage, fuel balance, and daily quota",
9696
+ args: "[--json] [--since DATE]",
9697
+ description: "Show detailed usage, fuel balance, and daily quota; sync offline usage",
9579
9698
  category: "chat",
9580
9699
  handler: async (args2, context) => {
9581
9700
  try {
9701
+ const isJson = args2.includes("--json");
9582
9702
  const user = await context.client.getLiveUsage();
9703
+ await context.client.syncOfflineUsage().catch(() => {
9704
+ });
9705
+ if (isJson) {
9706
+ context.addMessage("system", JSON.stringify(user, null, 2));
9707
+ return;
9708
+ }
9583
9709
  context.addMessage("system", "MSapling Usage Dashboard:");
9584
9710
  context.addMessage("system", ` - Fuel Credits: $${user.fuel_credits.toFixed(4)}`);
9585
9711
  context.addMessage("system", ` - Daily Spending Limit: ${user.monthly_spending_limit ? "$" + user.monthly_spending_limit : "Unlimited"}`);
@@ -9680,12 +9806,31 @@ var init_project = __esm({
9680
9806
  LETTERS2 = "abcdefghijklmnopqrstuvwxyz";
9681
9807
  projectCommand = {
9682
9808
  name: "project",
9683
- args: "[number|letter|name|id]",
9684
- description: "List or switch active project",
9809
+ args: "[number|letter|name|id|config]",
9810
+ description: "List or switch active project, or set per-project config",
9685
9811
  category: "project",
9686
9812
  handler: async (args2, context) => {
9687
9813
  const arg = args2.join(" ").trim();
9688
9814
  const currentId = context.getProjectId() || null;
9815
+ if (args2[0] === "config") {
9816
+ const modelIdx = args2.indexOf("--model");
9817
+ const model = modelIdx >= 0 ? args2[modelIdx + 1] : void 0;
9818
+ if (!model) {
9819
+ context.addMessage("system", "Usage: /project config --model <MODEL>");
9820
+ return;
9821
+ }
9822
+ if (!currentId) {
9823
+ context.addMessage("error", "No active project. Use /project <id> first.");
9824
+ return;
9825
+ }
9826
+ try {
9827
+ await context.client.setProjectModel(currentId, model);
9828
+ context.addMessage("system", `Project default model set to: ${model}`);
9829
+ } catch (e) {
9830
+ context.addMessage("error", `Failed to set model: ${e.message}`);
9831
+ }
9832
+ return;
9833
+ }
9689
9834
  if (args2[0] === "new" || args2[0] === "create") {
9690
9835
  const name = args2.slice(1).join(" ").trim();
9691
9836
  if (!name) {
@@ -10632,7 +10777,7 @@ var init_version = __esm({
10632
10777
  description: "Show version information for CLI and core packages",
10633
10778
  category: "debug",
10634
10779
  handler: async (_args, context) => {
10635
- const cliVersion = true ? "2.3.6-beta.27" : "(dev)";
10780
+ const cliVersion = true ? "2.3.6-beta.28" : "(dev)";
10636
10781
  const coreVersion = true ? "2.3.2" : "(dev)";
10637
10782
  const runtime = process.version;
10638
10783
  context.addMessage("system", "MSapling Version Info");
@@ -10641,7 +10786,7 @@ var init_version = __esm({
10641
10786
  context.addMessage("system", row2("Core (@msapling/core)", coreVersion));
10642
10787
  context.addMessage("system", row2("Runtime (Node/Bun)", runtime));
10643
10788
  try {
10644
- const ts = "2026-05-29T00:38:48.242Z";
10789
+ const ts = "2026-05-29T17:03:26.902Z";
10645
10790
  if (ts && ts !== "__BUILD_TIMESTAMP__") {
10646
10791
  context.addMessage("system", row2("Build Timestamp", ts));
10647
10792
  }
@@ -11359,6 +11504,529 @@ var init_totp = __esm({
11359
11504
  }
11360
11505
  });
11361
11506
 
11507
+ // src/commands/budget.ts
11508
+ var budgetCommand;
11509
+ var init_budget = __esm({
11510
+ "src/commands/budget.ts"() {
11511
+ "use strict";
11512
+ init_esm_shims();
11513
+ budgetCommand = {
11514
+ name: "budget",
11515
+ description: "Show budget buckets (lifetime, sub, top_up, free, guest, byok, ollama)",
11516
+ category: "config",
11517
+ handler: async (args2, context) => {
11518
+ try {
11519
+ const data = await context.client.getBillingBuckets();
11520
+ context.addMessage("system", "Budget Buckets:");
11521
+ if (data && typeof data === "object") {
11522
+ for (const [key, val] of Object.entries(data)) {
11523
+ const bucket = val;
11524
+ const remaining = bucket.remaining ?? bucket.balance ?? 0;
11525
+ const limit = bucket.limit ?? bucket.cap ?? 0;
11526
+ context.addMessage("system", ` - ${key}: $${remaining.toFixed(4)} / $${limit.toFixed(4)}`);
11527
+ }
11528
+ } else {
11529
+ context.addMessage("system", JSON.stringify(data, null, 2));
11530
+ }
11531
+ } catch (e) {
11532
+ context.addMessage("error", `Failed to fetch budget: ${e.message}`);
11533
+ }
11534
+ }
11535
+ };
11536
+ }
11537
+ });
11538
+
11539
+ // src/commands/image.ts
11540
+ var imageCommand;
11541
+ var init_image = __esm({
11542
+ "src/commands/image.ts"() {
11543
+ "use strict";
11544
+ init_esm_shims();
11545
+ imageCommand = {
11546
+ name: "image",
11547
+ args: "<prompt> [--model MODEL] [--output FILE]",
11548
+ description: "Generate an image from a text prompt",
11549
+ category: "chat",
11550
+ handler: async (args2, context) => {
11551
+ let prompt4 = "";
11552
+ let model = "dall-e-3";
11553
+ let outputFile = null;
11554
+ for (let i = 0; i < args2.length; i++) {
11555
+ if (args2[i] === "--model" && i + 1 < args2.length) {
11556
+ model = args2[++i];
11557
+ continue;
11558
+ }
11559
+ if (args2[i] === "--output" && i + 1 < args2.length) {
11560
+ outputFile = args2[++i];
11561
+ continue;
11562
+ }
11563
+ prompt4 += (prompt4 ? " " : "") + args2[i];
11564
+ }
11565
+ if (!prompt4) {
11566
+ context.addMessage("system", "Usage: /image <prompt> [--model MODEL] [--output FILE]");
11567
+ return;
11568
+ }
11569
+ try {
11570
+ const result = await context.client.generateImage(prompt4, model);
11571
+ context.addMessage("system", `Image generated: ${result.url ?? result.image_url ?? "processing"}`);
11572
+ } catch (e) {
11573
+ context.addMessage("error", `Image generation failed: ${e.message}`);
11574
+ }
11575
+ }
11576
+ };
11577
+ }
11578
+ });
11579
+
11580
+ // src/commands/voice.ts
11581
+ var voiceCommand;
11582
+ var init_voice = __esm({
11583
+ "src/commands/voice.ts"() {
11584
+ "use strict";
11585
+ init_esm_shims();
11586
+ voiceCommand = {
11587
+ name: "voice",
11588
+ args: "[list|speak|transcribe] [args...]",
11589
+ description: "Voice operations: list, speak, or transcribe audio",
11590
+ category: "chat",
11591
+ handler: async (args2, context) => {
11592
+ const sub = (args2[0] ?? "list").toLowerCase();
11593
+ const rest = args2.slice(1);
11594
+ try {
11595
+ if (sub === "list") {
11596
+ const voices = await context.client.listVoices();
11597
+ context.addMessage("system", "Available voices:");
11598
+ if (Array.isArray(voices)) {
11599
+ for (const voice of voices) {
11600
+ context.addMessage("system", ` - ${voice.id ?? voice.name}: ${voice.name ?? voice.id}`);
11601
+ }
11602
+ } else if (typeof voices === "object") {
11603
+ for (const [key, val] of Object.entries(voices)) {
11604
+ context.addMessage("system", ` - ${key}`);
11605
+ }
11606
+ }
11607
+ return;
11608
+ }
11609
+ if (sub === "speak") {
11610
+ const text = rest.join(" ").trim();
11611
+ if (!text) {
11612
+ context.addMessage("system", "Usage: /voice speak --text <TEXT> --voice <VOICE>");
11613
+ return;
11614
+ }
11615
+ const voiceIdx = rest.indexOf("--voice");
11616
+ const voice = voiceIdx >= 0 ? rest[voiceIdx + 1] : "default";
11617
+ const result = await context.client.speak(text, voice);
11618
+ context.addMessage("system", `Audio generated: ${result.url ?? result.audio_url ?? "processing"}`);
11619
+ return;
11620
+ }
11621
+ if (sub === "transcribe") {
11622
+ context.addMessage("system", "Transcribe: pipe audio file to this command (not yet implemented)");
11623
+ return;
11624
+ }
11625
+ context.addMessage("error", `Unknown /voice subcommand '${sub}'. Try: list, speak, transcribe.`);
11626
+ } catch (e) {
11627
+ context.addMessage("error", `Voice: ${e.message}`);
11628
+ }
11629
+ }
11630
+ };
11631
+ }
11632
+ });
11633
+
11634
+ // src/commands/wakeup.ts
11635
+ var wakeupCommand;
11636
+ var init_wakeup = __esm({
11637
+ "src/commands/wakeup.ts"() {
11638
+ "use strict";
11639
+ init_esm_shims();
11640
+ wakeupCommand = {
11641
+ name: "wakeup",
11642
+ args: "[create|list|cancel] [...args]",
11643
+ description: "Manage wakeups (scheduled tasks): create, list, or cancel",
11644
+ category: "config",
11645
+ handler: async (args2, context) => {
11646
+ const sub = (args2[0] ?? "list").toLowerCase();
11647
+ const rest = args2.slice(1);
11648
+ try {
11649
+ if (sub === "list") {
11650
+ const wakeups = await context.client.listWakeups();
11651
+ context.addMessage("system", "Wakeups:");
11652
+ if (Array.isArray(wakeups)) {
11653
+ for (const wu of wakeups) {
11654
+ context.addMessage("system", ` - ${wu.id}: ${wu.reason ?? wu.prompt ?? "scheduled"}`);
11655
+ }
11656
+ } else {
11657
+ context.addMessage("system", JSON.stringify(wakeups, null, 2));
11658
+ }
11659
+ return;
11660
+ }
11661
+ if (sub === "create") {
11662
+ const delayIdx = rest.indexOf("--delay");
11663
+ const delay = delayIdx >= 0 ? Number(rest[delayIdx + 1]) : 60;
11664
+ const reasonIdx = rest.indexOf("--reason");
11665
+ const reason = reasonIdx >= 0 ? rest[reasonIdx + 1] : void 0;
11666
+ const promptIdx = rest.indexOf("--prompt");
11667
+ const prompt4 = promptIdx >= 0 ? rest.slice(promptIdx + 1).join(" ") : void 0;
11668
+ const result = await context.client.createWakeup({
11669
+ delay_seconds: delay,
11670
+ reason,
11671
+ prompt: prompt4
11672
+ });
11673
+ context.addMessage("system", `Wakeup created: ${result.id ?? "ok"}`);
11674
+ return;
11675
+ }
11676
+ if (sub === "cancel") {
11677
+ const id = rest[0];
11678
+ if (!id) {
11679
+ context.addMessage("system", "Usage: /wakeup cancel <ID>");
11680
+ return;
11681
+ }
11682
+ await context.client.cancelWakeup(id);
11683
+ context.addMessage("system", `Wakeup cancelled: ${id}`);
11684
+ return;
11685
+ }
11686
+ context.addMessage("error", `Unknown /wakeup subcommand '${sub}'. Try: list, create, cancel.`);
11687
+ } catch (e) {
11688
+ context.addMessage("error", `Wakeup: ${e.message}`);
11689
+ }
11690
+ }
11691
+ };
11692
+ }
11693
+ });
11694
+
11695
+ // src/commands/share.ts
11696
+ var shareCommand;
11697
+ var init_share = __esm({
11698
+ "src/commands/share.ts"() {
11699
+ "use strict";
11700
+ init_esm_shims();
11701
+ shareCommand = {
11702
+ name: "share",
11703
+ args: "[create|list|fetch] [...args]",
11704
+ description: "Share chats: create, list, or fetch shared conversations",
11705
+ category: "chat",
11706
+ handler: async (args2, context) => {
11707
+ const sub = (args2[0] ?? "list").toLowerCase();
11708
+ const rest = args2.slice(1);
11709
+ try {
11710
+ if (sub === "list") {
11711
+ const shares = await context.client.listShares();
11712
+ context.addMessage("system", "Shared Chats:");
11713
+ if (Array.isArray(shares)) {
11714
+ for (const share of shares) {
11715
+ const expiry = share.expiry_at ? ` (expires ${share.expiry_at})` : "";
11716
+ context.addMessage("system", ` - ${share.token}: chat ${share.chat_id}${expiry}`);
11717
+ }
11718
+ } else {
11719
+ context.addMessage("system", JSON.stringify(shares, null, 2));
11720
+ }
11721
+ return;
11722
+ }
11723
+ if (sub === "create") {
11724
+ const chatId = rest[0];
11725
+ const expiryIdx = rest.indexOf("--expiry");
11726
+ const expiry = expiryIdx >= 0 ? Number(rest[expiryIdx + 1]) : void 0;
11727
+ if (!chatId) {
11728
+ context.addMessage("system", "Usage: /share create <CHAT-ID> [--expiry DAYS]");
11729
+ return;
11730
+ }
11731
+ const result = await context.client.shareChat(chatId, expiry);
11732
+ context.addMessage("system", `Share created: ${result.token ?? result.url ?? "ok"}`);
11733
+ return;
11734
+ }
11735
+ if (sub === "fetch") {
11736
+ const token = rest[0];
11737
+ if (!token) {
11738
+ context.addMessage("system", "Usage: /share fetch <TOKEN>");
11739
+ return;
11740
+ }
11741
+ const result = await context.client.fetchSharedChat(token);
11742
+ context.addMessage("system", `Fetched shared chat: ${result.chat_id ?? result.id}`);
11743
+ return;
11744
+ }
11745
+ context.addMessage("error", `Unknown /share subcommand '${sub}'. Try: list, create, fetch.`);
11746
+ } catch (e) {
11747
+ context.addMessage("error", `Share: ${e.message}`);
11748
+ }
11749
+ }
11750
+ };
11751
+ }
11752
+ });
11753
+
11754
+ // src/commands/notify.ts
11755
+ var notifyCommand;
11756
+ var init_notify = __esm({
11757
+ "src/commands/notify.ts"() {
11758
+ "use strict";
11759
+ init_esm_shims();
11760
+ notifyCommand = {
11761
+ name: "notify",
11762
+ args: "[preferences] [--get|--set KEY=VALUE]",
11763
+ description: "Manage notification preferences (SSE stream not yet implemented)",
11764
+ category: "config",
11765
+ handler: async (args2, context) => {
11766
+ try {
11767
+ if (args2.length === 0 || args2[0] === "preferences" || args2[0] === "--get") {
11768
+ const prefs = await context.client.getNotificationPreferences();
11769
+ context.addMessage("system", "Notification Preferences:");
11770
+ context.addMessage("system", JSON.stringify(prefs, null, 2));
11771
+ return;
11772
+ }
11773
+ if (args2[0] === "--set") {
11774
+ const updates = {};
11775
+ for (let i = 1; i < args2.length; i++) {
11776
+ const pair = args2[i].split("=");
11777
+ if (pair.length === 2) {
11778
+ updates[pair[0]] = pair[1] === "true" ? true : pair[1] === "false" ? false : pair[1];
11779
+ }
11780
+ }
11781
+ const result = await context.client.setNotificationPreferences(updates);
11782
+ context.addMessage("system", `Preferences updated: ${result.status ?? "ok"}`);
11783
+ return;
11784
+ }
11785
+ context.addMessage("error", "Usage: /notify [--get] or /notify --set KEY=VALUE ...");
11786
+ } catch (e) {
11787
+ context.addMessage("error", `Notify: ${e.message}`);
11788
+ }
11789
+ }
11790
+ };
11791
+ }
11792
+ });
11793
+
11794
+ // src/commands/mlineage.ts
11795
+ var mlineageCommand;
11796
+ var init_mlineage = __esm({
11797
+ "src/commands/mlineage.ts"() {
11798
+ "use strict";
11799
+ init_esm_shims();
11800
+ mlineageCommand = {
11801
+ name: "mlineage",
11802
+ args: "[events] [--follow]",
11803
+ description: "List MLineage events (follow mode not yet implemented)",
11804
+ category: "chat",
11805
+ handler: async (args2, context) => {
11806
+ try {
11807
+ const follow = args2.includes("--follow");
11808
+ const events = await context.client.listMLineageEvents();
11809
+ context.addMessage("system", "MLineage Events:");
11810
+ if (Array.isArray(events)) {
11811
+ for (const evt of events) {
11812
+ context.addMessage("system", ` - ${evt.id}: ${evt.type} @ ${evt.timestamp}`);
11813
+ }
11814
+ } else {
11815
+ context.addMessage("system", JSON.stringify(events, null, 2));
11816
+ }
11817
+ if (follow) {
11818
+ context.addMessage("system", "(follow mode not yet implemented)");
11819
+ }
11820
+ } catch (e) {
11821
+ context.addMessage("error", `MLineage: ${e.message}`);
11822
+ }
11823
+ }
11824
+ };
11825
+ }
11826
+ });
11827
+
11828
+ // src/commands/mfa.ts
11829
+ var mfaCommand;
11830
+ var init_mfa = __esm({
11831
+ "src/commands/mfa.ts"() {
11832
+ "use strict";
11833
+ init_esm_shims();
11834
+ mfaCommand = {
11835
+ name: "mfa",
11836
+ args: "[enroll|verify] [...args]",
11837
+ description: "Enroll or verify MFA/TOTP",
11838
+ category: "config",
11839
+ handler: async (args2, context) => {
11840
+ const sub = (args2[0] ?? "status").toLowerCase();
11841
+ const rest = args2.slice(1);
11842
+ try {
11843
+ if (sub === "enroll") {
11844
+ const method = rest[0] ?? "totp";
11845
+ const result = await context.client.enrollMFA(method);
11846
+ context.addMessage("system", `MFA enrollment initiated: ${method}`);
11847
+ if (result.qr_code) {
11848
+ context.addMessage("system", `QR Code: ${result.qr_code}`);
11849
+ }
11850
+ if (result.secret) {
11851
+ context.addMessage("system", `Secret: ${result.secret}`);
11852
+ }
11853
+ return;
11854
+ }
11855
+ if (sub === "verify") {
11856
+ const code = rest[0];
11857
+ if (!code) {
11858
+ context.addMessage("system", "Usage: /mfa verify <CODE>");
11859
+ return;
11860
+ }
11861
+ const result = await context.client.verifyMFA(code);
11862
+ context.addMessage("system", `MFA verified: ${result.status ?? "ok"}`);
11863
+ return;
11864
+ }
11865
+ context.addMessage("error", `Unknown /mfa subcommand '${sub}'. Try: enroll, verify.`);
11866
+ } catch (e) {
11867
+ context.addMessage("error", `MFA: ${e.message}`);
11868
+ }
11869
+ }
11870
+ };
11871
+ }
11872
+ });
11873
+
11874
+ // src/commands/mcp.ts
11875
+ var mcpCommand;
11876
+ var init_mcp = __esm({
11877
+ "src/commands/mcp.ts"() {
11878
+ "use strict";
11879
+ init_esm_shims();
11880
+ mcpCommand = {
11881
+ name: "mcp",
11882
+ args: "[connect|invoke|tools|disconnect] [...args]",
11883
+ description: "MCP client surface: connect, invoke, list tools, disconnect",
11884
+ category: "config",
11885
+ handler: async (args2, context) => {
11886
+ const sub = (args2[0] ?? "tools").toLowerCase();
11887
+ const rest = args2.slice(1);
11888
+ try {
11889
+ if (sub === "connect") {
11890
+ const url = rest[0];
11891
+ if (!url) {
11892
+ context.addMessage("system", "Usage: /mcp connect <server-url>");
11893
+ return;
11894
+ }
11895
+ const result = await context.client.mcpConnect(url);
11896
+ context.addMessage("system", `MCP Connected: ${result.status ?? "ok"}`);
11897
+ return;
11898
+ }
11899
+ if (sub === "tools") {
11900
+ const tools = await context.client.mcpTools();
11901
+ context.addMessage("system", "Available MCP Tools:");
11902
+ if (Array.isArray(tools)) {
11903
+ for (const tool of tools) {
11904
+ context.addMessage("system", ` - ${tool.name}: ${tool.description ?? ""}`);
11905
+ }
11906
+ } else if (typeof tools === "object") {
11907
+ context.addMessage("system", JSON.stringify(tools, null, 2));
11908
+ }
11909
+ return;
11910
+ }
11911
+ if (sub === "invoke") {
11912
+ const method = rest[0];
11913
+ if (!method) {
11914
+ context.addMessage("system", "Usage: /mcp invoke <method> [args...]");
11915
+ return;
11916
+ }
11917
+ const argsStr = rest.slice(1).join(" ");
11918
+ let argsObj;
11919
+ try {
11920
+ argsObj = argsStr ? JSON.parse(argsStr) : void 0;
11921
+ } catch {
11922
+ argsObj = { raw: argsStr };
11923
+ }
11924
+ const result = await context.client.mcpInvoke(method, argsObj);
11925
+ context.addMessage("system", `MCP Result: ${JSON.stringify(result)}`);
11926
+ return;
11927
+ }
11928
+ if (sub === "disconnect") {
11929
+ const result = await context.client.mcpDisconnect();
11930
+ context.addMessage("system", `MCP Disconnected: ${result.status ?? "ok"}`);
11931
+ return;
11932
+ }
11933
+ context.addMessage("error", `Unknown /mcp subcommand '${sub}'. Try: connect, tools, invoke, disconnect.`);
11934
+ } catch (e) {
11935
+ context.addMessage("error", `MCP: ${e.message}`);
11936
+ }
11937
+ }
11938
+ };
11939
+ }
11940
+ });
11941
+
11942
+ // src/commands/webhook.ts
11943
+ var webhookCommand;
11944
+ var init_webhook = __esm({
11945
+ "src/commands/webhook.ts"() {
11946
+ "use strict";
11947
+ init_esm_shims();
11948
+ webhookCommand = {
11949
+ name: "webhook",
11950
+ args: "[list|add|rm|deliveries|retry] [...args]",
11951
+ description: "Manage webhooks: create, list, delete, and view delivery logs",
11952
+ category: "project",
11953
+ handler: async (args2, context) => {
11954
+ const sub = (args2[0] ?? "list").toLowerCase();
11955
+ const rest = args2.slice(1);
11956
+ try {
11957
+ if (sub === "list") {
11958
+ const webhooks = await context.client.listWebhooks();
11959
+ context.addMessage("system", "Webhooks:");
11960
+ if (Array.isArray(webhooks) && webhooks.length > 0) {
11961
+ for (const wh of webhooks) {
11962
+ const id = wh.id ?? wh.webhook_id ?? "?";
11963
+ const url = wh.url ?? "?";
11964
+ const events = wh.events ? wh.events.join(", ") : "";
11965
+ context.addMessage("system", ` - ${id}: ${url} (${events})`);
11966
+ }
11967
+ } else {
11968
+ context.addMessage("system", " (no webhooks)");
11969
+ }
11970
+ return;
11971
+ }
11972
+ if (sub === "add") {
11973
+ const url = rest[0];
11974
+ const events = rest.slice(1);
11975
+ if (!url || events.length === 0) {
11976
+ context.addMessage("system", "Usage: /webhook add <url> <event1> [event2] ...");
11977
+ return;
11978
+ }
11979
+ const result = await context.client.createWebhook(url, events);
11980
+ const id = result.id ?? result.webhook_id ?? "?";
11981
+ context.addMessage("system", `Webhook created: ${id} \u2192 ${url}`);
11982
+ return;
11983
+ }
11984
+ if (sub === "rm" || sub === "delete") {
11985
+ const id = rest[0];
11986
+ if (!id) {
11987
+ context.addMessage("system", "Usage: /webhook rm <id>");
11988
+ return;
11989
+ }
11990
+ await context.client.deleteWebhook(id);
11991
+ context.addMessage("system", `Deleted webhook: ${id}`);
11992
+ return;
11993
+ }
11994
+ if (sub === "deliveries") {
11995
+ const webhookId = rest[0] || void 0;
11996
+ const deliveries = await context.client.listWebhookDeliveries(webhookId);
11997
+ const title = webhookId ? `Deliveries for webhook ${webhookId}:` : "Recent deliveries:";
11998
+ context.addMessage("system", title);
11999
+ if (Array.isArray(deliveries) && deliveries.length > 0) {
12000
+ for (const d of deliveries) {
12001
+ const id = d.id ?? d.delivery_id ?? "?";
12002
+ const status = d.status ?? "?";
12003
+ const at = d.delivered_at ?? d.created_at ?? "?";
12004
+ context.addMessage("system", ` - ${id}: ${status} (${at})`);
12005
+ }
12006
+ } else {
12007
+ context.addMessage("system", " (no deliveries)");
12008
+ }
12009
+ return;
12010
+ }
12011
+ if (sub === "retry") {
12012
+ const deliveryId = rest[0];
12013
+ if (!deliveryId) {
12014
+ context.addMessage("system", "Usage: /webhook retry <delivery-id>");
12015
+ return;
12016
+ }
12017
+ const result = await context.client.retryWebhookDelivery(deliveryId);
12018
+ context.addMessage("system", `Retrying delivery: ${deliveryId} (${result.status ?? "queued"})`);
12019
+ return;
12020
+ }
12021
+ context.addMessage("error", `Unknown /webhook subcommand '${sub}'. Try: list, add, rm, deliveries, retry.`);
12022
+ } catch (e) {
12023
+ context.addMessage("error", `Webhook: ${e.message}`);
12024
+ }
12025
+ }
12026
+ };
12027
+ }
12028
+ });
12029
+
11362
12030
  // src/commands/index.ts
11363
12031
  var commands_exports = {};
11364
12032
  __export(commands_exports, {
@@ -11412,6 +12080,16 @@ var init_commands = __esm({
11412
12080
  init_todo();
11413
12081
  init_outputStyle();
11414
12082
  init_totp();
12083
+ init_budget();
12084
+ init_image();
12085
+ init_voice();
12086
+ init_wakeup();
12087
+ init_share();
12088
+ init_notify();
12089
+ init_mlineage();
12090
+ init_mfa();
12091
+ init_mcp();
12092
+ init_webhook();
11415
12093
  commands = [
11416
12094
  loginCommand,
11417
12095
  unlockCommand,
@@ -11451,7 +12129,17 @@ var init_commands = __esm({
11451
12129
  noteCommand,
11452
12130
  todoCommand,
11453
12131
  outputStyleCommand,
11454
- totpCommand
12132
+ totpCommand,
12133
+ budgetCommand,
12134
+ imageCommand,
12135
+ voiceCommand,
12136
+ wakeupCommand,
12137
+ shareCommand,
12138
+ notifyCommand,
12139
+ mlineageCommand,
12140
+ mfaCommand,
12141
+ mcpCommand,
12142
+ webhookCommand
11455
12143
  ];
11456
12144
  }
11457
12145
  });
@@ -15054,7 +15742,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
15054
15742
  var Header = () => /* @__PURE__ */ jsxs(Box, { borderStyle: "single", borderColor: "cyan", paddingX: 1, marginBottom: 1, children: [
15055
15743
  /* @__PURE__ */ jsxs(Text, { bold: true, color: "cyan", children: [
15056
15744
  "\u25CF MSapling CLI v",
15057
- "2.3.6-beta.27"
15745
+ "2.3.6-beta.28"
15058
15746
  ] }),
15059
15747
  /* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "Platinum Tier Architecture" }) })
15060
15748
  ] });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mtreeai/msapling-cli",
3
- "version": "2.3.6-beta.27",
3
+ "version": "2.3.6-beta.28",
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",