@vultisig/cli 2.16.0 → 2.18.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,49 @@
1
1
  # @vultisig/cli
2
2
 
3
+ ## 2.18.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#1004](https://github.com/vultisig/vultisig-sdk/pull/1004) [`42fe389`](https://github.com/vultisig/vultisig-sdk/commit/42fe3893196e7d8945f852695387828eb49bfb41) Thanks [@neavra](https://github.com/neavra)! - feat(cli): surface a typed turn-outcome for `agent ask` (success / blocked / refusal / error)
8
+
9
+ The CLI now advertises the `turn_outcome` surface and parses the backend's
10
+ `data-turn_outcome` SSE part, so a headless `agent ask` caller can tell four turn
11
+ endings apart WITHOUT parsing prose:
12
+
13
+ - **success** — the turn completed normally
14
+ - **blocked** — a fund-safety guardrail deliberately blocked the requested action
15
+ - **refusal** — the model refused or asked a clarifying question (no action taken)
16
+ - **error** — an infrastructure error ended the turn
17
+
18
+ Two additive surfaces:
19
+
20
+ - `agent ask --output json` gains a top-level `outcome` field
21
+ (`{ kind, code?, detail? }`) on both the success and error envelopes. Human
22
+ output prints a greppable `outcome:<kind>[:<code>]` line for non-success turns.
23
+ - New dedicated exit codes (additive; the 0–9 taxonomy is unchanged):
24
+ `10` = a fund-safety block, `11` = a refusal/clarifying question. A frame-less
25
+ infrastructure error now exits `1` instead of a false `0`. Success stays `0`.
26
+
27
+ Behavior change to note: a turn the backend BLOCKS or the model REFUSES previously
28
+ exited `0` (indistinguishable from success); it now exits `10`/`11`. Scripts that
29
+ treated every `agent ask` as success-on-0 should branch on `outcome.kind` (or the
30
+ exit code). Against an older backend that does not emit `data-turn_outcome`, the
31
+ `outcome` field is absent and exit codes are unchanged.
32
+
33
+ ### Patch Changes
34
+
35
+ - Updated dependencies [[`31814c4`](https://github.com/vultisig/vultisig-sdk/commit/31814c4b452ef5b2628dc12bc46e427fcf0b7237), [`b37dc3c`](https://github.com/vultisig/vultisig-sdk/commit/b37dc3c31d6f93af982cd1e082e0b4d1382dc19d), [`01c5630`](https://github.com/vultisig/vultisig-sdk/commit/01c56303d0b872a76de07da9685331106f586c80)]:
36
+ - @vultisig/sdk@2.18.0
37
+ - @vultisig/rujira@51.0.0
38
+
39
+ ## 2.17.0
40
+
41
+ ### Patch Changes
42
+
43
+ - Updated dependencies [[`2585dc1`](https://github.com/vultisig/vultisig-sdk/commit/2585dc1830dd7b28694edd411991b24c3fad1538), [`152bb4a`](https://github.com/vultisig/vultisig-sdk/commit/152bb4a2b717efa2f1edb14b7e19cdeba87450c7), [`4a58c6c`](https://github.com/vultisig/vultisig-sdk/commit/4a58c6c1294c88e5d937c3dde24e50edd3fdf2a0), [`ed46385`](https://github.com/vultisig/vultisig-sdk/commit/ed46385358883ed5277f8771ba73000afec9859e), [`72082a6`](https://github.com/vultisig/vultisig-sdk/commit/72082a65eab226cebf562863bcb99346b81ca831), [`a9266a1`](https://github.com/vultisig/vultisig-sdk/commit/a9266a1753ca474b3f337f8a605900acdd7508b0), [`2791af8`](https://github.com/vultisig/vultisig-sdk/commit/2791af8a1e539103678ba71b774d62d2e7691a29), [`b68ddad`](https://github.com/vultisig/vultisig-sdk/commit/b68ddadbc6295957cbb4b37c365a4062b0a2576f), [`ab5e413`](https://github.com/vultisig/vultisig-sdk/commit/ab5e413ead62da47dc144e591ac310d1d4328a56), [`90f6ae5`](https://github.com/vultisig/vultisig-sdk/commit/90f6ae5a1865321e08bf6f03c17e23ed11006649), [`7cfa332`](https://github.com/vultisig/vultisig-sdk/commit/7cfa332787f7646e049813a9f3b15613454f19d1), [`c60d7c6`](https://github.com/vultisig/vultisig-sdk/commit/c60d7c6ecdf46e46bf1098cc57342d5fb79d2194), [`99db752`](https://github.com/vultisig/vultisig-sdk/commit/99db752f093575f90b99b30674ec9be8af49fed9)]:
44
+ - @vultisig/sdk@2.17.0
45
+ - @vultisig/rujira@50.0.0
46
+
3
47
  ## 2.16.0
4
48
 
5
49
  ### Patch Changes
package/dist/index.js CHANGED
@@ -5316,7 +5316,9 @@ var EXIT_CODE_DESCRIPTIONS = {
5316
5316
  [6 /* EXTERNAL_SERVICE */]: "External service error (retryable)",
5317
5317
  [7 /* UNKNOWN */]: "Unknown/unexpected error",
5318
5318
  [8 /* ACK_FAILED */]: "Broadcast succeeded but post-broadcast report failed \u2014 hash is valid, do NOT retry",
5319
- [9 /* DUPLICATE_BROADCAST */]: "Duplicate broadcast refused (nothing sent) \u2014 retry with --force to override"
5319
+ [9 /* DUPLICATE_BROADCAST */]: "Duplicate broadcast refused (nothing sent) \u2014 retry with --force to override",
5320
+ [10 /* AGENT_TURN_BLOCKED */]: "agent ask: a fund-safety guardrail blocked the requested action",
5321
+ [11 /* AGENT_TURN_REFUSAL */]: "agent ask: the model refused or asked a clarifying question (no action taken)"
5320
5322
  };
5321
5323
  var VsigError = class extends Error {
5322
5324
  hint;
@@ -8249,6 +8251,7 @@ var AskInterface = class {
8249
8251
  toolCalls = [];
8250
8252
  transactions = [];
8251
8253
  cards = [];
8254
+ outcome;
8252
8255
  error;
8253
8256
  // Initialize-time error, kept SEPARATE from the turn error so it stays the
8254
8257
  // LOWEST-priority signal. initialize() drives getCallbacks() BEFORE the first
@@ -8311,6 +8314,9 @@ var AskInterface = class {
8311
8314
  onBalanceSummary: (card) => {
8312
8315
  this.cards.push(card);
8313
8316
  },
8317
+ onTurnOutcome: (outcome) => {
8318
+ this.outcome = outcome;
8319
+ },
8314
8320
  onSuggestions: (_suggestions) => {
8315
8321
  },
8316
8322
  onTxStatus: (txHash, chain, status, explorerUrl) => {
@@ -8363,6 +8369,7 @@ var AskInterface = class {
8363
8369
  this.toolCalls = [];
8364
8370
  this.transactions = [];
8365
8371
  this.cards = [];
8372
+ this.outcome = void 0;
8366
8373
  this.error = void 0;
8367
8374
  if (this.hasAsked) {
8368
8375
  this.initError = void 0;
@@ -8390,7 +8397,8 @@ var AskInterface = class {
8390
8397
  cards: this.cards,
8391
8398
  // A real turn error wins; fall back to the init-time signal (e.g. stale
8392
8399
  // --session SESSION_NOT_FOUND) only when the turn produced no error.
8393
- error: this.error ?? this.initError
8400
+ error: this.error ?? this.initError,
8401
+ ...this.outcome ? { outcome: this.outcome } : {}
8394
8402
  };
8395
8403
  }
8396
8404
  };
@@ -8797,7 +8805,19 @@ function padTo32Bytes(buf) {
8797
8805
 
8798
8806
  // src/agent/cards.ts
8799
8807
  import chalk8 from "chalk";
8800
- var CLI_SUPPORTED_SURFACES = ["balance_summary"];
8808
+ var CLI_SUPPORTED_SURFACES = ["balance_summary", "turn_outcome"];
8809
+ function parseTurnOutcome(raw) {
8810
+ if (!raw || typeof raw !== "object") return null;
8811
+ const kind = raw.kind;
8812
+ if (kind !== "success" && kind !== "blocked" && kind !== "refusal" && kind !== "error") return null;
8813
+ const code = raw.code;
8814
+ const detail = raw.detail;
8815
+ return {
8816
+ kind,
8817
+ ...typeof code === "string" ? { code } : {},
8818
+ ...typeof detail === "string" ? { detail } : {}
8819
+ };
8820
+ }
8801
8821
  function stripControlChars(s) {
8802
8822
  let out = "";
8803
8823
  for (const ch of s) {
@@ -12347,6 +12367,11 @@ var AgentClient = class {
12347
12367
  callbacks.onBalanceSummary?.(card);
12348
12368
  break;
12349
12369
  }
12370
+ case "turn_outcome": {
12371
+ const outcome = parseTurnOutcome(v1Data ?? parsed.data ?? parsed);
12372
+ if (outcome) callbacks.onTurnOutcome?.(outcome);
12373
+ break;
12374
+ }
12350
12375
  case "message": {
12351
12376
  const msg = v1Data?.message ?? parsed.message ?? parsed;
12352
12377
  result.message = msg;
@@ -12448,6 +12473,8 @@ var AgentClient = class {
12448
12473
  return "tx_ready";
12449
12474
  case "data-balance_summary":
12450
12475
  return "balance_summary";
12476
+ case "data-turn_outcome":
12477
+ return "turn_outcome";
12451
12478
  case "data-message":
12452
12479
  return "message";
12453
12480
  case "error":
@@ -13288,6 +13315,9 @@ var AgentSession = class {
13288
13315
  ui.onBalanceSummary?.(card);
13289
13316
  }
13290
13317
  },
13318
+ onTurnOutcome: (outcome) => {
13319
+ ui.onTurnOutcome?.(outcome);
13320
+ },
13291
13321
  onMessage: (_msg) => {
13292
13322
  },
13293
13323
  onError: (error2, code) => {
@@ -14280,6 +14310,7 @@ function outputAskError(wantsJson, message, code, conversationId, result) {
14280
14310
  if (result?.transactions.length) data.transactions = result.transactions;
14281
14311
  if (result?.toolCalls.length) data.tool_calls = result.toolCalls;
14282
14312
  if (result?.response) data.response = result.response;
14313
+ if (result?.outcome) data.outcome = result.outcome;
14283
14314
  outputErrorJson({
14284
14315
  success: false,
14285
14316
  v: 1,
@@ -14294,6 +14325,11 @@ function outputAskError(wantsJson, message, code, conversationId, result) {
14294
14325
  function outputAskHuman(result, confirmationRequired, proposed) {
14295
14326
  process.stdout.write(`session:${result.sessionId}
14296
14327
  `);
14328
+ if (result.outcome && result.outcome.kind !== "success") {
14329
+ const { kind, code } = result.outcome;
14330
+ process.stdout.write(`outcome:${kind}${code ? `:${code}` : ""}
14331
+ `);
14332
+ }
14297
14333
  if (confirmationRequired) {
14298
14334
  process.stdout.write(`confirmation-required:pass --yes to authorize signing
14299
14335
  `);
@@ -14336,6 +14372,12 @@ function outputAskSuccess(wantsJson, result, conversationId) {
14336
14372
  tool_calls: result.toolCalls,
14337
14373
  transactions: result.transactions,
14338
14374
  ...result.cards.length > 0 ? { cards: result.cards } : {},
14375
+ // a2a-02: the typed turn ending (success | blocked | refusal | error) at
14376
+ // `data.outcome` — the same relative slot as on the error envelope. Present
14377
+ // only against a backend that honored the advertised turn_outcome surface;
14378
+ // headless callers should branch on this (and the exit code), not `success`
14379
+ // (which stays true for a completed-but-blocked/refused turn).
14380
+ ...result.outcome ? { outcome: result.outcome } : {},
14339
14381
  ...confirmationRequired ? { confirmation_required: true } : {},
14340
14382
  ...proposed ? { proposed } : {}
14341
14383
  });
@@ -14343,6 +14385,21 @@ function outputAskSuccess(wantsJson, result, conversationId) {
14343
14385
  }
14344
14386
  outputAskHuman(result, confirmationRequired, proposed);
14345
14387
  }
14388
+ function outcomeToExitCode(outcome) {
14389
+ switch (outcome?.kind) {
14390
+ case "blocked":
14391
+ return 10 /* AGENT_TURN_BLOCKED */;
14392
+ case "refusal":
14393
+ return 11 /* AGENT_TURN_REFUSAL */;
14394
+ case "error":
14395
+ return 1 /* USAGE */;
14396
+ // 1 — generic failure; a stream error-frame path sets a more specific code first
14397
+ case "success":
14398
+ return 0 /* SUCCESS */;
14399
+ default:
14400
+ return void 0;
14401
+ }
14402
+ }
14346
14403
  async function executeAgentAsk(ctx2, message, options) {
14347
14404
  setSilentMode(true);
14348
14405
  const originalConsoleLog = console.log;
@@ -14376,6 +14433,7 @@ async function executeAgentAsk(ctx2, message, options) {
14376
14433
  exitCode = agentErrorCodeToExitCode(result.error.code);
14377
14434
  outputAskError(wantsJson, result.error.message, result.error.code, conversationId, result);
14378
14435
  } else {
14436
+ exitCode = outcomeToExitCode(result.outcome) ?? 0;
14379
14437
  outputAskSuccess(wantsJson, result, conversationId);
14380
14438
  }
14381
14439
  } catch (err) {
@@ -14494,7 +14552,7 @@ var cachedVersion = null;
14494
14552
  function getVersion() {
14495
14553
  if (cachedVersion) return cachedVersion;
14496
14554
  if (true) {
14497
- cachedVersion = "2.16.0";
14555
+ cachedVersion = "2.18.0";
14498
14556
  return cachedVersion;
14499
14557
  }
14500
14558
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vultisig/cli",
3
- "version": "2.16.0",
3
+ "version": "2.18.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.17",
77
77
  "@vultisig/core-chain": "^2.23.1",
78
- "@vultisig/rujira": "^49.0.0",
79
- "@vultisig/sdk": "^2.16.0",
78
+ "@vultisig/rujira": "^51.0.0",
79
+ "@vultisig/sdk": "^2.18.0",
80
80
  "chalk": "^5.6.2",
81
81
  "cli-table3": "^0.6.5",
82
82
  "commander": "^15.0.0",