@vultisig/cli 2.7.0 → 2.8.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.
Files changed (3) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/index.js +109 -61
  3. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @vultisig/cli
2
2
 
3
+ ## 2.8.0
4
+
5
+ ### Patch Changes
6
+
7
+ - [#868](https://github.com/vultisig/vultisig-sdk/pull/868) [`6f84f19`](https://github.com/vultisig/vultisig-sdk/commit/6f84f19444752976a6677d3ee4054701b0904eae) Thanks [@neavra](https://github.com/neavra)! - `agent ask --json` now emits one stable v1 envelope on stdout for both success and error. Previously the success envelope was written through a redirected `console.log` and landed on stderr (stdout empty), and the error path wrote a different flat `{error,code}` shape. The envelope now carries `conversation_id` (success + error) and per-tool-call `id`s, and a mid-stream backend/SSE `error` frame makes the command exit non-zero instead of reporting false success.
8
+
9
+ - Updated dependencies [[`c9a235b`](https://github.com/vultisig/vultisig-sdk/commit/c9a235b959c7c82cd189482fab86ce3d27ddb4ff), [`9585b6f`](https://github.com/vultisig/vultisig-sdk/commit/9585b6f246de3ce537eae201f0d660fc89ff1012), [`f82caf5`](https://github.com/vultisig/vultisig-sdk/commit/f82caf58532f58af9d62b0143c7466cabcd88b06), [`361ba58`](https://github.com/vultisig/vultisig-sdk/commit/361ba58f79f241c4c00e33785a66ec6987628d26), [`7625e0b`](https://github.com/vultisig/vultisig-sdk/commit/7625e0bf325c8957bc3e28270454fd54c5589e2f), [`2024a92`](https://github.com/vultisig/vultisig-sdk/commit/2024a92b44760e1ff2043b0e45b083edc131b16c)]:
10
+ - @vultisig/sdk@2.8.0
11
+ - @vultisig/rujira@41.0.0
12
+
3
13
  ## 2.7.0
4
14
 
5
15
  ### Patch Changes
package/dist/index.js CHANGED
@@ -5053,11 +5053,11 @@ function bigIntReplacer(_key, value) {
5053
5053
  }
5054
5054
  function outputJson(data) {
5055
5055
  const transformed = applyOutputTransforms(data);
5056
- console.log(JSON.stringify({ success: true, v: 1, data: transformed }, bigIntReplacer, 2));
5056
+ process.stdout.write(JSON.stringify({ success: true, v: 1, data: transformed }, bigIntReplacer, 2) + "\n");
5057
5057
  }
5058
5058
  function outputErrorJson(errJson) {
5059
5059
  const transformed = applyOutputTransforms(errJson);
5060
- console.log(JSON.stringify(transformed, bigIntReplacer, 2));
5060
+ process.stdout.write(JSON.stringify(transformed, bigIntReplacer, 2) + "\n");
5061
5061
  }
5062
5062
  function info(message) {
5063
5063
  if (!silentMode) {
@@ -8184,6 +8184,7 @@ var AskInterface = class {
8184
8184
  toolCalls = [];
8185
8185
  transactions = [];
8186
8186
  cards = [];
8187
+ error;
8187
8188
  constructor(session, verbose = false, autoApprove = false) {
8188
8189
  this.session = session;
8189
8190
  this.verbose = verbose;
@@ -8204,8 +8205,8 @@ var AskInterface = class {
8204
8205
  `);
8205
8206
  }
8206
8207
  },
8207
- onToolResult: (_id, action, success2, data, error2, code) => {
8208
- this.toolCalls.push({ action, success: success2, data, error: error2, code });
8208
+ onToolResult: (id, action, success2, data, error2, code) => {
8209
+ this.toolCalls.push({ id, action, success: success2, data, error: error2, code });
8209
8210
  if (this.verbose) {
8210
8211
  const status = success2 ? "ok" : `error: ${error2}${code ? ` [${code}]` : ""}`;
8211
8212
  process.stderr.write(`[tool] ${action}: ${status}
@@ -8222,14 +8223,17 @@ var AskInterface = class {
8222
8223
  },
8223
8224
  onSuggestions: (_suggestions) => {
8224
8225
  },
8225
- onTxStatus: (txHash, chain, _status, explorerUrl) => {
8226
- this.transactions.push({ hash: txHash, chain, explorerUrl });
8226
+ onTxStatus: (txHash, chain, status, explorerUrl) => {
8227
+ this.transactions.push({ hash: txHash, chain, ...status ? { status } : {}, explorerUrl });
8227
8228
  if (this.verbose) {
8228
8229
  process.stderr.write(`[tx] ${chain}: ${txHash}
8229
8230
  `);
8230
8231
  }
8231
8232
  },
8232
8233
  onError: (message, code) => {
8234
+ if (!this.error) {
8235
+ this.error = { message, code };
8236
+ }
8233
8237
  process.stderr.write(`[error] ${message} [${code}]
8234
8238
  `);
8235
8239
  },
@@ -8259,14 +8263,27 @@ var AskInterface = class {
8259
8263
  this.toolCalls = [];
8260
8264
  this.transactions = [];
8261
8265
  this.cards = [];
8266
+ this.error = void 0;
8262
8267
  const callbacks = this.getCallbacks();
8263
8268
  await this.session.sendMessage(message, callbacks);
8269
+ return this.partialResult();
8270
+ }
8271
+ /**
8272
+ * Snapshot of everything collected so far this turn. Identical to a normal
8273
+ * `ask()` return, but callable from a catch block when `ask()` THREW mid-turn
8274
+ * — e.g. the follow-up request that reports recent_actions back to the backend
8275
+ * fails (timeout/5xx/auth) AFTER a tx has already broadcast and `onTxStatus`
8276
+ * fired. Lets the caller still surface the already-broadcast tx hash in the
8277
+ * error envelope instead of stranding funds the turn just moved.
8278
+ */
8279
+ partialResult() {
8264
8280
  return {
8265
8281
  sessionId: this.session.getConversationId() || "",
8266
8282
  response: this.responseParts[this.responseParts.length - 1] || "",
8267
8283
  toolCalls: this.toolCalls,
8268
8284
  transactions: this.transactions,
8269
- cards: this.cards
8285
+ cards: this.cards,
8286
+ error: this.error
8270
8287
  };
8271
8288
  }
8272
8289
  };
@@ -13068,12 +13085,85 @@ async function executeAgent(ctx2, options) {
13068
13085
  }
13069
13086
  }
13070
13087
  }
13088
+ function outputAskError(wantsJson, message, code, conversationId, result) {
13089
+ if (wantsJson) {
13090
+ const data = {};
13091
+ if (result?.transactions.length) data.transactions = result.transactions;
13092
+ if (result?.toolCalls.length) data.tool_calls = result.toolCalls;
13093
+ if (result?.response) data.response = result.response;
13094
+ outputErrorJson({
13095
+ success: false,
13096
+ v: 1,
13097
+ error: { message, code, conversation_id: conversationId },
13098
+ ...Object.keys(data).length > 0 ? { data } : {}
13099
+ });
13100
+ } else {
13101
+ process.stderr.write(`Error: ${message} [${code}]
13102
+ `);
13103
+ }
13104
+ }
13105
+ function outputAskHuman(result, confirmationRequired, proposed) {
13106
+ process.stdout.write(`session:${result.sessionId}
13107
+ `);
13108
+ if (confirmationRequired) {
13109
+ process.stdout.write(`confirmation-required:pass --yes to authorize signing
13110
+ `);
13111
+ if (proposed) {
13112
+ process.stdout.write(`proposed:${proposed}
13113
+ `);
13114
+ }
13115
+ }
13116
+ for (const card of result.cards) {
13117
+ process.stdout.write(`
13118
+ ${renderBalanceSummaryCard(card)}
13119
+ `);
13120
+ }
13121
+ if (result.response) {
13122
+ process.stdout.write(`
13123
+ ${result.response}
13124
+ `);
13125
+ }
13126
+ for (const tx of result.transactions) {
13127
+ process.stdout.write(`
13128
+ tx:${tx.chain}:${tx.hash}
13129
+ `);
13130
+ if (tx.explorerUrl) {
13131
+ process.stdout.write(`explorer:${tx.explorerUrl}
13132
+ `);
13133
+ }
13134
+ }
13135
+ }
13136
+ function outputAskSuccess(wantsJson, result, conversationId) {
13137
+ const confirmationRequired = result.toolCalls.some((tc) => tc.code === "CONFIRMATION_REQUIRED" /* CONFIRMATION_REQUIRED */);
13138
+ const proposedCall = result.toolCalls.find(
13139
+ (tc) => tc.code === "CONFIRMATION_REQUIRED" /* CONFIRMATION_REQUIRED */ && typeof tc.data?.proposed === "string"
13140
+ );
13141
+ const proposed = proposedCall?.data?.proposed;
13142
+ if (wantsJson) {
13143
+ outputJson({
13144
+ conversation_id: conversationId,
13145
+ session_id: result.sessionId,
13146
+ response: result.response,
13147
+ tool_calls: result.toolCalls,
13148
+ transactions: result.transactions,
13149
+ ...result.cards.length > 0 ? { cards: result.cards } : {},
13150
+ ...confirmationRequired ? { confirmation_required: true } : {},
13151
+ ...proposed ? { proposed } : {}
13152
+ });
13153
+ return;
13154
+ }
13155
+ outputAskHuman(result, confirmationRequired, proposed);
13156
+ }
13071
13157
  async function executeAgentAsk(ctx2, message, options) {
13072
13158
  setSilentMode(true);
13073
13159
  const originalConsoleLog = console.log;
13074
13160
  console.log = (...args) => {
13075
13161
  process.stderr.write(args.map(String).join(" ") + "\n");
13076
13162
  };
13163
+ const wantsJson = !!options.json || isJsonOutput();
13164
+ let conversationId = "";
13165
+ let exitCode = 0;
13166
+ let ask;
13077
13167
  try {
13078
13168
  const vault = await ctx2.ensureActiveVault();
13079
13169
  const config = {
@@ -13087,70 +13177,28 @@ async function executeAgentAsk(ctx2, message, options) {
13087
13177
  profile: options.profile ?? process.env.VULTISIG_AGENT_PROFILE ?? ""
13088
13178
  };
13089
13179
  const session = new AgentSession(vault, config);
13090
- const ask = new AskInterface(session, !!config.verbose, !!options.autoApprove);
13180
+ ask = new AskInterface(session, !!config.verbose, !!options.autoApprove);
13091
13181
  const callbacks = ask.getCallbacks();
13092
13182
  await session.initialize(callbacks);
13093
13183
  const result = await ask.ask(message);
13094
- const confirmationRequired = result.toolCalls.some((tc) => tc.code === "CONFIRMATION_REQUIRED" /* CONFIRMATION_REQUIRED */);
13095
- const proposedCall = result.toolCalls.find(
13096
- (tc) => tc.code === "CONFIRMATION_REQUIRED" /* CONFIRMATION_REQUIRED */ && typeof tc.data?.proposed === "string"
13097
- );
13098
- const proposed = proposedCall?.data?.proposed;
13099
- if (options.json || isJsonOutput()) {
13100
- outputJson({
13101
- session_id: result.sessionId,
13102
- response: result.response,
13103
- tool_calls: result.toolCalls,
13104
- transactions: result.transactions,
13105
- ...result.cards.length > 0 ? { cards: result.cards } : {},
13106
- ...confirmationRequired ? { confirmation_required: true } : {},
13107
- ...proposed ? { proposed } : {}
13108
- });
13184
+ conversationId = result.sessionId;
13185
+ if (result.error) {
13186
+ exitCode = 1;
13187
+ outputAskError(wantsJson, result.error.message, result.error.code, conversationId, result);
13109
13188
  } else {
13110
- process.stdout.write(`session:${result.sessionId}
13111
- `);
13112
- if (confirmationRequired) {
13113
- process.stdout.write(`confirmation-required:pass --yes to authorize signing
13114
- `);
13115
- if (proposed) {
13116
- process.stdout.write(`proposed:${proposed}
13117
- `);
13118
- }
13119
- }
13120
- for (const card of result.cards) {
13121
- process.stdout.write(`
13122
- ${renderBalanceSummaryCard(card)}
13123
- `);
13124
- }
13125
- if (result.response) {
13126
- process.stdout.write(`
13127
- ${result.response}
13128
- `);
13129
- }
13130
- for (const tx of result.transactions) {
13131
- process.stdout.write(`
13132
- tx:${tx.chain}:${tx.hash}
13133
- `);
13134
- if (tx.explorerUrl) {
13135
- process.stdout.write(`explorer:${tx.explorerUrl}
13136
- `);
13137
- }
13138
- }
13189
+ outputAskSuccess(wantsJson, result, conversationId);
13139
13190
  }
13140
13191
  } catch (err) {
13141
13192
  const { code, message: message2 } = normalizeAgentError(err);
13142
- if (options.json) {
13143
- process.stdout.write(JSON.stringify({ error: message2, code }) + "\n");
13144
- } else {
13145
- process.stderr.write(`Error: ${message2} [${code}]
13146
- `);
13147
- }
13148
- process.exit(1);
13193
+ exitCode = 1;
13194
+ const partial = ask?.partialResult();
13195
+ if (partial && !conversationId) conversationId = partial.sessionId;
13196
+ outputAskError(wantsJson, message2, code, conversationId, partial);
13149
13197
  } finally {
13150
13198
  console.log = originalConsoleLog;
13151
13199
  setSilentMode(false);
13152
13200
  }
13153
- process.exit(0);
13201
+ process.exit(exitCode);
13154
13202
  }
13155
13203
  async function executeAgentSessionsList(ctx2, options) {
13156
13204
  const vault = await ctx2.ensureActiveVault();
@@ -13235,7 +13283,7 @@ var cachedVersion = null;
13235
13283
  function getVersion() {
13236
13284
  if (cachedVersion) return cachedVersion;
13237
13285
  if (true) {
13238
- cachedVersion = "2.7.0";
13286
+ cachedVersion = "2.8.0";
13239
13287
  return cachedVersion;
13240
13288
  }
13241
13289
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vultisig/cli",
3
- "version": "2.7.0",
3
+ "version": "2.8.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": {
@@ -75,8 +75,8 @@
75
75
  "@noble/hashes": "^2.2.0",
76
76
  "@vultisig/client-shared": "^0.2.16",
77
77
  "@vultisig/core-chain": "^2.17.8",
78
- "@vultisig/rujira": "^40.0.0",
79
- "@vultisig/sdk": "^2.7.0",
78
+ "@vultisig/rujira": "^41.0.0",
79
+ "@vultisig/sdk": "^2.8.0",
80
80
  "chalk": "^5.6.2",
81
81
  "cli-table3": "^0.6.5",
82
82
  "commander": "^15.0.0",