@vultisig/cli 2.7.0 → 2.8.1
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 +28 -0
- package/dist/index.js +194 -63
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @vultisig/cli
|
|
2
2
|
|
|
3
|
+
## 2.8.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#867](https://github.com/vultisig/vultisig-sdk/pull/867) [`ddd08af`](https://github.com/vultisig/vultisig-sdk/commit/ddd08af883a1b2ee2f72dac4d406782de9090672) Thanks [@neavra](https://github.com/neavra)! - Agent: poll for final on-chain confirmation after broadcasting a signed tx
|
|
8
|
+
(audit F1). A `pending` `tx_status` only means "broadcast accepted" — the tx can
|
|
9
|
+
still revert, expire, or be dropped. After broadcast the session now polls
|
|
10
|
+
`vault.getTxStatus` until the tx reaches a final state and emits `confirmed` /
|
|
11
|
+
`failed`, or `timeout` when the bounded poll budget (~120s) is exhausted. The
|
|
12
|
+
`ask` result records the latest per-tx `status` (deduped by hash), and the pipe
|
|
13
|
+
`tx_status` event gains a `timeout` status. Best-effort and non-fatal: when the
|
|
14
|
+
chain can't be resolved or the vault can't poll status, the existing `pending`
|
|
15
|
+
status stands. The blocking confirmation wait is scoped to the top of the
|
|
16
|
+
message loop (depth 0 — the single-tx ask/pipe case); inside a multi-turn tool
|
|
17
|
+
loop a leg keeps its honest `pending` instead of stacking the poll budget per
|
|
18
|
+
tx. The shared `pending | confirmed | failed | timeout` union is now threaded
|
|
19
|
+
through the ask result, pipe event, and UI callback without unchecked casts.
|
|
20
|
+
|
|
21
|
+
## 2.8.0
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- [#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.
|
|
26
|
+
|
|
27
|
+
- 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)]:
|
|
28
|
+
- @vultisig/sdk@2.8.0
|
|
29
|
+
- @vultisig/rujira@41.0.0
|
|
30
|
+
|
|
3
31
|
## 2.7.0
|
|
4
32
|
|
|
5
33
|
### 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
|
-
|
|
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
|
-
|
|
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: (
|
|
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,23 @@ var AskInterface = class {
|
|
|
8222
8223
|
},
|
|
8223
8224
|
onSuggestions: (_suggestions) => {
|
|
8224
8225
|
},
|
|
8225
|
-
onTxStatus: (txHash, chain,
|
|
8226
|
-
this.transactions.
|
|
8226
|
+
onTxStatus: (txHash, chain, status, explorerUrl) => {
|
|
8227
|
+
const existing = this.transactions.find((t) => t.hash === txHash);
|
|
8228
|
+
if (existing) {
|
|
8229
|
+
existing.status = status;
|
|
8230
|
+
if (explorerUrl) existing.explorerUrl = explorerUrl;
|
|
8231
|
+
} else {
|
|
8232
|
+
this.transactions.push({ hash: txHash, chain, explorerUrl, status });
|
|
8233
|
+
}
|
|
8227
8234
|
if (this.verbose) {
|
|
8228
|
-
process.stderr.write(`[tx] ${chain}: ${txHash}
|
|
8235
|
+
process.stderr.write(`[tx] ${chain}: ${txHash} (${status})
|
|
8229
8236
|
`);
|
|
8230
8237
|
}
|
|
8231
8238
|
},
|
|
8232
8239
|
onError: (message, code) => {
|
|
8240
|
+
if (!this.error) {
|
|
8241
|
+
this.error = { message, code };
|
|
8242
|
+
}
|
|
8233
8243
|
process.stderr.write(`[error] ${message} [${code}]
|
|
8234
8244
|
`);
|
|
8235
8245
|
},
|
|
@@ -8259,14 +8269,27 @@ var AskInterface = class {
|
|
|
8259
8269
|
this.toolCalls = [];
|
|
8260
8270
|
this.transactions = [];
|
|
8261
8271
|
this.cards = [];
|
|
8272
|
+
this.error = void 0;
|
|
8262
8273
|
const callbacks = this.getCallbacks();
|
|
8263
8274
|
await this.session.sendMessage(message, callbacks);
|
|
8275
|
+
return this.partialResult();
|
|
8276
|
+
}
|
|
8277
|
+
/**
|
|
8278
|
+
* Snapshot of everything collected so far this turn. Identical to a normal
|
|
8279
|
+
* `ask()` return, but callable from a catch block when `ask()` THREW mid-turn
|
|
8280
|
+
* — e.g. the follow-up request that reports recent_actions back to the backend
|
|
8281
|
+
* fails (timeout/5xx/auth) AFTER a tx has already broadcast and `onTxStatus`
|
|
8282
|
+
* fired. Lets the caller still surface the already-broadcast tx hash in the
|
|
8283
|
+
* error envelope instead of stranding funds the turn just moved.
|
|
8284
|
+
*/
|
|
8285
|
+
partialResult() {
|
|
8264
8286
|
return {
|
|
8265
8287
|
sessionId: this.session.getConversationId() || "",
|
|
8266
8288
|
response: this.responseParts[this.responseParts.length - 1] || "",
|
|
8267
8289
|
toolCalls: this.toolCalls,
|
|
8268
8290
|
transactions: this.transactions,
|
|
8269
|
-
cards: this.cards
|
|
8291
|
+
cards: this.cards,
|
|
8292
|
+
error: this.error
|
|
8270
8293
|
};
|
|
8271
8294
|
}
|
|
8272
8295
|
};
|
|
@@ -12063,6 +12086,8 @@ var CLIENT_SIDE_TOOL_DISPATCH = {
|
|
|
12063
12086
|
var MAX_MESSAGE_LOOP_DEPTH = 16;
|
|
12064
12087
|
var RECOVERY_POLL_INTERVAL_MS = 2e3;
|
|
12065
12088
|
var RECOVERY_MAX_POLLS = 90;
|
|
12089
|
+
var TX_CONFIRM_POLL_INTERVAL_MS = 3e3;
|
|
12090
|
+
var TX_CONFIRM_MAX_POLLS = 40;
|
|
12066
12091
|
var AgentSession = class {
|
|
12067
12092
|
client;
|
|
12068
12093
|
vault;
|
|
@@ -12080,6 +12105,10 @@ var AgentSession = class {
|
|
|
12080
12105
|
// poll loop without real 2s waits.
|
|
12081
12106
|
recoveryPollIntervalMs = RECOVERY_POLL_INTERVAL_MS;
|
|
12082
12107
|
recoveryMaxPolls = RECOVERY_MAX_POLLS;
|
|
12108
|
+
// Post-broadcast confirmation poll cadence — instance fields so tests can
|
|
12109
|
+
// drive the loop without real waits.
|
|
12110
|
+
txConfirmPollIntervalMs = TX_CONFIRM_POLL_INTERVAL_MS;
|
|
12111
|
+
txConfirmMaxPolls = TX_CONFIRM_MAX_POLLS;
|
|
12083
12112
|
constructor(vault, config) {
|
|
12084
12113
|
this.vault = vault;
|
|
12085
12114
|
this.config = config;
|
|
@@ -12358,7 +12387,9 @@ var AgentSession = class {
|
|
|
12358
12387
|
const txHash = recent.data.tx_hash;
|
|
12359
12388
|
const chain = recent.data.chain;
|
|
12360
12389
|
const explorerUrl = recent.data.explorer_url;
|
|
12361
|
-
if (txHash)
|
|
12390
|
+
if (txHash) {
|
|
12391
|
+
await this.emitAndConfirmTx(txHash, chain, explorerUrl, depth, ui);
|
|
12392
|
+
}
|
|
12362
12393
|
}
|
|
12363
12394
|
await this.processMessageLoop(null, ui, depth + 1);
|
|
12364
12395
|
return;
|
|
@@ -12417,6 +12448,75 @@ var AgentSession = class {
|
|
|
12417
12448
|
recoverySleep() {
|
|
12418
12449
|
return new Promise((resolve) => setTimeout(resolve, this.recoveryPollIntervalMs));
|
|
12419
12450
|
}
|
|
12451
|
+
/**
|
|
12452
|
+
* Post-broadcast confirmation polling (audit F1). A bare `pending` status only
|
|
12453
|
+
* means "broadcast accepted"; the tx can still revert, expire, or be dropped,
|
|
12454
|
+
* so a headless caller that stops at `pending` may mark a later-reverted
|
|
12455
|
+
* operation complete. Poll vault.getTxStatus until the tx reaches a final
|
|
12456
|
+
* state and emit the matching lifecycle status (`confirmed`/`failed`), or
|
|
12457
|
+
* `timeout` when the bounded poll budget is exhausted (the tx may still
|
|
12458
|
+
* confirm later — callers can re-check with `vultisig tx-status`).
|
|
12459
|
+
*
|
|
12460
|
+
* Transient RPC/network errors are treated as "not final yet" and retried
|
|
12461
|
+
* until the budget is spent. Best-effort and non-fatal: if the chain can't be
|
|
12462
|
+
* resolved or the vault doesn't expose getTxStatus, the caller's already-
|
|
12463
|
+
* emitted `pending` status stands and this returns quietly.
|
|
12464
|
+
*
|
|
12465
|
+
* Scoped to headless callers (ask/pipe) that need machine-readable finality.
|
|
12466
|
+
* The interactive TUI already shows `pending` + an explorer link immediately
|
|
12467
|
+
* and has the dedicated `vultisig tx-status` command, so blocking its prompt
|
|
12468
|
+
* for the full poll budget would be a UX regression the audit didn't scope.
|
|
12469
|
+
* The poll also bails on cancel (Ctrl-C aborts the controller) so a long wait
|
|
12470
|
+
* is interruptible.
|
|
12471
|
+
*
|
|
12472
|
+
* The caller only invokes this at message-loop depth 0 (see the call site):
|
|
12473
|
+
* inside a multi-turn tool loop the broadcast result already drives the next
|
|
12474
|
+
* turn, so blocking here would stack the poll budget per leg without feeding
|
|
12475
|
+
* the server any extra signal. Those deeper legs keep their honest `pending`.
|
|
12476
|
+
*/
|
|
12477
|
+
async emitAndConfirmTx(txHash, chain, explorerUrl, depth, ui) {
|
|
12478
|
+
ui.onTxStatus(txHash, chain || "", "pending", explorerUrl);
|
|
12479
|
+
if (depth === 0) {
|
|
12480
|
+
await this.confirmBroadcastedTx(txHash, chain, explorerUrl, ui);
|
|
12481
|
+
}
|
|
12482
|
+
}
|
|
12483
|
+
async confirmBroadcastedTx(txHash, chainName, explorerUrl, ui) {
|
|
12484
|
+
if (!this.config.askMode && !this.config.viaAgent) return;
|
|
12485
|
+
const chain = resolveChain(chainName ?? "");
|
|
12486
|
+
if (!chain || typeof this.vault?.getTxStatus !== "function") return;
|
|
12487
|
+
for (let attempt = 0; attempt < this.txConfirmMaxPolls; attempt++) {
|
|
12488
|
+
if (this.abortController?.signal?.aborted) return;
|
|
12489
|
+
try {
|
|
12490
|
+
const result = await this.vault.getTxStatus({ chain, txHash });
|
|
12491
|
+
if (result.status === "success") {
|
|
12492
|
+
ui.onTxStatus(txHash, chainName ?? "", "confirmed", explorerUrl);
|
|
12493
|
+
return;
|
|
12494
|
+
}
|
|
12495
|
+
if (result.status === "error") {
|
|
12496
|
+
ui.onTxStatus(txHash, chainName ?? "", "failed", explorerUrl);
|
|
12497
|
+
return;
|
|
12498
|
+
}
|
|
12499
|
+
} catch (err) {
|
|
12500
|
+
if (this.config.verbose) {
|
|
12501
|
+
process.stderr.write(`[session] tx confirm poll ${attempt + 1} failed: ${err?.message ?? err}
|
|
12502
|
+
`);
|
|
12503
|
+
}
|
|
12504
|
+
}
|
|
12505
|
+
if (attempt < this.txConfirmMaxPolls - 1) await this.txConfirmSleep();
|
|
12506
|
+
}
|
|
12507
|
+
if (this.abortController?.signal?.aborted) return;
|
|
12508
|
+
if (this.config.verbose) {
|
|
12509
|
+
process.stderr.write(
|
|
12510
|
+
`[session] tx ${txHash} not confirmed within ${this.txConfirmMaxPolls} polls; emitting timeout
|
|
12511
|
+
`
|
|
12512
|
+
);
|
|
12513
|
+
}
|
|
12514
|
+
ui.onTxStatus(txHash, chainName ?? "", "timeout", explorerUrl);
|
|
12515
|
+
}
|
|
12516
|
+
/** Sleep between confirmation polls. Separate method so tests can stub it out. */
|
|
12517
|
+
txConfirmSleep() {
|
|
12518
|
+
return new Promise((resolve) => setTimeout(resolve, this.txConfirmPollIntervalMs));
|
|
12519
|
+
}
|
|
12420
12520
|
/**
|
|
12421
12521
|
* Fold a recovered assistant message back into the live stream result: the
|
|
12422
12522
|
* authoritative message wins over any partial deltas, and any persisted
|
|
@@ -13068,12 +13168,85 @@ async function executeAgent(ctx2, options) {
|
|
|
13068
13168
|
}
|
|
13069
13169
|
}
|
|
13070
13170
|
}
|
|
13171
|
+
function outputAskError(wantsJson, message, code, conversationId, result) {
|
|
13172
|
+
if (wantsJson) {
|
|
13173
|
+
const data = {};
|
|
13174
|
+
if (result?.transactions.length) data.transactions = result.transactions;
|
|
13175
|
+
if (result?.toolCalls.length) data.tool_calls = result.toolCalls;
|
|
13176
|
+
if (result?.response) data.response = result.response;
|
|
13177
|
+
outputErrorJson({
|
|
13178
|
+
success: false,
|
|
13179
|
+
v: 1,
|
|
13180
|
+
error: { message, code, conversation_id: conversationId },
|
|
13181
|
+
...Object.keys(data).length > 0 ? { data } : {}
|
|
13182
|
+
});
|
|
13183
|
+
} else {
|
|
13184
|
+
process.stderr.write(`Error: ${message} [${code}]
|
|
13185
|
+
`);
|
|
13186
|
+
}
|
|
13187
|
+
}
|
|
13188
|
+
function outputAskHuman(result, confirmationRequired, proposed) {
|
|
13189
|
+
process.stdout.write(`session:${result.sessionId}
|
|
13190
|
+
`);
|
|
13191
|
+
if (confirmationRequired) {
|
|
13192
|
+
process.stdout.write(`confirmation-required:pass --yes to authorize signing
|
|
13193
|
+
`);
|
|
13194
|
+
if (proposed) {
|
|
13195
|
+
process.stdout.write(`proposed:${proposed}
|
|
13196
|
+
`);
|
|
13197
|
+
}
|
|
13198
|
+
}
|
|
13199
|
+
for (const card of result.cards) {
|
|
13200
|
+
process.stdout.write(`
|
|
13201
|
+
${renderBalanceSummaryCard(card)}
|
|
13202
|
+
`);
|
|
13203
|
+
}
|
|
13204
|
+
if (result.response) {
|
|
13205
|
+
process.stdout.write(`
|
|
13206
|
+
${result.response}
|
|
13207
|
+
`);
|
|
13208
|
+
}
|
|
13209
|
+
for (const tx of result.transactions) {
|
|
13210
|
+
process.stdout.write(`
|
|
13211
|
+
tx:${tx.chain}:${tx.hash}
|
|
13212
|
+
`);
|
|
13213
|
+
if (tx.explorerUrl) {
|
|
13214
|
+
process.stdout.write(`explorer:${tx.explorerUrl}
|
|
13215
|
+
`);
|
|
13216
|
+
}
|
|
13217
|
+
}
|
|
13218
|
+
}
|
|
13219
|
+
function outputAskSuccess(wantsJson, result, conversationId) {
|
|
13220
|
+
const confirmationRequired = result.toolCalls.some((tc) => tc.code === "CONFIRMATION_REQUIRED" /* CONFIRMATION_REQUIRED */);
|
|
13221
|
+
const proposedCall = result.toolCalls.find(
|
|
13222
|
+
(tc) => tc.code === "CONFIRMATION_REQUIRED" /* CONFIRMATION_REQUIRED */ && typeof tc.data?.proposed === "string"
|
|
13223
|
+
);
|
|
13224
|
+
const proposed = proposedCall?.data?.proposed;
|
|
13225
|
+
if (wantsJson) {
|
|
13226
|
+
outputJson({
|
|
13227
|
+
conversation_id: conversationId,
|
|
13228
|
+
session_id: result.sessionId,
|
|
13229
|
+
response: result.response,
|
|
13230
|
+
tool_calls: result.toolCalls,
|
|
13231
|
+
transactions: result.transactions,
|
|
13232
|
+
...result.cards.length > 0 ? { cards: result.cards } : {},
|
|
13233
|
+
...confirmationRequired ? { confirmation_required: true } : {},
|
|
13234
|
+
...proposed ? { proposed } : {}
|
|
13235
|
+
});
|
|
13236
|
+
return;
|
|
13237
|
+
}
|
|
13238
|
+
outputAskHuman(result, confirmationRequired, proposed);
|
|
13239
|
+
}
|
|
13071
13240
|
async function executeAgentAsk(ctx2, message, options) {
|
|
13072
13241
|
setSilentMode(true);
|
|
13073
13242
|
const originalConsoleLog = console.log;
|
|
13074
13243
|
console.log = (...args) => {
|
|
13075
13244
|
process.stderr.write(args.map(String).join(" ") + "\n");
|
|
13076
13245
|
};
|
|
13246
|
+
const wantsJson = !!options.json || isJsonOutput();
|
|
13247
|
+
let conversationId = "";
|
|
13248
|
+
let exitCode = 0;
|
|
13249
|
+
let ask;
|
|
13077
13250
|
try {
|
|
13078
13251
|
const vault = await ctx2.ensureActiveVault();
|
|
13079
13252
|
const config = {
|
|
@@ -13087,70 +13260,28 @@ async function executeAgentAsk(ctx2, message, options) {
|
|
|
13087
13260
|
profile: options.profile ?? process.env.VULTISIG_AGENT_PROFILE ?? ""
|
|
13088
13261
|
};
|
|
13089
13262
|
const session = new AgentSession(vault, config);
|
|
13090
|
-
|
|
13263
|
+
ask = new AskInterface(session, !!config.verbose, !!options.autoApprove);
|
|
13091
13264
|
const callbacks = ask.getCallbacks();
|
|
13092
13265
|
await session.initialize(callbacks);
|
|
13093
13266
|
const result = await ask.ask(message);
|
|
13094
|
-
|
|
13095
|
-
|
|
13096
|
-
|
|
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
|
-
});
|
|
13267
|
+
conversationId = result.sessionId;
|
|
13268
|
+
if (result.error) {
|
|
13269
|
+
exitCode = 1;
|
|
13270
|
+
outputAskError(wantsJson, result.error.message, result.error.code, conversationId, result);
|
|
13109
13271
|
} else {
|
|
13110
|
-
|
|
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
|
-
}
|
|
13272
|
+
outputAskSuccess(wantsJson, result, conversationId);
|
|
13139
13273
|
}
|
|
13140
13274
|
} catch (err) {
|
|
13141
13275
|
const { code, message: message2 } = normalizeAgentError(err);
|
|
13142
|
-
|
|
13143
|
-
|
|
13144
|
-
|
|
13145
|
-
|
|
13146
|
-
`);
|
|
13147
|
-
}
|
|
13148
|
-
process.exit(1);
|
|
13276
|
+
exitCode = 1;
|
|
13277
|
+
const partial = ask?.partialResult();
|
|
13278
|
+
if (partial && !conversationId) conversationId = partial.sessionId;
|
|
13279
|
+
outputAskError(wantsJson, message2, code, conversationId, partial);
|
|
13149
13280
|
} finally {
|
|
13150
13281
|
console.log = originalConsoleLog;
|
|
13151
13282
|
setSilentMode(false);
|
|
13152
13283
|
}
|
|
13153
|
-
process.exit(
|
|
13284
|
+
process.exit(exitCode);
|
|
13154
13285
|
}
|
|
13155
13286
|
async function executeAgentSessionsList(ctx2, options) {
|
|
13156
13287
|
const vault = await ctx2.ensureActiveVault();
|
|
@@ -13235,7 +13366,7 @@ var cachedVersion = null;
|
|
|
13235
13366
|
function getVersion() {
|
|
13236
13367
|
if (cachedVersion) return cachedVersion;
|
|
13237
13368
|
if (true) {
|
|
13238
|
-
cachedVersion = "2.
|
|
13369
|
+
cachedVersion = "2.8.1";
|
|
13239
13370
|
return cachedVersion;
|
|
13240
13371
|
}
|
|
13241
13372
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vultisig/cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.1",
|
|
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": "^
|
|
79
|
-
"@vultisig/sdk": "^2.
|
|
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",
|