@vultisig/cli 0.19.0 → 0.20.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # @vultisig/cli
2
2
 
3
+ ## 0.20.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [[`1d1c02c`](https://github.com/vultisig/vultisig-sdk/commit/1d1c02c37e58340b0617eec3a5e44909efc9b452)]:
8
+ - @vultisig/sdk@0.20.0
9
+ - @vultisig/client-shared@0.2.4
10
+ - @vultisig/rujira@15.0.0
11
+
3
12
  ## 0.19.0
4
13
 
5
14
  ### Patch Changes
package/dist/index.js CHANGED
@@ -1654,7 +1654,7 @@ var thorchainMidgardBaseUrl, POOL_ID_RE, assertValidPoolId, isValidPoolId, norma
1654
1654
  var init_pools = __esm({
1655
1655
  "../../packages/core/chain/dist/chains/cosmos/thor/lp/pools.js"() {
1656
1656
  init_queryUrl();
1657
- thorchainMidgardBaseUrl = "https://midgard.ninerealms.com";
1657
+ thorchainMidgardBaseUrl = "https://midgard.thorchain.network";
1658
1658
  POOL_ID_RE = /^[A-Z0-9]+\.[A-Z0-9]+(-[A-Z0-9]+)?$/;
1659
1659
  assertValidPoolId = (pool) => {
1660
1660
  if (typeof pool !== "string" || pool.length === 0) {
@@ -6091,6 +6091,11 @@ var AgentClient = class {
6091
6091
  }
6092
6092
  const toolName = inlineName ?? (callId ? toolNameByCallId.get(callId) : void 0);
6093
6093
  const label = typeof parsed.label === "string" ? parsed.label : void 0;
6094
+ if (v1Type === "tool-input-available" && parsed.clientExecuted === true && callId && toolName && callbacks.onClientSideToolCall) {
6095
+ const rawInput = parsed.input;
6096
+ const input = rawInput && typeof rawInput === "object" && !Array.isArray(rawInput) ? rawInput : {};
6097
+ callbacks.onClientSideToolCall(callId, toolName, input);
6098
+ }
6094
6099
  if (status && toolName) {
6095
6100
  callbacks.onToolProgress?.(toolName, status, label);
6096
6101
  }
@@ -8420,6 +8425,25 @@ import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, wri
8420
8425
  import { homedir as homedir2 } from "node:os";
8421
8426
  import { join as join2 } from "node:path";
8422
8427
  import { MemoryStorage, PushNotificationService } from "@vultisig/sdk";
8428
+ var CLIENT_SIDE_TOOL_DISPATCH = {
8429
+ sign_typed_data: "sign_typed_data",
8430
+ add_coin: "add_coin",
8431
+ remove_coin: "remove_coin",
8432
+ add_chain: "add_chain",
8433
+ remove_chain: "remove_chain",
8434
+ address_book_add: "address_book_add",
8435
+ address_book_remove: "address_book_remove"
8436
+ };
8437
+ var MAX_MESSAGE_LOOP_DEPTH = 16;
8438
+ function actionResultToRecentAction(r) {
8439
+ if (r.success) {
8440
+ return { tool: r.action, success: true, data: r.data ?? {} };
8441
+ }
8442
+ const data = { ...r.data ?? {} };
8443
+ if (r.error) data.error = r.error;
8444
+ if (r.code) data.code = r.code;
8445
+ return { tool: r.action, success: false, data };
8446
+ }
8423
8447
  var AgentSession = class {
8424
8448
  client;
8425
8449
  vault;
@@ -8431,6 +8455,8 @@ var AgentSession = class {
8431
8455
  abortController = null;
8432
8456
  historyMessages = [];
8433
8457
  pushService = null;
8458
+ // Flushed into context.recent_actions on the next outbound request.
8459
+ pendingToolResults = [];
8434
8460
  constructor(vault, config) {
8435
8461
  this.vault = vault;
8436
8462
  this.config = config;
@@ -8552,17 +8578,10 @@ var AgentSession = class {
8552
8578
  } catch {
8553
8579
  }
8554
8580
  try {
8555
- await this.processMessageLoop(content, null, ui);
8581
+ await this.processMessageLoop(content, ui);
8556
8582
  } catch (err) {
8557
- if (err.message?.includes("401") || err.message?.includes("403")) {
8558
- clearCachedToken(this.publicKey);
8559
- const auth = await authenticateVault(this.client, this.vault, this.config.password);
8560
- this.client.setAuthToken(auth.token);
8561
- saveCachedToken(this.publicKey, auth.token, auth.expiresAt);
8562
- await this.processMessageLoop(content, null, ui);
8563
- } else {
8564
- throw err;
8565
- }
8583
+ this.pendingToolResults = [];
8584
+ throw err;
8566
8585
  } finally {
8567
8586
  this.abortController = null;
8568
8587
  }
@@ -8571,11 +8590,20 @@ var AgentSession = class {
8571
8590
  * Core message processing loop.
8572
8591
  * Sends content or action results, executes returned actions, repeats.
8573
8592
  */
8574
- async processMessageLoop(content, actionResults, ui) {
8593
+ async processMessageLoop(content, ui, depth = 0) {
8575
8594
  if (!this.conversationId) return;
8595
+ if (depth > MAX_MESSAGE_LOOP_DEPTH) {
8596
+ process.stderr.write(
8597
+ `[session] processMessageLoop exceeded MAX_MESSAGE_LOOP_DEPTH (${MAX_MESSAGE_LOOP_DEPTH}); stopping. pendingToolResults=${this.pendingToolResults.length}
8598
+ `
8599
+ );
8600
+ this.pendingToolResults = [];
8601
+ ui.onDone();
8602
+ return;
8603
+ }
8576
8604
  const request = {
8577
8605
  public_key: this.publicKey,
8578
- context: this.cachedContext
8606
+ context: this.cachedContext ? { ...this.cachedContext } : {}
8579
8607
  };
8580
8608
  if (this.config.viaAgent || this.config.askMode) {
8581
8609
  request.via_agent = true;
@@ -8583,61 +8611,92 @@ var AgentSession = class {
8583
8611
  if (content) {
8584
8612
  request.content = content;
8585
8613
  }
8586
- if (actionResults && actionResults.length > 0) {
8587
- const result = actionResults[0];
8588
- request.action_result = {
8589
- action: result.action,
8590
- action_id: result.action_id,
8591
- success: result.success,
8592
- data: result.data || {},
8593
- error: result.error || "",
8594
- ...!result.success && result.code ? { code: result.code } : {}
8595
- };
8614
+ let flushedThisCall = [];
8615
+ if (this.pendingToolResults.length > 0) {
8616
+ flushedThisCall = [...this.pendingToolResults];
8617
+ request.context.recent_actions = this.pendingToolResults.splice(0);
8618
+ if (this.config.verbose) {
8619
+ process.stderr.write(`[session] flushed ${request.context.recent_actions.length} recent_actions into request
8620
+ `);
8621
+ }
8596
8622
  }
8597
8623
  let serverTxStoredFromStream = 0;
8598
- const streamResult = await this.client.sendMessageStream(
8599
- this.conversationId,
8600
- request,
8601
- {
8602
- onTextDelta: (delta) => ui.onTextDelta(delta),
8603
- onToolProgress: (tool, status, label) => {
8604
- if (status === "running") {
8605
- ui.onToolCall(`mcp-${tool}`, tool);
8606
- } else {
8607
- ui.onToolResult(`mcp-${tool}`, tool, true, { label });
8608
- }
8609
- },
8610
- onTitle: (_title) => {
8611
- },
8612
- onActions: (_actions) => {
8613
- },
8614
- onSuggestions: (suggestions) => {
8615
- ui.onSuggestions(suggestions);
8616
- },
8617
- onTxReady: (tx) => {
8618
- if (this.executor.storeServerTransaction(tx)) {
8619
- serverTxStoredFromStream++;
8620
- if (this.config.password) {
8621
- this.executor.setPassword(this.config.password);
8622
- }
8624
+ const pendingDispatches = [];
8625
+ let dispatchChain = Promise.resolve();
8626
+ const callbacks = {
8627
+ onTextDelta: (delta) => ui.onTextDelta(delta),
8628
+ onToolProgress: (tool, status, label) => {
8629
+ if (status === "running") {
8630
+ ui.onToolCall(`mcp-${tool}`, tool);
8631
+ } else {
8632
+ ui.onToolResult(`mcp-${tool}`, tool, true, { label });
8633
+ }
8634
+ },
8635
+ onClientSideToolCall: (toolCallId, toolName, input) => {
8636
+ const dispatch = dispatchChain.then(() => this.dispatchClientSideTool(toolCallId, toolName, input, ui));
8637
+ dispatchChain = dispatch.catch(() => {
8638
+ });
8639
+ pendingDispatches.push(dispatch);
8640
+ },
8641
+ onTitle: (_title) => {
8642
+ },
8643
+ onActions: (_actions) => {
8644
+ },
8645
+ onSuggestions: (suggestions) => {
8646
+ ui.onSuggestions(suggestions);
8647
+ },
8648
+ onTxReady: (tx) => {
8649
+ if (this.executor.storeServerTransaction(tx)) {
8650
+ serverTxStoredFromStream++;
8651
+ if (this.config.password) {
8652
+ this.executor.setPassword(this.config.password);
8623
8653
  }
8624
- },
8625
- onMessage: (_msg) => {
8626
- },
8627
- onError: (error2, code) => {
8628
- ui.onError(error2, code);
8629
8654
  }
8630
8655
  },
8631
- this.abortController?.signal
8632
- );
8656
+ onMessage: (_msg) => {
8657
+ },
8658
+ onError: (error2, code) => {
8659
+ ui.onError(error2, code);
8660
+ }
8661
+ };
8662
+ let streamResult;
8663
+ let authRetried = false;
8664
+ while (true) {
8665
+ try {
8666
+ streamResult = await this.client.sendMessageStream(
8667
+ this.conversationId,
8668
+ request,
8669
+ callbacks,
8670
+ this.abortController?.signal
8671
+ );
8672
+ break;
8673
+ } catch (err) {
8674
+ const isAuthErr = err.message?.includes("401") || err.message?.includes("403");
8675
+ if (isAuthErr && !authRetried) {
8676
+ authRetried = true;
8677
+ clearCachedToken(this.publicKey);
8678
+ const auth = await authenticateVault(this.client, this.vault, this.config.password);
8679
+ this.client.setAuthToken(auth.token);
8680
+ saveCachedToken(this.publicKey, auth.token, auth.expiresAt);
8681
+ continue;
8682
+ }
8683
+ if (flushedThisCall.length > 0) {
8684
+ this.pendingToolResults = [...flushedThisCall, ...this.pendingToolResults];
8685
+ }
8686
+ throw err;
8687
+ }
8688
+ }
8689
+ if (pendingDispatches.length > 0) {
8690
+ await Promise.all(pendingDispatches);
8691
+ }
8633
8692
  const responseText = streamResult.message?.content || streamResult.fullText || "";
8634
8693
  const displayText = stripLeakedToolCallTags(responseText);
8635
8694
  if (displayText) {
8636
8695
  ui.onAssistantMessage(displayText);
8637
8696
  }
8638
- const actions = streamResult.actions.filter((a) => a.type !== "sign_tx");
8639
- if (actions.length > 0) {
8640
- const results = await this.executeActions(actions, ui);
8697
+ const legacyActions = streamResult.actions.filter((a) => a.type !== "sign_tx");
8698
+ if (legacyActions.length > 0) {
8699
+ const results = await this.executeActions(legacyActions, ui);
8641
8700
  const hasBuildSuccess = results.some((r) => r.success && r.action.startsWith("build_"));
8642
8701
  if (hasBuildSuccess && this.executor.hasPendingTransaction()) {
8643
8702
  if (this.config.verbose)
@@ -8653,14 +8712,16 @@ var AgentSession = class {
8653
8712
  const signResults = await this.executeActions([signAction], ui);
8654
8713
  const signResult = signResults[0];
8655
8714
  if (signResult) {
8656
- await this.processMessageLoop(null, [signResult], ui);
8715
+ this.pendingToolResults.push(actionResultToRecentAction(signResult));
8716
+ await this.processMessageLoop(null, ui, depth + 1);
8657
8717
  return;
8658
8718
  }
8659
8719
  }
8660
8720
  if (results.length > 0) {
8661
8721
  for (const result of results) {
8662
- await this.processMessageLoop(null, [result], ui);
8722
+ this.pendingToolResults.push(actionResultToRecentAction(result));
8663
8723
  }
8724
+ await this.processMessageLoop(null, ui, depth + 1);
8664
8725
  return;
8665
8726
  }
8666
8727
  }
@@ -8680,13 +8741,62 @@ var AgentSession = class {
8680
8741
  const results = await this.executeActions([signAction], ui);
8681
8742
  if (results.length > 0) {
8682
8743
  for (const result of results) {
8683
- await this.processMessageLoop(null, [result], ui);
8744
+ this.pendingToolResults.push(actionResultToRecentAction(result));
8684
8745
  }
8746
+ await this.processMessageLoop(null, ui, depth + 1);
8685
8747
  return;
8686
8748
  }
8687
8749
  }
8750
+ if (this.pendingToolResults.length > 0) {
8751
+ await this.processMessageLoop(null, ui, depth + 1);
8752
+ return;
8753
+ }
8688
8754
  ui.onDone();
8689
8755
  }
8756
+ // Routes client-side tool calls through executeAction. Missing registry
8757
+ // entries surface as a visible `[cli] unimplemented` warning + failure
8758
+ // RecentAction (never silent).
8759
+ async dispatchClientSideTool(toolCallId, toolName, input, ui) {
8760
+ const actionType = CLIENT_SIDE_TOOL_DISPATCH[toolName];
8761
+ if (!actionType) {
8762
+ process.stderr.write(`[cli] unimplemented client-side tool: ${toolName}
8763
+ `);
8764
+ this.pendingToolResults.push({
8765
+ tool: toolName,
8766
+ success: false,
8767
+ data: { error: `unimplemented in CLI: ${toolName}` }
8768
+ });
8769
+ return;
8770
+ }
8771
+ const action = {
8772
+ id: toolCallId,
8773
+ type: actionType,
8774
+ title: toolName,
8775
+ params: input,
8776
+ auto_execute: true
8777
+ };
8778
+ try {
8779
+ const results = await this.executeActions([action], ui);
8780
+ const result = results[0];
8781
+ if (result) {
8782
+ const recent = actionResultToRecentAction(result);
8783
+ if (recent.data === void 0) recent.data = {};
8784
+ for (const key of Object.keys(input)) {
8785
+ if (key.startsWith("__") || key === "pm_order_ref") {
8786
+ recent.data[key] = input[key];
8787
+ }
8788
+ }
8789
+ this.pendingToolResults.push(recent);
8790
+ }
8791
+ } catch (err) {
8792
+ const message = err instanceof Error ? err.message : String(err);
8793
+ this.pendingToolResults.push({
8794
+ tool: toolName,
8795
+ success: false,
8796
+ data: { error: message }
8797
+ });
8798
+ }
8799
+ }
8690
8800
  /**
8691
8801
  * Execute a list of actions, handling password requirements.
8692
8802
  */
@@ -9343,7 +9453,7 @@ var cachedVersion = null;
9343
9453
  function getVersion() {
9344
9454
  if (cachedVersion) return cachedVersion;
9345
9455
  if (true) {
9346
- cachedVersion = "0.19.0";
9456
+ cachedVersion = "0.20.0";
9347
9457
  return cachedVersion;
9348
9458
  }
9349
9459
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vultisig/cli",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "description": "The self-custody MPC wallet CLI for AI coding agents (Claude Code, Cursor, OpenCode). Natural-language agent mode, 36+ chains, DKLS23 threshold signatures. Seedless.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -73,10 +73,10 @@
73
73
  "@cosmjs/stargate": "^0.38.1",
74
74
  "@napi-rs/keyring": "^1.2.0",
75
75
  "@noble/hashes": "^2.0.1",
76
- "@vultisig/client-shared": "^0.2.3",
76
+ "@vultisig/client-shared": "^0.2.4",
77
77
  "@vultisig/core-chain": "^1.4.1",
78
- "@vultisig/rujira": "^14.0.0",
79
- "@vultisig/sdk": "^0.19.0",
78
+ "@vultisig/rujira": "^15.0.0",
79
+ "@vultisig/sdk": "^0.20.0",
80
80
  "chalk": "^5.6.2",
81
81
  "cli-table3": "^0.6.5",
82
82
  "commander": "^14.0.3",