@vultisig/cli 2.20.0 → 2.21.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 (4) hide show
  1. package/CHANGELOG.md +138 -0
  2. package/README.md +70 -33
  3. package/dist/index.js +1691 -1473
  4. package/package.json +5 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,143 @@
1
1
  # @vultisig/cli
2
2
 
3
+ ## 2.21.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#1291](https://github.com/vultisig/vultisig-sdk/pull/1291) [`11f0c0c`](https://github.com/vultisig/vultisig-sdk/commit/11f0c0c362d0fca0a935acd396216c379b50ea1b) Thanks [@neavra](https://github.com/neavra)! - Send a fresh idempotency key for each agent message attempt, reuse it for the attempt's auth retry, and expose keyed-turn duplicates as a typed error with exit code 14.
8
+
9
+ - [#1281](https://github.com/vultisig/vultisig-sdk/pull/1281) [`feb2137`](https://github.com/vultisig/vultisig-sdk/commit/feb213783534fc4a424cbc7e01bd97ae90320c11) Thanks [@rcoderdev](https://github.com/rcoderdev)! - Expose canonical EIP-191 hashing and ECDSA 65-byte signature formatting helpers, and use them in vault message signing and CLI authentication.
10
+
11
+ - [#1305](https://github.com/vultisig/vultisig-sdk/pull/1305) [`7cbcfa7`](https://github.com/vultisig/vultisig-sdk/commit/7cbcfa7d792229e7558417ff5a5f0fdd5ef96991) Thanks [@neavra](https://github.com/neavra)! - Harden agent channels with an SSE frame-idle timeout, backend/profile-scoped token caching, protocol-drift warnings, and explicit Polymarket auto-submit authorization.
12
+
13
+ **Behavior change — auto-submit is now opt-in.** Backend-requested Polymarket order submission previously flowed by default; it now requires the new `--allow-auto-submit` flag. Without it the CLI strips the submit markers and forces `auto_submit=false`, so a script that relied on `--yes` alone to place an order will sign and exit 0 without submitting. Add `--allow-auto-submit` to restore the old behavior.
14
+
15
+ Also: the agent token cache is re-keyed by (vault, backend URL, profile), so cached credentials from a previous version are dropped and the next run re-authenticates. New `VULTISIG_SSE_IDLE_TIMEOUT_MS` env var (default 60s) bounds an established but silent SSE stream; `agent ask --output json` may now carry an additive `warnings` field, and `agent --via-agent` now emits warning events on the NDJSON stream for consumers to handle alongside other event frames.
16
+
17
+ ### Patch Changes
18
+
19
+ - [#1474](https://github.com/vultisig/vultisig-sdk/pull/1474) [`c443b9c`](https://github.com/vultisig/vultisig-sdk/commit/c443b9ce699ef76f1407d0386ed20fbc7e3f253f) Thanks [@rcoderdev](https://github.com/rcoderdev)! - Route SwapKit transaction links through its public tracker across the shared core and SDK APIs.
20
+
21
+ - [#1256](https://github.com/vultisig/vultisig-sdk/pull/1256) [`20a0fd0`](https://github.com/vultisig/vultisig-sdk/commit/20a0fd0dafab088d92bc53e5bd84acaf5cc20cc6) Thanks [@gomesalexandre](https://github.com/gomesalexandre)! - Fix typed EVM transaction decoding so newer supported chain ids resolve through the canonical SDK registry instead of a stale local map.
22
+
23
+ - [#1346](https://github.com/vultisig/vultisig-sdk/pull/1346) [`662eed0`](https://github.com/vultisig/vultisig-sdk/commit/662eed02fac61e3e138d3e3629f0d48aa951b531) Thanks [@neavra](https://github.com/neavra)! - Classify permanent UTXO, Solana, Sui, and Cosmos broadcast validation failures as non-retryable invalid input while leaving ambiguous and transient failures retryable.
24
+
25
+ - [#1286](https://github.com/vultisig/vultisig-sdk/pull/1286) [`4f111d1`](https://github.com/vultisig/vultisig-sdk/commit/4f111d1f448e5dbd8cb99e71b1f9e7a5cd875e30) Thanks [@rcoderdev](https://github.com/rcoderdev)! - Infer EVM and Cosmos decoder families from canonical SDK chain metadata.
26
+
27
+ - [#1437](https://github.com/vultisig/vultisig-sdk/pull/1437) [`620648a`](https://github.com/vultisig/vultisig-sdk/commit/620648a43e67c4804e27520a98c160af8932e8da) Thanks [@neavra](https://github.com/neavra)! - Classify a Cosmos DeliverTx execution failure honestly, and journal its on-chain hash.
28
+
29
+ A Cosmos transaction can be included in a block and still fail execution (DeliverTx code !== 0 — out-of-gas, a wasm revert, a THORChain/Maya deposit-handler rejection). The SDK now surfaces that truthfully (cosmjs `assertIsDeliverTxSuccess`, [#1316](https://github.com/vultisig/vultisig-sdk/issues/1316)), but the CLI mishandled it:
30
+
31
+ - **Classification.** The DeliverTx-failure message (`Error when broadcasting tx <hash> at height <N>. Code: <c>; Raw log: <log>`) did not match the CheckTx-shaped classifier, so it fell through to `EXTERNAL_SERVICE` (exit 6, retryable) with a "the node may be temporarily unavailable / Retry" hint — for a transaction that is on-chain and has failed. It now classifies as `INVALID_INPUT` (exit 4, non-retryable) with an honest message: the transaction was included on-chain and its execution failed, the on-chain result is authoritative — inspect it via the hash and rebuild rather than blindly re-broadcasting the identical bytes. The chain is resolved from the SDK broadcast wrapper (never from wrapped payload text), so a foreign chain's program log cannot spoof the marker and strand a genuinely-retryable error.
32
+ - **Journaling.** On the direct `send` / `swap` guard, a DeliverTx failure previously journaled nothing (the throw preceded hash computation), discarding a hash we definitively have. The guard now records the hash cosmjs embedded in the message as a broadcast plus a `failed` resolution, so the transaction is on the record (tx-status / explorer / audit) while the guard correctly re-opens for a legitimate retry. Gated on the intent's own (trusted) chain so a non-Cosmos error can't get a spoofed hash journaled.
33
+
34
+ - [#1436](https://github.com/vultisig/vultisig-sdk/pull/1436) [`8471b88`](https://github.com/vultisig/vultisig-sdk/commit/8471b88cb0403e28506d82c380115eed50acdc25) Thanks [@neavra](https://github.com/neavra)! - fix(cli): an interactive `send`/`execute`/`swap` decline now exits 12
35
+ `CONFIRMATION_REQUIRED` (`success:false` in JSON), matching the non-interactive
36
+ refusal, instead of the old swallowed exit 0 that told a scripted caller a declined
37
+ transaction had succeeded. A decline inside the interactive REPL still just returns
38
+ to the prompt. **Behavior change scripted consumers branch on:** answering "no" at
39
+ a confirm prompt flips `$?` from 0 → 12.
40
+
41
+ Also corrects the ask-mode taxonomy so a persistent auth failure while resuming a
42
+ `--session` fails closed as `AUTH_FAILED` (exit 2) rather than `SESSION_NOT_FOUND`
43
+ (exit 5).
44
+
45
+ - [#1387](https://github.com/vultisig/vultisig-sdk/pull/1387) [`c837c0b`](https://github.com/vultisig/vultisig-sdk/commit/c837c0b524dea366a77d2d5eccd6ad737d15cb29) Thanks [@neavra](https://github.com/neavra)! - Two CLI developer-experience fixes:
46
+
47
+ - Silence the `bigint: Failed to load bindings, pure JS will be used` warning that
48
+ `bigint-buffer` printed to stderr on every invocation, including `--version`. It
49
+ warns at module load, before any flag has been parsed, so it cannot be gated behind
50
+ `--debug`; it is silenced with a `yarn patch`. The SDK's node bundle inlines the
51
+ patched copy, which is why `@vultisig/sdk` is bumped here too.
52
+ - Generate shell completion from the Commander command table and the SDK chain
53
+ registry instead of a stale hardcoded list, which was missing eleven commands
54
+ (sign/broadcast/tx-status/execute/discount/agent/auth/delete/join/rujira/add-mldsa)
55
+ and 17 of 38 chains.
56
+
57
+ - [#1386](https://github.com/vultisig/vultisig-sdk/pull/1386) [`a2ea19a`](https://github.com/vultisig/vultisig-sdk/commit/a2ea19a386b77d4135e56cd9ce4b6bf8e70b5e60) Thanks [@neavra](https://github.com/neavra)! - Tighten the handling of files that carry key shares:
58
+
59
+ - Write exported `.vult` files owner-only (0600) instead of with the default umask
60
+ (0644, world-readable), matching the SDK's own vault store. The export is written to
61
+ a fresh temp file and renamed over the target, so the shares are never on disk at a
62
+ looser mode — `writeFile`'s `mode` only applies when it creates the file, so writing
63
+ straight to a pre-existing path would have left the shares world-readable for a window.
64
+ - Stop `rename` rejecting vault names the ecosystem itself creates (e.g. the `#` in
65
+ "Vultisig Cluster [#1](https://github.com/vultisig/vultisig-sdk/issues/1)"), which made rename a one-way door. The alphanumeric allowlist
66
+ is replaced with a denylist of what is genuinely unsafe for the export filename the
67
+ name is interpolated into: path separators and control characters.
68
+ - Enforce that denylist at the real lifecycle boundary — `export()` — rather than only
69
+ at rename. A vault imported or created via a path that ran no name validation could
70
+ otherwise carry an unsafe name or `localPartyId` (path separators, control chars, a
71
+ bare `..`) straight into the export filename. `export()` now encodes every filename
72
+ component to a single safe path segment (same policy as rename), encoding rather than
73
+ refusing so a legitimately-imported vault is never stranded behind its own backup file.
74
+
75
+ - [#1385](https://github.com/vultisig/vultisig-sdk/pull/1385) [`8998264`](https://github.com/vultisig/vultisig-sdk/commit/8998264d3136a2ab0ea051b31ce0626dceeb6c08) Thanks [@neavra](https://github.com/neavra)! - Make CLI machine output tell the truth about what happened:
76
+
77
+ - Emit a result envelope from every successful mutation in `-o json`
78
+ (switch/rename/currency/address-book/import/export/add-mldsa previously exited 0
79
+ with no output at all).
80
+ - Emit exactly one JSON envelope from a failed `verify` — it previously wrote two
81
+ documents, so `JSON.parse` on the output failed — and list vaults pending
82
+ verification in `vaults`, which were otherwise only named in the create-time output.
83
+ - Validate the chain argument for `tokens` and `swap-quote`, which previously reported
84
+ `success: true` with an empty list / a raw TypeError for an unknown chain. Both now
85
+ throw a typed `INVALID_CHAIN` (exit 4).
86
+ - Add `NO_ACTIVE_VAULT` (15) and `CORRUPT_STATE` (16) exit codes with recovery hints,
87
+ replacing a generic `UNKNOWN_ERROR`/7 for both states.
88
+ - Report `fee` and `total` from `send --dry-run` in JSON — the human preview already
89
+ printed the fee, and `total` is the number the insufficient-balance warning is
90
+ derived from.
91
+
92
+ Note: a failed `verify` now exits 4 (wrong/expired code) or 5 (unknown pending vault)
93
+ instead of 1. This is a deliberate change on a published surface — see the PR body.
94
+
95
+ - [#1239](https://github.com/vultisig/vultisig-sdk/pull/1239) [`937a58c`](https://github.com/vultisig/vultisig-sdk/commit/937a58cce27f935346f44f4bae4b3e40f464cba9) Thanks [@gomesalexandre](https://github.com/gomesalexandre)! - Fix `formatBalance`/`formatBigintAmount` computing the display divisor via `BigInt(10 ** decimals)` — a float64 power that's only exact up to decimals=22, silently corrupting balance display for higher-decimal assets. Both now delegate to the pure-bigint `fromChainAmountExact`, which is also exported from the root `@vultisig/sdk` entrypoint alongside `getBlockExplorerUrl` — including the React Native platform entry (the one Metro actually resolves for Station), not just the node/default condition, so RN consumers can reach both without a `@vultisig/core-chain` deep import.
96
+
97
+ - [#1266](https://github.com/vultisig/vultisig-sdk/pull/1266) [`98e715a`](https://github.com/vultisig/vultisig-sdk/commit/98e715a0c770ae2a776314763fb18ffa309c1e2b) Thanks [@gomesalexandre](https://github.com/gomesalexandre)! - Keep the direct Jupiter swap tool's affiliate-fee state in sync with the canonical shared Jupiter path when the quoted platform fee floors to zero.
98
+
99
+ - [#1282](https://github.com/vultisig/vultisig-sdk/pull/1282) [`6f32745`](https://github.com/vultisig/vultisig-sdk/commit/6f327454c04c42f6771e53584026ec7283aa2ac3) Thanks [@gomesalexandre](https://github.com/gomesalexandre)! - Export the canonical prep constants from `@vultisig/sdk` and `@vultisig/sdk/react-native` so consumers can import `TRC20_TRANSFER_SELECTOR`, `SUI_NATIVE_COIN_TYPE`, and `CONSOLIDATE_CHAINS` from the public SDK surfaces instead of copying local literals.
100
+
101
+ - [#1345](https://github.com/vultisig/vultisig-sdk/pull/1345) [`5cd0a12`](https://github.com/vultisig/vultisig-sdk/commit/5cd0a12957d05e324e056ca3453e76c3668c2071) Thanks [@neavra](https://github.com/neavra)! - Make the agent SSE idle deadline bound a hung backend, and handle the frame types that carry turn-outcome semantics.
102
+
103
+ Follow-up to the agent-channel hardening in [#1305](https://github.com/vultisig/vultisig-sdk/issues/1305); both are behavior changes worth reading.
104
+
105
+ **The idle deadline now measures progress, not traffic.** Keep-alive comments no longer extend it. Both backends emit those from a timer that runs independently of whether the turn is advancing, so a deadline they reset bounded only a dead connection — a backend wedged in a model or tool call kept pinging and `agent ask` hung forever, which is the exact failure the deadline was added to stop. The default rises 60s → 180s to match what it now measures: real backend silence, which a healthy turn is documented to produce for up to ~150s (a model call is bounded at 90s, the swap builder at 90s + 60s MCP). A slow-but-progressing turn still resets the clock on every real frame. `VULTISIG_SSE_IDLE_TIMEOUT_MS` is unchanged, and the timeout still throws a typed `TIMEOUT` → exit 3.
106
+
107
+ **`tool-output-error` and `text-replace` are now handled.** Both were counted as unknown frames and dropped, and both carry semantics the turn result depends on:
108
+
109
+ - `tool-output-error` is the backend's tool-failure terminal. Ignored, the call never closed, so a FAILED tool was reported as a running one and the turn recorded no failure. It now surfaces as a failed tool result. It can never produce a signable transaction.
110
+ - `text-replace` retracts prose the backend has decided is wrong and supplies a correction. Ignored, the retracted claim stayed as the turn's answer — a turn could answer "I sent your 5 ETH." after the backend had withdrawn exactly that sentence. The correction is now applied, or declined outright if it cannot be applied cleanly, never half-applied.
111
+
112
+ **`PROTOCOL_DRIFT` warnings are now `--verbose`-only,** and unknown `data-*` card kinds no longer produce them at all. The backend's V1 wire treats unknown data kinds as forward-compatible and emits some from a dynamic call site no static client list can track, so warning by default fired on healthy turns against a newer backend. Automation that read `warnings` for drift will no longer receive it unless `--verbose` is set; the field was already documented as omitted-when-empty. Frames whose absence is a real defect are handled explicitly instead of enumerated.
113
+
114
+ - [#1355](https://github.com/vultisig/vultisig-sdk/pull/1355) [`42e5e36`](https://github.com/vultisig/vultisig-sdk/commit/42e5e36350a2e6cc71681f6ac5545051c045381a) Thanks [@neavra](https://github.com/neavra)! - Correct the non-EVM permanent broadcast classification so it only declares a failure permanent when the fault is in the signed bytes themselves.
115
+
116
+ - Cosmos: `insufficient funds` (5), `insufficient fee` (13) and `unknown address` (9) are no longer permanent. A CheckTx rejection does not increment the account sequence, so these stay replayable verbatim once the account is funded, a cheaper node accepts the fee, or the account exists — they now classify as retryable (`EXTERNAL_SERVICE`, exit 6) instead of `INVALID_INPUT`, exit 4.
117
+ - UTXO: dropped matching on bitcoind's `-26`/`-27` reject codes. Blockchair is the only UTXO broadcast backend and does not preserve those codes — it reformats the node's reply as `Invalid transaction. Error: <reason>` — so the branch never fired, and `-26` is a bucket that also covers recoverable rejections (`non-final`, `too-long-mempool-chain`, `min relay fee not met`) that must not be stranded.
118
+ - Chain detection now reads the SDK's own wrapper rather than scanning the whole error text for any ` on <chain>:` substring, so chain-labelled text inside a wrapped payload (e.g. a Solana program log) can no longer route an error to another family's vocabulary.
119
+
120
+ EVM classification and the exit 9/13 broadcast-safety semantics are unchanged.
121
+
122
+ - [#1202](https://github.com/vultisig/vultisig-sdk/pull/1202) [`7ae91d9`](https://github.com/vultisig/vultisig-sdk/commit/7ae91d9231add2e4063966aa9cdfbddf12883564) Thanks [@gomesalexandre](https://github.com/gomesalexandre)! - Export `toChainAmount` and `ChainAmountParseError` from the root `@vultisig/sdk` entrypoint so downstream consumers can use the hardened amount parser without deep-importing core-chain internals.
123
+
124
+ - [#1277](https://github.com/vultisig/vultisig-sdk/pull/1277) [`7c1570e`](https://github.com/vultisig/vultisig-sdk/commit/7c1570e528c30e6b037ddbaea538add5353a7dcc) Thanks [@gomesalexandre](https://github.com/gomesalexandre)! - Re-export XRPL issued-currency canonicals from the root and React Native SDK entrypoints so first-party consumers can reuse the SDK's token-id and currency-code helpers instead of mirroring them locally.
125
+
126
+ - [#1279](https://github.com/vultisig/vultisig-sdk/pull/1279) [`ab018c7`](https://github.com/vultisig/vultisig-sdk/commit/ab018c7f747bbbc48984f2ab7a2f244f8179d137) Thanks [@gomesalexandre](https://github.com/gomesalexandre)! - Forward `recipient`, `slippageTolerance`, and `excludeProviders` through `vault.swap()` and make the CLI `swap --slippage` flag reach the SDK quote builder instead of being silently dropped.
127
+
128
+ - [#1225](https://github.com/vultisig/vultisig-sdk/pull/1225) [`52f90bd`](https://github.com/vultisig/vultisig-sdk/commit/52f90bd00a9dfa2937f2cf31f883b444a76a486b) Thanks [@gomesalexandre](https://github.com/gomesalexandre)! - Re-export the SDK's pure parse/tx-normalize/decode helpers from the React Native entrypoint so RN consumers get the same public surface as other first-party platforms.
129
+
130
+ - [#1222](https://github.com/vultisig/vultisig-sdk/pull/1222) [`6b71775`](https://github.com/vultisig/vultisig-sdk/commit/6b71775956d244d291883fd90b9a121f227dfa4b) Thanks [@gomesalexandre](https://github.com/gomesalexandre)! - Fix the CLI agent push-notification listener to register/connect with the canonical hashed notification vault id instead of the raw ECDSA pubkey, restoring parity with SDK secure-vault notification delivery.
131
+
132
+ - [#1182](https://github.com/vultisig/vultisig-sdk/pull/1182) [`ec6c810`](https://github.com/vultisig/vultisig-sdk/commit/ec6c810e81798b8dab7d004c931f2ecc1b859bd2) Thanks [@gomesalexandre](https://github.com/gomesalexandre)! - Re-export `prepareThorchainMsgDepositTxFromKeys` and its params type from the SDK root surface so downstream signers can consume the canonical THOR/Maya MsgDeposit prep helper instead of maintaining local shims.
133
+
134
+ - [#1220](https://github.com/vultisig/vultisig-sdk/pull/1220) [`855ac6b`](https://github.com/vultisig/vultisig-sdk/commit/855ac6bdd4be566743ddc7c4f7a248029f6d2d47) Thanks [@gomesalexandre](https://github.com/gomesalexandre)! - Fix React Native `getCoinBalance()` so Ripple balances use the RN-safe fetch path instead of the websocket `xrpl` client.
135
+
136
+ - Updated dependencies [[`8c1ad1e`](https://github.com/vultisig/vultisig-sdk/commit/8c1ad1ec73152ad161b2d17ffceeb166abafe30a), [`5d46269`](https://github.com/vultisig/vultisig-sdk/commit/5d46269396fd0dbcf9d84f0201a494dffafc1a36), [`9d50ac5`](https://github.com/vultisig/vultisig-sdk/commit/9d50ac5c586d058aabdbfb413e7be163a222da89), [`c443b9c`](https://github.com/vultisig/vultisig-sdk/commit/c443b9ce699ef76f1407d0386ed20fbc7e3f253f), [`ce7271f`](https://github.com/vultisig/vultisig-sdk/commit/ce7271fe009092d995b87a86c33cb830b37fc0a8), [`20a0fd0`](https://github.com/vultisig/vultisig-sdk/commit/20a0fd0dafab088d92bc53e5bd84acaf5cc20cc6), [`4f111d1`](https://github.com/vultisig/vultisig-sdk/commit/4f111d1f448e5dbd8cb99e71b1f9e7a5cd875e30), [`802910d`](https://github.com/vultisig/vultisig-sdk/commit/802910d74219ba11e7e819d38bbafd88843028b8), [`c837c0b`](https://github.com/vultisig/vultisig-sdk/commit/c837c0b524dea366a77d2d5eccd6ad737d15cb29), [`a2ea19a`](https://github.com/vultisig/vultisig-sdk/commit/a2ea19a386b77d4135e56cd9ce4b6bf8e70b5e60), [`a4d8bbe`](https://github.com/vultisig/vultisig-sdk/commit/a4d8bbe81a94019aea5193a411a091ccb2e98682), [`69a3f75`](https://github.com/vultisig/vultisig-sdk/commit/69a3f75c265e19682e6dbdac0fdb640c53d73b33), [`e3d8568`](https://github.com/vultisig/vultisig-sdk/commit/e3d8568a04a6dcd977ccaeeeb5bcf5da080fd275), [`47a63df`](https://github.com/vultisig/vultisig-sdk/commit/47a63dfc8613405b7be1105233627e66a163d7c7), [`feb2137`](https://github.com/vultisig/vultisig-sdk/commit/feb213783534fc4a424cbc7e01bd97ae90320c11), [`937a58c`](https://github.com/vultisig/vultisig-sdk/commit/937a58cce27f935346f44f4bae4b3e40f464cba9), [`5303d70`](https://github.com/vultisig/vultisig-sdk/commit/5303d704e792bb7ed70df08eab7140aac81a519a), [`9b5d103`](https://github.com/vultisig/vultisig-sdk/commit/9b5d103500cce4f984dc7049a316529a193716f2), [`069176b`](https://github.com/vultisig/vultisig-sdk/commit/069176bc0d0edf44911cb131a2fe609075cab5d2), [`ceccf56`](https://github.com/vultisig/vultisig-sdk/commit/ceccf5633ebd7d838e26e2fcbac151c52d26af85), [`98e715a`](https://github.com/vultisig/vultisig-sdk/commit/98e715a0c770ae2a776314763fb18ffa309c1e2b), [`b5f880a`](https://github.com/vultisig/vultisig-sdk/commit/b5f880a2dea1e06239b6ccb1a35fbdb4994d5917), [`338ef32`](https://github.com/vultisig/vultisig-sdk/commit/338ef3229d778bb012d915977f512121d330ac1f), [`6f32745`](https://github.com/vultisig/vultisig-sdk/commit/6f327454c04c42f6771e53584026ec7283aa2ac3), [`0c4a090`](https://github.com/vultisig/vultisig-sdk/commit/0c4a090bc4f3868e2a3a20c9f12742344cf8350e), [`a8c10f0`](https://github.com/vultisig/vultisig-sdk/commit/a8c10f02423760c805593b0a1ad9c25a83609e1f), [`8a0bca6`](https://github.com/vultisig/vultisig-sdk/commit/8a0bca688ec606292df587559115cafcc3287fcf), [`8c02c8c`](https://github.com/vultisig/vultisig-sdk/commit/8c02c8c7e8463b5d57fbd5c338a1f95c6129feb2), [`01a66cf`](https://github.com/vultisig/vultisig-sdk/commit/01a66cf5c0110ea1ea439ddbca8e6b75179fc0c5), [`7226d49`](https://github.com/vultisig/vultisig-sdk/commit/7226d49d42cec673465aac5b49b54d4e47628ab6), [`7ae91d9`](https://github.com/vultisig/vultisig-sdk/commit/7ae91d9231add2e4063966aa9cdfbddf12883564), [`7c1570e`](https://github.com/vultisig/vultisig-sdk/commit/7c1570e528c30e6b037ddbaea538add5353a7dcc), [`ab018c7`](https://github.com/vultisig/vultisig-sdk/commit/ab018c7f747bbbc48984f2ab7a2f244f8179d137), [`b3d17d8`](https://github.com/vultisig/vultisig-sdk/commit/b3d17d855c2e2250c78641912d70203a43fdf332), [`afa17b2`](https://github.com/vultisig/vultisig-sdk/commit/afa17b2aee9abea47a52cfdee433d2cf2ae58ced), [`0de8684`](https://github.com/vultisig/vultisig-sdk/commit/0de8684706f1b538a459acca0e55bf15c95a91f3), [`52f90bd`](https://github.com/vultisig/vultisig-sdk/commit/52f90bd00a9dfa2937f2cf31f883b444a76a486b), [`6b71775`](https://github.com/vultisig/vultisig-sdk/commit/6b71775956d244d291883fd90b9a121f227dfa4b), [`300dabf`](https://github.com/vultisig/vultisig-sdk/commit/300dabf232bfe49d9628d4026c55bb72b6472b97), [`ec6c810`](https://github.com/vultisig/vultisig-sdk/commit/ec6c810e81798b8dab7d004c931f2ecc1b859bd2), [`a971dfa`](https://github.com/vultisig/vultisig-sdk/commit/a971dfa99274b419863f83a078868f25a8241235), [`77e2401`](https://github.com/vultisig/vultisig-sdk/commit/77e24018c906a8dcf1cb21d2c1fc8e337a4b2b8e), [`83df849`](https://github.com/vultisig/vultisig-sdk/commit/83df8496aa01cfe7d59f48b32686ba863cf87a02), [`d01ac2e`](https://github.com/vultisig/vultisig-sdk/commit/d01ac2ee87d080def76454adcf5313726a916ed8), [`358c27b`](https://github.com/vultisig/vultisig-sdk/commit/358c27ba3bdd94813d00ec966ba43c8cc46f49e0), [`a971dfa`](https://github.com/vultisig/vultisig-sdk/commit/a971dfa99274b419863f83a078868f25a8241235), [`3a40960`](https://github.com/vultisig/vultisig-sdk/commit/3a40960cc6391b69bbe6371874889b64399d64b9), [`855ac6b`](https://github.com/vultisig/vultisig-sdk/commit/855ac6bdd4be566743ddc7c4f7a248029f6d2d47), [`9510a9d`](https://github.com/vultisig/vultisig-sdk/commit/9510a9d8099c52a482dff05a3cf49938e06d9a85), [`3bc880a`](https://github.com/vultisig/vultisig-sdk/commit/3bc880a06b90fa64793983ba498f11fdc55e2115), [`ffc174c`](https://github.com/vultisig/vultisig-sdk/commit/ffc174c56d72990e6ee387ac389c96a2f4812cf5), [`e710f0c`](https://github.com/vultisig/vultisig-sdk/commit/e710f0c97274732312e965db467a31de040d7533), [`e92fa0c`](https://github.com/vultisig/vultisig-sdk/commit/e92fa0cb47d8607587798ca3f167c150b2f73d7d)]:
137
+ - @vultisig/sdk@2.21.0
138
+ - @vultisig/core-chain@2.27.0
139
+ - @vultisig/rujira@54.0.0
140
+
3
141
  ## 2.20.0
4
142
 
5
143
  ### Minor Changes
package/README.md CHANGED
@@ -719,8 +719,13 @@ vultisig agent ask "Check my portfolio" --json
719
719
 
720
720
  # Fallback only — exposes the secret to `ps`/shell history (emits a warning)
721
721
  vultisig agent ask "What is my ETH balance?" --password "$VAULT_PASSWORD"
722
+
723
+ # Signing does not authorize backend order submission unless this is also set
724
+ vultisig agent ask "Place the order" --yes --allow-auto-submit
722
725
  ```
723
726
 
727
+ `--yes` authorizes unattended signing and transaction broadcast. It does not authorize the backend to submit a signed Polymarket order: that separate behavior is fail-closed unless `--allow-auto-submit` is present.
728
+
724
729
  **Text output (default):**
725
730
 
726
731
  ```
@@ -751,11 +756,21 @@ explorer:https://etherscan.io/tx/0x9f8e7d6c...
751
756
  }
752
757
  ],
753
758
  "transactions": [],
759
+ "warnings": [
760
+ {
761
+ "code": "PROTOCOL_DRIFT",
762
+ "message": "Ignored 1 unknown SSE frame: data-future-critical",
763
+ "count": 1,
764
+ "eventTypes": ["data-future-critical"]
765
+ }
766
+ ],
754
767
  "outcome": { "kind": "success" }
755
768
  }
756
769
  }
757
770
  ```
758
771
 
772
+ `warnings` is omitted when empty, and is **`--verbose`-only**: `PROTOCOL_DRIFT` is a debugging aid, not a machine contract. The backend's V1 wire evolves forward-compatibly — unknown `data-*` card kinds are expected against a newer backend and are tolerated silently — so a warning emitted by default would fire on healthy turns. Run with `--verbose` to see which frame types a turn carried that this CLI does not route.
773
+
759
774
  Failures use the same v1 envelope with `success:false` and a stable `error.code`. This includes
760
775
  failed/declined signing and typed blocked/refusal/error turn endings; their partial turn data remains under `data`.
761
776
  If `--session` cannot be resumed, ask mode exits `5` before sending the message and does not fall back to a fresh
@@ -800,26 +815,28 @@ Each entry in `tool_calls` may include `code` when `success` is false (same valu
800
815
 
801
816
  Orchestrators should branch on `code`. The message in `error` / `message` stays human-readable and may change between releases.
802
817
 
803
- | Code | Typical meaning |
804
- | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
805
- | `BACKEND_UNREACHABLE` | Agent health check failed or backend not responding |
806
- | `AUTH_FAILED` | Auth/token failure, HTTP 401/403, or wrong vault password |
807
- | `VAULT_LOCKED` | Encrypted vault needs unlock (password) |
808
- | `PASSWORD_REQUIRED` | Password was not supplied when required (e.g. pipe mode or signing) |
809
- | `CONFIRMATION_REQUIRED` | User confirmation needed (pipe mode; message prefix `CONFIRMATION_REQUIRED:`); also returned by `agent ask` on a declined sign (no `--yes`), exit 12 |
810
- | `ACTION_NOT_IMPLEMENTED` | Local executor does not implement this action type |
811
- | `INVALID_INPUT` | Bad parameters, unknown chain, malformed NDJSON input, etc. |
812
- | `NETWORK_ERROR` | RPC/fetch connectivity (includes many SDK `VaultError` network cases) |
813
- | `TIMEOUT` | Deadline exceeded, or abort where the message indicates a timeout |
814
- | `TRANSACTION_FAILED` | Build/broadcast/gas errors mapped from the SDK |
815
- | `SIGNING_FAILED` | MPC/signing failed |
816
- | `ACK_FAILED` | Transaction broadcast, but its immediate acknowledgement/report failed; hash is valid and must be inspected before retrying |
817
- | `BROADCAST_COMMITTED` | At least one transaction broadcast, but the overall agent request may be incomplete; do not blindly retry |
818
- | `AGENT_TURN_BLOCKED` | A fund-safety guardrail blocked the requested action (exit 10) |
819
- | `AGENT_TURN_REFUSAL` | The model refused or requested clarification without completing the action (exit 11) |
820
- | `AGENT_TURN_ERROR` | The typed turn ending reported a failure without a more specific stream error |
821
- | `SESSION_NOT_INITIALIZED` | Internal session state error |
822
- | `UNKNOWN_ERROR` | Unclassified failure (default for opaque SSE `error` events). Plain `AbortError` without “timeout” in the message maps here. |
818
+ | Code | Typical meaning |
819
+ | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
820
+ | `BACKEND_UNREACHABLE` | Agent health check failed or backend not responding |
821
+ | `AUTH_FAILED` | Auth/token failure, HTTP 401/403, or wrong vault password |
822
+ | `VAULT_LOCKED` | Encrypted vault needs unlock (password) |
823
+ | `PASSWORD_REQUIRED` | Password was not supplied when required (e.g. pipe mode or signing) |
824
+ | `CONFIRMATION_REQUIRED` | User confirmation needed (pipe mode; message prefix `CONFIRMATION_REQUIRED:`); also returned by `agent ask` on a declined sign (no `--yes`), exit 12 |
825
+ | `ACTION_NOT_IMPLEMENTED` | Local executor does not implement this action type |
826
+ | `INVALID_INPUT` | Bad parameters, unknown chain, malformed NDJSON input, etc. |
827
+ | `NETWORK_ERROR` | RPC/fetch connectivity (includes many SDK `VaultError` network cases) |
828
+ | `TIMEOUT` | HTTP deadline or SSE frame-idle deadline exceeded (process exit 3, retryable) |
829
+ | `TRANSACTION_FAILED` | Build/broadcast/gas errors mapped from the SDK |
830
+ | `SIGNING_FAILED` | MPC/signing failed |
831
+ | `ACK_FAILED` | Transaction broadcast, but its immediate acknowledgement/report failed; hash is valid and must be inspected before retrying |
832
+ | `BROADCAST_COMMITTED` | At least one transaction broadcast, but the overall agent request may be incomplete; do not blindly retry |
833
+ | `AGENT_TURN_BLOCKED` | A fund-safety guardrail blocked the requested action (exit 10) |
834
+ | `AGENT_TURN_REFUSAL` | The model refused or requested clarification without completing the action (exit 11) |
835
+ | `AGENT_TURN_ERROR` | The typed turn ending reported a failure without a more specific stream error |
836
+ | `IDEMPOTENT_TURN_DUPLICATE` | The backend already accepted the same keyed turn; inspect the conversation for the original persisted result |
837
+ | `IDEMPOTENCY_KEY_REUSED` | The idempotency key was already used for a _different_ request body. This request did NOT run and nothing was persisted for it — retry with a fresh key (exit code 4, not 14) |
838
+ | `SESSION_NOT_INITIALIZED` | Internal session state error |
839
+ | `UNKNOWN_ERROR` | Unclassified failure (default for opaque SSE `error` events). Plain `AbortError` without “timeout” in the message maps here. |
823
840
 
824
841
  SSE `error` events may optionally include a `code` field from the backend; if it matches one of the values above, it is passed through unchanged. Otherwise the CLI infers a code from the message.
825
842
 
@@ -830,6 +847,9 @@ SSE `error` events may optionally include a `code` field from the backend; if it
830
847
  - `--password <password>` - Vault password (fallback only; prefer the keyring/`VAULT_PASSWORD` env — see **Password resolution** above)
831
848
  - `--verbose` - Show tool calls and debug info on stderr
832
849
  - `--json` - Output structured JSON
850
+ - `--yes` - Authorize unattended signing/broadcast
851
+ - `--allow-auto-submit` - Separately allow backend submission of signed Polymarket orders (requires `--yes` to sign)
852
+ - `--force` - Bypass the duplicate-broadcast guard
833
853
 
834
854
  #### Agent Chat (Interactive/Pipe Mode)
835
855
 
@@ -853,6 +873,7 @@ The vault password is resolved from the keyring/env chain (`vsig auth setup` or
853
873
  - `--password <password>` - Vault password (fallback only; prefer the keyring/`VAULT_PASSWORD` env)
854
874
  - `--password-ttl <ms>` - Password cache TTL (default: 5min, 24h for `--via-agent`)
855
875
  - `--session-id <id>` - Resume an existing session
876
+ - `--allow-auto-submit` - Allow backend submission of signed Polymarket orders after local confirmation
856
877
 
857
878
  #### Pipe Protocol (`--via-agent`)
858
879
 
@@ -868,19 +889,20 @@ The pipe interface uses NDJSON (one JSON object per line) on stdin/stdout. Desig
868
889
 
869
890
  **Output events** (emitted on stdout):
870
891
 
871
- | Type | Fields | When |
872
- | ------------- | ------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
873
- | `ready` | `vault, addresses` | Session initialized, addresses for all chains |
874
- | `session` | `id` | Conversation ID for resuming later |
875
- | `history` | `messages[]` | Previous messages when resuming a session |
876
- | `text_delta` | `delta` | Streaming text chunk from the agent |
877
- | `tool_call` | `id, action, params?, status` | Action started (`running`) |
878
- | `tool_result` | `id, action, success, data?, error?, code?` | Action completed (`code` when `success` is false) |
879
- | `tx_status` | `tx_hash, chain, status, explorer_url?` | Transaction broadcast/confirmed/failed |
880
- | `assistant` | `content` | Full assistant response |
881
- | `suggestions` | `suggestions[]` | Suggested follow-up actions |
882
- | `error` | `message, code` | Error or control signal (`PASSWORD_REQUIRED`, `CONFIRMATION_REQUIRED: …`; always includes stable `code`) |
883
- | `done` | `{}` | Response cycle complete |
892
+ | Type | Fields | When |
893
+ | ------------- | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
894
+ | `ready` | `vault, addresses` | Session initialized, addresses for all chains |
895
+ | `session` | `id` | Conversation ID for resuming later |
896
+ | `history` | `messages[]` | Previous messages when resuming a session |
897
+ | `text_delta` | `delta` | Streaming text chunk from the agent |
898
+ | `tool_call` | `id, action, params?, status` | Action started (`running`) |
899
+ | `tool_result` | `id, action, success, data?, error?, code?` | Action completed (`code` when `success` is false) |
900
+ | `tx_status` | `tx_hash, chain, status, explorer_url?` | Transaction broadcast/confirmed/failed |
901
+ | `assistant` | `content` | Full assistant response |
902
+ | `suggestions` | `suggestions[]` | Suggested follow-up actions |
903
+ | `warning` | `warning: { code, message, count, eventTypes }` | Non-fatal protocol drift; an unrecognized SSE frame was ignored (`--verbose` only) |
904
+ | `error` | `message, code` | Error or control signal (`PASSWORD_REQUIRED`, `CONFIRMATION_REQUIRED: …`; always includes stable `code`) |
905
+ | `done` | `{}` | Response cycle complete |
884
906
 
885
907
  **Example session:**
886
908
 
@@ -935,6 +957,18 @@ VAULT_PASSWORDS='{"Vault 1":"pass1","vault-id-2":"pass2"}'
935
957
 
936
958
  # Suppress spinners and info messages
937
959
  VULTISIG_SILENT=1
960
+
961
+ # Bound agent-backend connection/unary requests (default: 30000ms)
962
+ VULTISIG_HTTP_TIMEOUT_MS=30000
963
+
964
+ # Bound an established SSE stream that stops making PROGRESS (default: 180000ms).
965
+ # Measures time since the last real data frame. Keep-alive comments do NOT extend
966
+ # it — both backends heartbeat on a timer that runs regardless of whether the turn
967
+ # is advancing, so a clock they reset would bound only a dead connection, never a
968
+ # wedged backend. Sized above the backend's worst-case silent stretch (a model call
969
+ # is bounded at 90s; the swap builder is documented at 90s + 60s MCP), so a slow but
970
+ # healthy turn is never killed.
971
+ VULTISIG_SSE_IDLE_TIMEOUT_MS=180000
938
972
  ```
939
973
 
940
974
  ### Settings
@@ -1227,6 +1261,9 @@ Configuration is stored in `~/.vultisig/`:
1227
1261
  | 11 | agent ask: the model refused or asked a clarifying question (no action taken) |
1228
1262
  | 12 | Interactive confirmation/input required but the session is non-interactive — pass --yes/--confirm or the required flag |
1229
1263
  | 13 | agent ask: transaction broadcast but the overall request may be incomplete — inspect the hash, do NOT blindly retry |
1264
+ | 14 | agent ask: duplicate keyed turn rejected — inspect the conversation for the original result |
1265
+ | 15 | No active vault selected — create, import, or switch to one |
1266
+ | 16 | Stored state is unreadable — repair it or re-import the vault from a .vult backup |
1230
1267
 
1231
1268
  > These are generated from the `ExitCode` enum in `src/core/errors.ts` (the single source of
1232
1269
  > truth) and are covered by a doc-lint test that fails if this table drifts from the code. Run