@vultisig/cli 1.8.1 → 2.0.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 +46 -0
- package/dist/index.js +229 -90
- package/package.json +16 -16
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# @vultisig/cli
|
|
2
2
|
|
|
3
|
+
## 2.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- [#682](https://github.com/vultisig/vultisig-sdk/pull/682) [`341245e`](https://github.com/vultisig/vultisig-sdk/commit/341245e2d6d49348e38d61bc42805c35ac8d3052) Thanks [@neavra](https://github.com/neavra)! - Gate signing in `agent ask` mode behind explicit confirmation (security fix, **breaking**).
|
|
8
|
+
|
|
9
|
+
Previously `vsig agent ask` auto-signed and broadcast any transaction envelope the
|
|
10
|
+
backend returned, gated only by whether a password was present. Because the backend
|
|
11
|
+
routes read-only swap intents (e.g. "list swap routes from USDC to ETH") to the
|
|
12
|
+
fund-moving `execute_swap` tool, a query could broadcast a real on-chain swap.
|
|
13
|
+
|
|
14
|
+
`runPasswordGatedTool` now calls `ui.requestConfirmation` before any `sign_tx` /
|
|
15
|
+
`sign_typed_data` (the single chokepoint for both the tx_ready path and client-side
|
|
16
|
+
dispatch, covering both legs of a multi-leg swap). In ask mode this defaults to
|
|
17
|
+
**deny**: signing/broadcast now requires the new `agent ask --yes` flag. Without it,
|
|
18
|
+
the proposed transaction is reported (`CONFIRMATION_REQUIRED`) and nothing is signed.
|
|
19
|
+
Interactive (TUI) and pipe (`--via-agent`) modes already prompt/defer for confirmation.
|
|
20
|
+
|
|
21
|
+
**BREAKING — migration for unattended pipelines:** any automation that relied on
|
|
22
|
+
`agent ask` auto-signing must now pass `--yes`. A denied signing still exits **0**
|
|
23
|
+
(a misrouted read-only prompt remains a successful query); detect it via the new
|
|
24
|
+
top-level `confirmation_required: true` field in `--output json` mode, the
|
|
25
|
+
`confirmation-required:` line in text mode, or `tool_calls[].code ===
|
|
26
|
+
"CONFIRMATION_REQUIRED"`. Do not infer "broadcast happened" from exit code alone —
|
|
27
|
+
check the `transactions` array. With `--yes`, each authorization is logged to stderr
|
|
28
|
+
(`[confirm] auto-approved (--yes): <summary>`).
|
|
29
|
+
|
|
30
|
+
### Patch Changes
|
|
31
|
+
|
|
32
|
+
- Updated dependencies [[`dc75595`](https://github.com/vultisig/vultisig-sdk/commit/dc75595e83360f5bda84b2d91cae177bc7c8c966)]:
|
|
33
|
+
- @vultisig/sdk@2.0.0
|
|
34
|
+
- @vultisig/rujira@33.0.0
|
|
35
|
+
- @vultisig/client-shared@0.2.15
|
|
36
|
+
|
|
37
|
+
## 1.8.10
|
|
38
|
+
|
|
39
|
+
### Patch Changes
|
|
40
|
+
|
|
41
|
+
- [#683](https://github.com/vultisig/vultisig-sdk/pull/683) [`4561129`](https://github.com/vultisig/vultisig-sdk/commit/45611297a55da72d3c56b1a2ffe6522da1b64d7b) Thanks [@rcoderdev](https://github.com/rcoderdev)! - Update SDK package dependencies and Yarn tooling.
|
|
42
|
+
|
|
43
|
+
- Updated dependencies [[`4561129`](https://github.com/vultisig/vultisig-sdk/commit/45611297a55da72d3c56b1a2ffe6522da1b64d7b)]:
|
|
44
|
+
- @vultisig/client-shared@0.2.14
|
|
45
|
+
- @vultisig/core-chain@2.14.1
|
|
46
|
+
- @vultisig/rujira@32.0.1
|
|
47
|
+
- @vultisig/sdk@1.8.10
|
|
48
|
+
|
|
3
49
|
## 1.8.1
|
|
4
50
|
|
|
5
51
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -1102,7 +1102,7 @@ var require_main = __commonJS({
|
|
|
1102
1102
|
}
|
|
1103
1103
|
});
|
|
1104
1104
|
|
|
1105
|
-
//
|
|
1105
|
+
// node_modules/@noble/hashes/_u64.js
|
|
1106
1106
|
function fromBig(n, le = false) {
|
|
1107
1107
|
if (le)
|
|
1108
1108
|
return { h: Number(n & U32_MASK64), l: Number(n >> _32n & U32_MASK64) };
|
|
@@ -1120,7 +1120,7 @@ function split(lst, le = false) {
|
|
|
1120
1120
|
}
|
|
1121
1121
|
var U32_MASK64, _32n, rotlSH, rotlSL, rotlBH, rotlBL;
|
|
1122
1122
|
var init_u64 = __esm({
|
|
1123
|
-
"
|
|
1123
|
+
"node_modules/@noble/hashes/_u64.js"() {
|
|
1124
1124
|
U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
|
|
1125
1125
|
_32n = /* @__PURE__ */ BigInt(32);
|
|
1126
1126
|
rotlSH = (h, l, s) => h << s | l >>> 32 - s;
|
|
@@ -1130,19 +1130,34 @@ var init_u64 = __esm({
|
|
|
1130
1130
|
}
|
|
1131
1131
|
});
|
|
1132
1132
|
|
|
1133
|
-
//
|
|
1133
|
+
// node_modules/@noble/hashes/utils.js
|
|
1134
1134
|
function isBytes(a) {
|
|
1135
|
-
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
|
|
1135
|
+
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a && a.BYTES_PER_ELEMENT === 1;
|
|
1136
1136
|
}
|
|
1137
|
-
function anumber(n) {
|
|
1138
|
-
if (
|
|
1139
|
-
|
|
1137
|
+
function anumber(n, title = "") {
|
|
1138
|
+
if (typeof n !== "number") {
|
|
1139
|
+
const prefix = title && `"${title}" `;
|
|
1140
|
+
throw new TypeError(`${prefix}expected number, got ${typeof n}`);
|
|
1141
|
+
}
|
|
1142
|
+
if (!Number.isSafeInteger(n) || n < 0) {
|
|
1143
|
+
const prefix = title && `"${title}" `;
|
|
1144
|
+
throw new RangeError(`${prefix}expected integer >= 0, got ${n}`);
|
|
1145
|
+
}
|
|
1140
1146
|
}
|
|
1141
|
-
function abytes(
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1147
|
+
function abytes(value, length, title = "") {
|
|
1148
|
+
const bytes = isBytes(value);
|
|
1149
|
+
const len = value?.length;
|
|
1150
|
+
const needsLen = length !== void 0;
|
|
1151
|
+
if (!bytes || needsLen && len !== length) {
|
|
1152
|
+
const prefix = title && `"${title}" `;
|
|
1153
|
+
const ofLen = needsLen ? ` of length ${length}` : "";
|
|
1154
|
+
const got = bytes ? `length=${len}` : `type=${typeof value}`;
|
|
1155
|
+
const message = prefix + "expected Uint8Array" + ofLen + ", got " + got;
|
|
1156
|
+
if (!bytes)
|
|
1157
|
+
throw new TypeError(message);
|
|
1158
|
+
throw new RangeError(message);
|
|
1159
|
+
}
|
|
1160
|
+
return value;
|
|
1146
1161
|
}
|
|
1147
1162
|
function aexists(instance, checkFinished = true) {
|
|
1148
1163
|
if (instance.destroyed)
|
|
@@ -1151,10 +1166,10 @@ function aexists(instance, checkFinished = true) {
|
|
|
1151
1166
|
throw new Error("Hash#digest() has already been called");
|
|
1152
1167
|
}
|
|
1153
1168
|
function aoutput(out, instance) {
|
|
1154
|
-
abytes(out);
|
|
1169
|
+
abytes(out, void 0, "digestInto() output");
|
|
1155
1170
|
const min = instance.outputLen;
|
|
1156
1171
|
if (out.length < min) {
|
|
1157
|
-
throw new
|
|
1172
|
+
throw new RangeError('"digestInto() output" expected to be of length >=' + min);
|
|
1158
1173
|
}
|
|
1159
1174
|
}
|
|
1160
1175
|
function u32(arr) {
|
|
@@ -1174,44 +1189,30 @@ function byteSwap32(arr) {
|
|
|
1174
1189
|
}
|
|
1175
1190
|
return arr;
|
|
1176
1191
|
}
|
|
1177
|
-
function
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
return new Uint8Array(new TextEncoder().encode(str));
|
|
1181
|
-
}
|
|
1182
|
-
function toBytes(data) {
|
|
1183
|
-
if (typeof data === "string")
|
|
1184
|
-
data = utf8ToBytes(data);
|
|
1185
|
-
abytes(data);
|
|
1186
|
-
return data;
|
|
1187
|
-
}
|
|
1188
|
-
function createHasher(hashCons) {
|
|
1189
|
-
const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
|
|
1190
|
-
const tmp = hashCons();
|
|
1191
|
-
hashC.outputLen = tmp.outputLen;
|
|
1192
|
-
hashC.blockLen = tmp.blockLen;
|
|
1193
|
-
hashC.create = () => hashCons();
|
|
1194
|
-
return hashC;
|
|
1195
|
-
}
|
|
1196
|
-
function createXOFer(hashCons) {
|
|
1197
|
-
const hashC = (msg, opts) => hashCons(opts).update(toBytes(msg)).digest();
|
|
1198
|
-
const tmp = hashCons({});
|
|
1192
|
+
function createHasher(hashCons, info2 = {}) {
|
|
1193
|
+
const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
|
|
1194
|
+
const tmp = hashCons(void 0);
|
|
1199
1195
|
hashC.outputLen = tmp.outputLen;
|
|
1200
1196
|
hashC.blockLen = tmp.blockLen;
|
|
1197
|
+
hashC.canXOF = tmp.canXOF;
|
|
1201
1198
|
hashC.create = (opts) => hashCons(opts);
|
|
1202
|
-
|
|
1199
|
+
Object.assign(hashC, info2);
|
|
1200
|
+
return Object.freeze(hashC);
|
|
1203
1201
|
}
|
|
1204
|
-
var isLE, swap32IfBE,
|
|
1202
|
+
var isLE, swap32IfBE, oidNist;
|
|
1205
1203
|
var init_utils = __esm({
|
|
1206
|
-
"
|
|
1204
|
+
"node_modules/@noble/hashes/utils.js"() {
|
|
1207
1205
|
isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)();
|
|
1208
1206
|
swap32IfBE = isLE ? (u) => u : byteSwap32;
|
|
1209
|
-
|
|
1210
|
-
|
|
1207
|
+
oidNist = (suffix) => ({
|
|
1208
|
+
// Current NIST hashAlgs suffixes used here fit in one DER subidentifier octet.
|
|
1209
|
+
// Larger suffix values would need base-128 OID encoding and a different length byte.
|
|
1210
|
+
oid: Uint8Array.from([6, 9, 96, 134, 72, 1, 101, 3, 4, 2, suffix])
|
|
1211
|
+
});
|
|
1211
1212
|
}
|
|
1212
1213
|
});
|
|
1213
1214
|
|
|
1214
|
-
//
|
|
1215
|
+
// node_modules/@noble/hashes/sha3.js
|
|
1215
1216
|
var sha3_exports = {};
|
|
1216
1217
|
__export(sha3_exports, {
|
|
1217
1218
|
Keccak: () => Keccak,
|
|
@@ -1225,9 +1226,14 @@ __export(sha3_exports, {
|
|
|
1225
1226
|
sha3_384: () => sha3_384,
|
|
1226
1227
|
sha3_512: () => sha3_512,
|
|
1227
1228
|
shake128: () => shake128,
|
|
1228
|
-
|
|
1229
|
+
shake128_32: () => shake128_32,
|
|
1230
|
+
shake256: () => shake256,
|
|
1231
|
+
shake256_64: () => shake256_64
|
|
1229
1232
|
});
|
|
1230
1233
|
function keccakP(s, rounds = 24) {
|
|
1234
|
+
anumber(rounds, "rounds");
|
|
1235
|
+
if (rounds < 1 || rounds > 24)
|
|
1236
|
+
throw new Error('"rounds" expected integer 1..24');
|
|
1231
1237
|
const B = new Uint32Array(5 * 2);
|
|
1232
1238
|
for (let round = 24 - rounds; round < 24; round++) {
|
|
1233
1239
|
for (let x = 0; x < 10; x++)
|
|
@@ -1257,19 +1263,26 @@ function keccakP(s, rounds = 24) {
|
|
|
1257
1263
|
s[PI + 1] = Tl;
|
|
1258
1264
|
}
|
|
1259
1265
|
for (let y = 0; y < 50; y += 10) {
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1266
|
+
const b0 = s[y], b1 = s[y + 1], b2 = s[y + 2], b3 = s[y + 3];
|
|
1267
|
+
s[y] ^= ~s[y + 2] & s[y + 4];
|
|
1268
|
+
s[y + 1] ^= ~s[y + 3] & s[y + 5];
|
|
1269
|
+
s[y + 2] ^= ~s[y + 4] & s[y + 6];
|
|
1270
|
+
s[y + 3] ^= ~s[y + 5] & s[y + 7];
|
|
1271
|
+
s[y + 4] ^= ~s[y + 6] & s[y + 8];
|
|
1272
|
+
s[y + 5] ^= ~s[y + 7] & s[y + 9];
|
|
1273
|
+
s[y + 6] ^= ~s[y + 8] & b0;
|
|
1274
|
+
s[y + 7] ^= ~s[y + 9] & b1;
|
|
1275
|
+
s[y + 8] ^= ~b0 & b2;
|
|
1276
|
+
s[y + 9] ^= ~b1 & b3;
|
|
1264
1277
|
}
|
|
1265
1278
|
s[0] ^= SHA3_IOTA_H[round];
|
|
1266
1279
|
s[1] ^= SHA3_IOTA_L[round];
|
|
1267
1280
|
}
|
|
1268
1281
|
clean(B);
|
|
1269
1282
|
}
|
|
1270
|
-
var _0n, _1n, _2n, _7n, _256n, _0x71n, SHA3_PI, SHA3_ROTL, _SHA3_IOTA, IOTAS, SHA3_IOTA_H, SHA3_IOTA_L, rotlH, rotlL, Keccak,
|
|
1283
|
+
var _0n, _1n, _2n, _7n, _256n, _0x71n, SHA3_PI, SHA3_ROTL, _SHA3_IOTA, IOTAS, SHA3_IOTA_H, SHA3_IOTA_L, rotlH, rotlL, Keccak, genKeccak, sha3_224, sha3_256, sha3_384, sha3_512, keccak_224, keccak_256, keccak_384, keccak_512, genShake, shake128, shake256, shake128_32, shake256_64;
|
|
1271
1284
|
var init_sha3 = __esm({
|
|
1272
|
-
"
|
|
1285
|
+
"node_modules/@noble/hashes/sha3.js"() {
|
|
1273
1286
|
init_u64();
|
|
1274
1287
|
init_utils();
|
|
1275
1288
|
_0n = BigInt(0);
|
|
@@ -1289,7 +1302,7 @@ var init_sha3 = __esm({
|
|
|
1289
1302
|
for (let j = 0; j < 7; j++) {
|
|
1290
1303
|
R = (R << _1n ^ (R >> _7n) * _0x71n) % _256n;
|
|
1291
1304
|
if (R & _2n)
|
|
1292
|
-
t ^= _1n << (_1n <<
|
|
1305
|
+
t ^= _1n << (_1n << BigInt(j)) - _1n;
|
|
1293
1306
|
}
|
|
1294
1307
|
_SHA3_IOTA.push(t);
|
|
1295
1308
|
}
|
|
@@ -1298,21 +1311,28 @@ var init_sha3 = __esm({
|
|
|
1298
1311
|
SHA3_IOTA_L = IOTAS[1];
|
|
1299
1312
|
rotlH = (h, l, s) => s > 32 ? rotlBH(h, l, s) : rotlSH(h, l, s);
|
|
1300
1313
|
rotlL = (h, l, s) => s > 32 ? rotlBL(h, l, s) : rotlSL(h, l, s);
|
|
1301
|
-
Keccak = class _Keccak
|
|
1314
|
+
Keccak = class _Keccak {
|
|
1315
|
+
state;
|
|
1316
|
+
pos = 0;
|
|
1317
|
+
posOut = 0;
|
|
1318
|
+
finished = false;
|
|
1319
|
+
state32;
|
|
1320
|
+
destroyed = false;
|
|
1321
|
+
blockLen;
|
|
1322
|
+
suffix;
|
|
1323
|
+
outputLen;
|
|
1324
|
+
canXOF;
|
|
1325
|
+
enableXOF = false;
|
|
1326
|
+
rounds;
|
|
1302
1327
|
// NOTE: we accept arguments in bytes instead of bits here.
|
|
1303
1328
|
constructor(blockLen, suffix, outputLen, enableXOF = false, rounds = 24) {
|
|
1304
|
-
super();
|
|
1305
|
-
this.pos = 0;
|
|
1306
|
-
this.posOut = 0;
|
|
1307
|
-
this.finished = false;
|
|
1308
|
-
this.destroyed = false;
|
|
1309
|
-
this.enableXOF = false;
|
|
1310
1329
|
this.blockLen = blockLen;
|
|
1311
1330
|
this.suffix = suffix;
|
|
1312
1331
|
this.outputLen = outputLen;
|
|
1313
1332
|
this.enableXOF = enableXOF;
|
|
1333
|
+
this.canXOF = enableXOF;
|
|
1314
1334
|
this.rounds = rounds;
|
|
1315
|
-
anumber(outputLen);
|
|
1335
|
+
anumber(outputLen, "outputLen");
|
|
1316
1336
|
if (!(0 < blockLen && blockLen < 200))
|
|
1317
1337
|
throw new Error("only keccak-f1600 function is supported");
|
|
1318
1338
|
this.state = new Uint8Array(200);
|
|
@@ -1330,7 +1350,6 @@ var init_sha3 = __esm({
|
|
|
1330
1350
|
}
|
|
1331
1351
|
update(data) {
|
|
1332
1352
|
aexists(this);
|
|
1333
|
-
data = toBytes(data);
|
|
1334
1353
|
abytes(data);
|
|
1335
1354
|
const { blockLen, state } = this;
|
|
1336
1355
|
const len = data.length;
|
|
@@ -1383,12 +1402,13 @@ var init_sha3 = __esm({
|
|
|
1383
1402
|
aoutput(out, this);
|
|
1384
1403
|
if (this.finished)
|
|
1385
1404
|
throw new Error("digest() was already called");
|
|
1386
|
-
this.writeInto(out);
|
|
1405
|
+
this.writeInto(out.subarray(0, this.outputLen));
|
|
1387
1406
|
this.destroy();
|
|
1388
|
-
return out;
|
|
1389
1407
|
}
|
|
1390
1408
|
digest() {
|
|
1391
|
-
|
|
1409
|
+
const out = new Uint8Array(this.outputLen);
|
|
1410
|
+
this.digestInto(out);
|
|
1411
|
+
return out;
|
|
1392
1412
|
}
|
|
1393
1413
|
destroy() {
|
|
1394
1414
|
this.destroyed = true;
|
|
@@ -1396,7 +1416,8 @@ var init_sha3 = __esm({
|
|
|
1396
1416
|
}
|
|
1397
1417
|
_cloneInto(to) {
|
|
1398
1418
|
const { blockLen, suffix, outputLen, rounds, enableXOF } = this;
|
|
1399
|
-
to
|
|
1419
|
+
to ||= new _Keccak(blockLen, suffix, outputLen, enableXOF, rounds);
|
|
1420
|
+
to.blockLen = blockLen;
|
|
1400
1421
|
to.state32.set(this.state32);
|
|
1401
1422
|
to.pos = this.pos;
|
|
1402
1423
|
to.posOut = this.posOut;
|
|
@@ -1405,22 +1426,45 @@ var init_sha3 = __esm({
|
|
|
1405
1426
|
to.suffix = suffix;
|
|
1406
1427
|
to.outputLen = outputLen;
|
|
1407
1428
|
to.enableXOF = enableXOF;
|
|
1429
|
+
to.canXOF = this.canXOF;
|
|
1408
1430
|
to.destroyed = this.destroyed;
|
|
1409
1431
|
return to;
|
|
1410
1432
|
}
|
|
1411
1433
|
};
|
|
1412
|
-
|
|
1413
|
-
sha3_224 = /* @__PURE__ */ (
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1434
|
+
genKeccak = (suffix, blockLen, outputLen, info2 = {}) => createHasher(() => new Keccak(blockLen, suffix, outputLen), info2);
|
|
1435
|
+
sha3_224 = /* @__PURE__ */ genKeccak(
|
|
1436
|
+
6,
|
|
1437
|
+
144,
|
|
1438
|
+
28,
|
|
1439
|
+
/* @__PURE__ */ oidNist(7)
|
|
1440
|
+
);
|
|
1441
|
+
sha3_256 = /* @__PURE__ */ genKeccak(
|
|
1442
|
+
6,
|
|
1443
|
+
136,
|
|
1444
|
+
32,
|
|
1445
|
+
/* @__PURE__ */ oidNist(8)
|
|
1446
|
+
);
|
|
1447
|
+
sha3_384 = /* @__PURE__ */ genKeccak(
|
|
1448
|
+
6,
|
|
1449
|
+
104,
|
|
1450
|
+
48,
|
|
1451
|
+
/* @__PURE__ */ oidNist(9)
|
|
1452
|
+
);
|
|
1453
|
+
sha3_512 = /* @__PURE__ */ genKeccak(
|
|
1454
|
+
6,
|
|
1455
|
+
72,
|
|
1456
|
+
64,
|
|
1457
|
+
/* @__PURE__ */ oidNist(10)
|
|
1458
|
+
);
|
|
1459
|
+
keccak_224 = /* @__PURE__ */ genKeccak(1, 144, 28);
|
|
1460
|
+
keccak_256 = /* @__PURE__ */ genKeccak(1, 136, 32);
|
|
1461
|
+
keccak_384 = /* @__PURE__ */ genKeccak(1, 104, 48);
|
|
1462
|
+
keccak_512 = /* @__PURE__ */ genKeccak(1, 72, 64);
|
|
1463
|
+
genShake = (suffix, blockLen, outputLen, info2 = {}) => createHasher((opts = {}) => new Keccak(blockLen, suffix, opts.dkLen === void 0 ? outputLen : opts.dkLen, true), info2);
|
|
1464
|
+
shake128 = /* @__PURE__ */ genShake(31, 168, 16, /* @__PURE__ */ oidNist(11));
|
|
1465
|
+
shake256 = /* @__PURE__ */ genShake(31, 136, 32, /* @__PURE__ */ oidNist(12));
|
|
1466
|
+
shake128_32 = /* @__PURE__ */ genShake(31, 168, 32, /* @__PURE__ */ oidNist(11));
|
|
1467
|
+
shake256_64 = /* @__PURE__ */ genShake(31, 136, 64, /* @__PURE__ */ oidNist(12));
|
|
1424
1468
|
}
|
|
1425
1469
|
});
|
|
1426
1470
|
|
|
@@ -4753,12 +4797,14 @@ function normalizeAgentError(err) {
|
|
|
4753
4797
|
var AskInterface = class {
|
|
4754
4798
|
session;
|
|
4755
4799
|
verbose;
|
|
4800
|
+
autoApprove;
|
|
4756
4801
|
responseParts = [];
|
|
4757
4802
|
toolCalls = [];
|
|
4758
4803
|
transactions = [];
|
|
4759
|
-
constructor(session, verbose = false) {
|
|
4804
|
+
constructor(session, verbose = false, autoApprove = false) {
|
|
4760
4805
|
this.session = session;
|
|
4761
4806
|
this.verbose = verbose;
|
|
4807
|
+
this.autoApprove = autoApprove;
|
|
4762
4808
|
}
|
|
4763
4809
|
/**
|
|
4764
4810
|
* Get UI callbacks that silently collect results.
|
|
@@ -4806,8 +4852,15 @@ var AskInterface = class {
|
|
|
4806
4852
|
requestPassword: async () => {
|
|
4807
4853
|
throw new Error("Password required but not provided. Use --password flag.");
|
|
4808
4854
|
},
|
|
4809
|
-
requestConfirmation: async (
|
|
4810
|
-
|
|
4855
|
+
requestConfirmation: async (message) => {
|
|
4856
|
+
if (!this.autoApprove) {
|
|
4857
|
+
process.stderr.write(`[confirm] signing requires --yes \u2014 NOT broadcasting: ${message}
|
|
4858
|
+
`);
|
|
4859
|
+
} else {
|
|
4860
|
+
process.stderr.write(`[confirm] auto-approved (--yes): ${message}
|
|
4861
|
+
`);
|
|
4862
|
+
}
|
|
4863
|
+
return this.autoApprove;
|
|
4811
4864
|
}
|
|
4812
4865
|
};
|
|
4813
4866
|
}
|
|
@@ -6148,6 +6201,7 @@ var AgentExecutor = class {
|
|
|
6148
6201
|
const chain2 = resolveChainFromTxReady(txReadyData) || Chain10.Ethereum;
|
|
6149
6202
|
if (getChainKind(chain2) !== "evm") {
|
|
6150
6203
|
this.pendingPayloads.clear();
|
|
6204
|
+
this.pendingLegs = [];
|
|
6151
6205
|
this.pendingPayloads.set("latest", {
|
|
6152
6206
|
payload: { __serverTx: true, ...txReadyData },
|
|
6153
6207
|
coin: { chain: chain2, address: "", decimals: 18, ticker: "" },
|
|
@@ -6171,6 +6225,7 @@ var AgentExecutor = class {
|
|
|
6171
6225
|
}
|
|
6172
6226
|
const chain = resolveChainFromTxReady(txReadyData) || Chain10.Ethereum;
|
|
6173
6227
|
this.pendingPayloads.clear();
|
|
6228
|
+
this.pendingLegs = [];
|
|
6174
6229
|
this.pendingPayloads.set("latest", {
|
|
6175
6230
|
payload: { __serverTx: true, ...txReadyData },
|
|
6176
6231
|
coin: { chain, address: "", decimals: 18, ticker: "" },
|
|
@@ -6187,6 +6242,43 @@ var AgentExecutor = class {
|
|
|
6187
6242
|
hasPendingTransaction() {
|
|
6188
6243
|
return this.pendingPayloads.has("latest");
|
|
6189
6244
|
}
|
|
6245
|
+
/**
|
|
6246
|
+
* Drop the buffered server tx and any staged multi-leg state. Called when
|
|
6247
|
+
* the user declines the pre-sign confirmation: the rejected envelope must
|
|
6248
|
+
* not linger (a fresh tx_ready always overwrites, but stale legs/payloads
|
|
6249
|
+
* would otherwise survive into later turns).
|
|
6250
|
+
*/
|
|
6251
|
+
clearPendingTransaction() {
|
|
6252
|
+
this.pendingPayloads.clear();
|
|
6253
|
+
this.pendingLegs = [];
|
|
6254
|
+
}
|
|
6255
|
+
/**
|
|
6256
|
+
* Human-readable one-line summary of the currently-buffered server tx
|
|
6257
|
+
* (set by storeServerTransaction), for the pre-sign confirmation prompt.
|
|
6258
|
+
* Returns null when nothing is buffered (e.g. sign_typed_data, which has
|
|
6259
|
+
* no tx_ready payload — callers fall back to the tool input).
|
|
6260
|
+
*/
|
|
6261
|
+
getPendingSummary() {
|
|
6262
|
+
const stored = this.pendingPayloads.get("latest");
|
|
6263
|
+
if (!stored) return null;
|
|
6264
|
+
const p = stored.payload;
|
|
6265
|
+
const labels = p?.resolved?.labels ?? {};
|
|
6266
|
+
const isSwap = !!(p?.approvalTxArgs || p?.swap_tx || labels.quote_summary || labels.to_token_symbol);
|
|
6267
|
+
if (isSwap) {
|
|
6268
|
+
const usedQuoteSummary = !!labels.quote_summary;
|
|
6269
|
+
const head = labels.quote_summary || `swap ${labels.amount_in ?? p?.txArgs?.amount ?? "?"} ${labels.from_token_symbol ?? ""} \u2192 ${labels.to_token_symbol ?? ""}`.trim();
|
|
6270
|
+
const parts = [head, `on ${stored.chain}`];
|
|
6271
|
+
if (!usedQuoteSummary && labels.provider) parts.push(`via ${labels.provider}`);
|
|
6272
|
+
if (p?.__multiLeg) parts.push("(+ token approval \u2014 2 transactions)");
|
|
6273
|
+
if (labels.estimated_fee) parts.push(`est. fee ${labels.estimated_fee}`);
|
|
6274
|
+
return parts.join(" ");
|
|
6275
|
+
}
|
|
6276
|
+
const amount = labels.resolved_amount ?? p?.txArgs?.amount ?? "?";
|
|
6277
|
+
const symbol = labels.token_resolved || labels.token_symbol || "";
|
|
6278
|
+
const amountWithSymbol = symbol && !amount.endsWith(` ${symbol}`) ? `${amount} ${symbol}` : amount;
|
|
6279
|
+
const to = p?.txArgs?.to || labels.recipient_echo || "?";
|
|
6280
|
+
return `send ${amountWithSymbol} on ${stored.chain} to ${to}`;
|
|
6281
|
+
}
|
|
6190
6282
|
/**
|
|
6191
6283
|
* Wrap a per-tool handler body with normalised success/failure → RecentAction
|
|
6192
6284
|
* conversion. Replaces the legacy executeAction → ActionResult adapter that
|
|
@@ -8077,6 +8169,34 @@ var AgentSession = class {
|
|
|
8077
8169
|
* prompt was declined).
|
|
8078
8170
|
*/
|
|
8079
8171
|
async runPasswordGatedTool(toolName, toolCallId, ui, body, input) {
|
|
8172
|
+
if (PASSWORD_REQUIRED_TOOLS.has(toolName)) {
|
|
8173
|
+
const summary = (toolName === "sign_tx" ? this.executor.getPendingSummary() : null) ?? `${toolName}${input ? ` ${JSON.stringify(input)}` : ""}`;
|
|
8174
|
+
const approved = await ui.requestConfirmation(summary);
|
|
8175
|
+
if (!approved) {
|
|
8176
|
+
if (toolName === "sign_tx") {
|
|
8177
|
+
this.executor.clearPendingTransaction();
|
|
8178
|
+
}
|
|
8179
|
+
const declined = {
|
|
8180
|
+
tool: toolName,
|
|
8181
|
+
success: false,
|
|
8182
|
+
data: {
|
|
8183
|
+
error: "Transaction not confirmed",
|
|
8184
|
+
code: "CONFIRMATION_REQUIRED" /* CONFIRMATION_REQUIRED */,
|
|
8185
|
+
proposed: summary
|
|
8186
|
+
}
|
|
8187
|
+
};
|
|
8188
|
+
ui.onToolCall(toolCallId, toolName, input);
|
|
8189
|
+
ui.onToolResult(
|
|
8190
|
+
toolCallId,
|
|
8191
|
+
toolName,
|
|
8192
|
+
false,
|
|
8193
|
+
declined.data,
|
|
8194
|
+
"Transaction not confirmed",
|
|
8195
|
+
"CONFIRMATION_REQUIRED" /* CONFIRMATION_REQUIRED */
|
|
8196
|
+
);
|
|
8197
|
+
return declined;
|
|
8198
|
+
}
|
|
8199
|
+
}
|
|
8080
8200
|
let promptedPassword;
|
|
8081
8201
|
if (PASSWORD_REQUIRED_TOOLS.has(toolName) && !this.config.password) {
|
|
8082
8202
|
try {
|
|
@@ -8641,20 +8761,35 @@ async function executeAgentAsk(ctx2, message, options) {
|
|
|
8641
8761
|
profile: options.profile ?? process.env.VULTISIG_AGENT_PROFILE ?? ""
|
|
8642
8762
|
};
|
|
8643
8763
|
const session = new AgentSession(vault, config);
|
|
8644
|
-
const ask = new AskInterface(session, !!config.verbose);
|
|
8764
|
+
const ask = new AskInterface(session, !!config.verbose, !!options.autoApprove);
|
|
8645
8765
|
const callbacks = ask.getCallbacks();
|
|
8646
8766
|
await session.initialize(callbacks);
|
|
8647
8767
|
const result = await ask.ask(message);
|
|
8768
|
+
const confirmationRequired = result.toolCalls.some((tc) => tc.code === "CONFIRMATION_REQUIRED" /* CONFIRMATION_REQUIRED */);
|
|
8769
|
+
const proposedCall = result.toolCalls.find(
|
|
8770
|
+
(tc) => tc.code === "CONFIRMATION_REQUIRED" /* CONFIRMATION_REQUIRED */ && typeof tc.data?.proposed === "string"
|
|
8771
|
+
);
|
|
8772
|
+
const proposed = proposedCall?.data?.proposed;
|
|
8648
8773
|
if (options.json || isJsonOutput()) {
|
|
8649
8774
|
outputJson({
|
|
8650
8775
|
session_id: result.sessionId,
|
|
8651
8776
|
response: result.response,
|
|
8652
8777
|
tool_calls: result.toolCalls,
|
|
8653
|
-
transactions: result.transactions
|
|
8778
|
+
transactions: result.transactions,
|
|
8779
|
+
...confirmationRequired ? { confirmation_required: true } : {},
|
|
8780
|
+
...proposed ? { proposed } : {}
|
|
8654
8781
|
});
|
|
8655
8782
|
} else {
|
|
8656
8783
|
process.stdout.write(`session:${result.sessionId}
|
|
8657
8784
|
`);
|
|
8785
|
+
if (confirmationRequired) {
|
|
8786
|
+
process.stdout.write(`confirmation-required:pass --yes to authorize signing
|
|
8787
|
+
`);
|
|
8788
|
+
if (proposed) {
|
|
8789
|
+
process.stdout.write(`proposed:${proposed}
|
|
8790
|
+
`);
|
|
8791
|
+
}
|
|
8792
|
+
}
|
|
8658
8793
|
if (result.response) {
|
|
8659
8794
|
process.stdout.write(`
|
|
8660
8795
|
${result.response}
|
|
@@ -8768,7 +8903,7 @@ var cachedVersion = null;
|
|
|
8768
8903
|
function getVersion() {
|
|
8769
8904
|
if (cachedVersion) return cachedVersion;
|
|
8770
8905
|
if (true) {
|
|
8771
|
-
cachedVersion = "
|
|
8906
|
+
cachedVersion = "2.0.0";
|
|
8772
8907
|
return cachedVersion;
|
|
8773
8908
|
}
|
|
8774
8909
|
try {
|
|
@@ -11488,13 +11623,21 @@ var agentCmd = program.command("agent").description("AI-powered chat interface f
|
|
|
11488
11623
|
});
|
|
11489
11624
|
}
|
|
11490
11625
|
);
|
|
11491
|
-
agentCmd.command("ask <message>").description("Send a single message and get the response (for AI agent integration)").option("--session <id>", "Continue an existing conversation").option("--backend-url <url>", "Agent backend URL (default: https://abe.vultisig.com)").option("--password <password>", "Vault password for signing operations").option("--verbose", "Show tool calls and debug info on stderr").option("--json", "Output structured JSON (deprecated: use --output json)").option("--profile <api_id>", "Billing profile slug sent as X-Vultisig-Abe-Profile header").
|
|
11626
|
+
agentCmd.command("ask <message>").description("Send a single message and get the response (for AI agent integration)").option("--session <id>", "Continue an existing conversation").option("--backend-url <url>", "Agent backend URL (default: https://abe.vultisig.com)").option("--password <password>", "Vault password for signing operations").option("--verbose", "Show tool calls and debug info on stderr").option("--json", "Output structured JSON (deprecated: use --output json)").option("--profile <api_id>", "Billing profile slug sent as X-Vultisig-Abe-Profile header").option(
|
|
11627
|
+
"--yes",
|
|
11628
|
+
"Auto-approve signing/broadcast. Required for unattended signing; default is to NOT broadcast and report the proposed transaction instead."
|
|
11629
|
+
).addHelpText(
|
|
11492
11630
|
"after",
|
|
11493
11631
|
`
|
|
11494
11632
|
Examples:
|
|
11495
11633
|
vultisig agent ask "What is my ETH balance?" --output json
|
|
11496
|
-
vultisig agent ask "Send 0.1 ETH to 0x..." --session abc123
|
|
11497
|
-
vultisig agent ask "..." --profile station-wallet
|
|
11634
|
+
vultisig agent ask "Send 0.1 ETH to 0x..." --session abc123 --yes
|
|
11635
|
+
vultisig agent ask "..." --profile station-wallet
|
|
11636
|
+
|
|
11637
|
+
Signing safety:
|
|
11638
|
+
Without --yes, ask mode never signs or broadcasts \u2014 it reports the proposed
|
|
11639
|
+
transaction so a read-only prompt can't move funds. Pass --yes to opt in to
|
|
11640
|
+
unattended signing.`
|
|
11498
11641
|
).action(
|
|
11499
11642
|
async (message, options) => {
|
|
11500
11643
|
const parentOpts = agentCmd.opts();
|
|
@@ -11504,7 +11647,8 @@ Examples:
|
|
|
11504
11647
|
backendUrl: options.backendUrl || parentOpts.backendUrl,
|
|
11505
11648
|
password: options.password || parentOpts.password,
|
|
11506
11649
|
verbose: options.verbose || parentOpts.verbose,
|
|
11507
|
-
profile: options.profile ?? parentOpts.profile
|
|
11650
|
+
profile: options.profile ?? parentOpts.profile,
|
|
11651
|
+
autoApprove: options.yes
|
|
11508
11652
|
});
|
|
11509
11653
|
}
|
|
11510
11654
|
);
|
|
@@ -11649,8 +11793,3 @@ if (isInteractiveMode) {
|
|
|
11649
11793
|
} else {
|
|
11650
11794
|
program.parse();
|
|
11651
11795
|
}
|
|
11652
|
-
/*! Bundled license information:
|
|
11653
|
-
|
|
11654
|
-
@noble/hashes/esm/utils.js:
|
|
11655
|
-
(*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
11656
|
-
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vultisig/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.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": {
|
|
@@ -67,35 +67,35 @@
|
|
|
67
67
|
},
|
|
68
68
|
"homepage": "https://vultisig.com",
|
|
69
69
|
"dependencies": {
|
|
70
|
-
"@cosmjs/cosmwasm-stargate": "^0.
|
|
70
|
+
"@cosmjs/cosmwasm-stargate": "^0.39.0",
|
|
71
71
|
"@cosmjs/encoding": "^0.39.0",
|
|
72
|
-
"@cosmjs/proto-signing": "^0.
|
|
73
|
-
"@cosmjs/stargate": "^0.
|
|
72
|
+
"@cosmjs/proto-signing": "^0.39.0",
|
|
73
|
+
"@cosmjs/stargate": "^0.39.0",
|
|
74
74
|
"@napi-rs/keyring": "^1.3.0",
|
|
75
|
-
"@noble/hashes": "^2.0
|
|
76
|
-
"@vultisig/client-shared": "^0.2.
|
|
77
|
-
"@vultisig/core-chain": "^2.
|
|
78
|
-
"@vultisig/rujira": "^
|
|
79
|
-
"@vultisig/sdk": "^
|
|
75
|
+
"@noble/hashes": "^2.2.0",
|
|
76
|
+
"@vultisig/client-shared": "^0.2.15",
|
|
77
|
+
"@vultisig/core-chain": "^2.15.0",
|
|
78
|
+
"@vultisig/rujira": "^33.0.0",
|
|
79
|
+
"@vultisig/sdk": "^2.0.0",
|
|
80
80
|
"chalk": "^5.6.2",
|
|
81
81
|
"cli-table3": "^0.6.5",
|
|
82
|
-
"commander": "^
|
|
83
|
-
"dotenv": "^17.
|
|
82
|
+
"commander": "^15.0.0",
|
|
83
|
+
"dotenv": "^17.4.2",
|
|
84
84
|
"ora": "^9.4.0",
|
|
85
85
|
"qrcode-terminal": "^0.12.0",
|
|
86
86
|
"tabtab": "^3.0.2",
|
|
87
|
-
"viem": "^2.
|
|
87
|
+
"viem": "^2.52.2",
|
|
88
88
|
"ws": "^8.21.0"
|
|
89
89
|
},
|
|
90
90
|
"devDependencies": {
|
|
91
91
|
"@types/inquirer": "^9.0.9",
|
|
92
|
-
"@types/node": "^25.
|
|
92
|
+
"@types/node": "^25.9.2",
|
|
93
93
|
"@types/tabtab": "^3.0.4",
|
|
94
94
|
"@types/ws": "^8.18.1",
|
|
95
|
-
"esbuild": "^0.
|
|
96
|
-
"tsx": "^4.22.
|
|
95
|
+
"esbuild": "^0.28.0",
|
|
96
|
+
"tsx": "^4.22.4",
|
|
97
97
|
"typescript": "^6.0.3",
|
|
98
|
-
"vitest": "^4.1.
|
|
98
|
+
"vitest": "^4.1.8"
|
|
99
99
|
},
|
|
100
100
|
"engines": {
|
|
101
101
|
"node": ">=20.0.0"
|