@vultisig/cli 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/index.js +317 -162
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @vultisig/cli
|
|
2
2
|
|
|
3
|
+
## 0.8.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#127](https://github.com/vultisig/vultisig-sdk/pull/127) [`073ca14`](https://github.com/vultisig/vultisig-sdk/commit/073ca141f78fe47af857c70b2f555f50210e4916) Thanks [@RaghavSood](https://github.com/RaghavSood)! - Add agent session management: `vultisig agent sessions list` and `vultisig agent sessions delete <id>`. Display session ID and conversation history when resuming sessions with `--session-id`. Replace `--conversation` flag with `--session-id`.
|
|
8
|
+
|
|
9
|
+
- [#125](https://github.com/vultisig/vultisig-sdk/pull/125) [`7677523`](https://github.com/vultisig/vultisig-sdk/commit/76775232866dccf4e1e85aa0fe0d91c2fd8fdddb) Thanks [@rcoderdev](https://github.com/rcoderdev)! - Use production notification API base path `/notification` (aligned with iOS), extend `PushNotificationService` for web device registration and WebSocket flows, export `computeNotificationVaultId`, add notification mock E2E tests, and ship a `live-web-push-e2e` harness for browser Web Push verification.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies [[`da88c6f`](https://github.com/vultisig/vultisig-sdk/commit/da88c6f06b8d74ccb5642f793e386d85ff6f30b1), [`4b29636`](https://github.com/vultisig/vultisig-sdk/commit/4b29636514edccf0980eddf5e8fffacfcb31c88f), [`7677523`](https://github.com/vultisig/vultisig-sdk/commit/76775232866dccf4e1e85aa0fe0d91c2fd8fdddb)]:
|
|
14
|
+
- @vultisig/sdk@0.8.0
|
|
15
|
+
- @vultisig/rujira@4.0.0
|
|
16
|
+
|
|
3
17
|
## 0.7.0
|
|
4
18
|
|
|
5
19
|
### Minor Changes
|
package/dist/index.js
CHANGED
|
@@ -1434,7 +1434,7 @@ var init_sha3 = __esm({
|
|
|
1434
1434
|
import "dotenv/config";
|
|
1435
1435
|
import { promises as fs3 } from "node:fs";
|
|
1436
1436
|
import { parseKeygenQR, Vultisig as Vultisig7 } from "@vultisig/sdk";
|
|
1437
|
-
import
|
|
1437
|
+
import chalk15 from "chalk";
|
|
1438
1438
|
import { program } from "commander";
|
|
1439
1439
|
import inquirer8 from "inquirer";
|
|
1440
1440
|
|
|
@@ -4097,6 +4097,10 @@ function displayDiscountTier(tierInfo) {
|
|
|
4097
4097
|
printResult("");
|
|
4098
4098
|
}
|
|
4099
4099
|
|
|
4100
|
+
// src/commands/agent.ts
|
|
4101
|
+
import chalk9 from "chalk";
|
|
4102
|
+
import Table from "cli-table3";
|
|
4103
|
+
|
|
4100
4104
|
// src/agent/auth.ts
|
|
4101
4105
|
init_sha3();
|
|
4102
4106
|
import { randomBytes } from "node:crypto";
|
|
@@ -4581,6 +4585,7 @@ var AgentExecutor = class {
|
|
|
4581
4585
|
return;
|
|
4582
4586
|
}
|
|
4583
4587
|
const chain = resolveChainFromTxReady(txReadyData) || Chain9.Ethereum;
|
|
4588
|
+
this.pendingPayloads.clear();
|
|
4584
4589
|
this.pendingPayloads.set("latest", {
|
|
4585
4590
|
payload: { __serverTx: true, ...txReadyData },
|
|
4586
4591
|
coin: { chain, address: "", decimals: 18, ticker: "" },
|
|
@@ -4798,6 +4803,7 @@ var AgentExecutor = class {
|
|
|
4798
4803
|
const amount = parseAmount(amountStr, balance.decimals);
|
|
4799
4804
|
const memo = params.memo;
|
|
4800
4805
|
const payload = await this.vault.prepareSendTx({ coin, receiver: toAddress, amount, memo });
|
|
4806
|
+
this.pendingPayloads.clear();
|
|
4801
4807
|
const payloadId = `tx_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
4802
4808
|
this.pendingPayloads.set(payloadId, { payload, coin, chain, timestamp: Date.now() });
|
|
4803
4809
|
this.pendingPayloads.set("latest", { payload, coin, chain, timestamp: Date.now() });
|
|
@@ -4849,6 +4855,7 @@ var AgentExecutor = class {
|
|
|
4849
4855
|
});
|
|
4850
4856
|
const chain = fromChain;
|
|
4851
4857
|
const payload = swapResult.keysignPayload;
|
|
4858
|
+
this.pendingPayloads.clear();
|
|
4852
4859
|
const payloadId = `swap_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
4853
4860
|
this.pendingPayloads.set(payloadId, { payload, coin: { chain, address: "", decimals: 18, ticker: fromSymbol }, chain, timestamp: Date.now() });
|
|
4854
4861
|
this.pendingPayloads.set("latest", { payload, coin: { chain, address: "", decimals: 18, ticker: fromSymbol }, chain, timestamp: Date.now() });
|
|
@@ -4951,7 +4958,7 @@ var AgentExecutor = class {
|
|
|
4951
4958
|
/**
|
|
4952
4959
|
* Sign and broadcast an SDK-built transaction (keysign payload from local build methods).
|
|
4953
4960
|
*/
|
|
4954
|
-
async signSdkTx(payload, chain,
|
|
4961
|
+
async signSdkTx(payload, chain, _payloadId) {
|
|
4955
4962
|
if (this.vault.isEncrypted && !this.vault.isUnlocked?.()) {
|
|
4956
4963
|
if (this.password) {
|
|
4957
4964
|
await this.vault.unlock?.(this.password);
|
|
@@ -4971,10 +4978,7 @@ var AgentExecutor = class {
|
|
|
4971
4978
|
keysignPayload: payload,
|
|
4972
4979
|
signature
|
|
4973
4980
|
});
|
|
4974
|
-
this.pendingPayloads.
|
|
4975
|
-
if (payloadId !== "latest") {
|
|
4976
|
-
this.pendingPayloads.delete("latest");
|
|
4977
|
-
}
|
|
4981
|
+
this.pendingPayloads.clear();
|
|
4978
4982
|
const explorerUrl = Vultisig6.getTxExplorerUrl(chain, txHash);
|
|
4979
4983
|
return {
|
|
4980
4984
|
tx_hash: txHash,
|
|
@@ -5042,7 +5046,7 @@ var AgentExecutor = class {
|
|
|
5042
5046
|
keysignPayload,
|
|
5043
5047
|
signature
|
|
5044
5048
|
});
|
|
5045
|
-
this.pendingPayloads.
|
|
5049
|
+
this.pendingPayloads.clear();
|
|
5046
5050
|
const explorerUrl = Vultisig6.getTxExplorerUrl(chain, txHash);
|
|
5047
5051
|
return {
|
|
5048
5052
|
tx_hash: txHash,
|
|
@@ -5491,6 +5495,17 @@ var PipeInterface = class {
|
|
|
5491
5495
|
terminal: false
|
|
5492
5496
|
});
|
|
5493
5497
|
this.emit({ type: "ready", vault: vaultName, addresses });
|
|
5498
|
+
const sessionId = this.session.getConversationId();
|
|
5499
|
+
if (sessionId) {
|
|
5500
|
+
this.emit({ type: "session", id: sessionId });
|
|
5501
|
+
}
|
|
5502
|
+
const history = this.session.getHistoryMessages();
|
|
5503
|
+
if (history.length > 0) {
|
|
5504
|
+
this.emit({
|
|
5505
|
+
type: "history",
|
|
5506
|
+
messages: history.filter((m) => m.content_type !== "action_result").map((m) => ({ role: m.role, content: m.content, created_at: m.created_at }))
|
|
5507
|
+
});
|
|
5508
|
+
}
|
|
5494
5509
|
const lines = [];
|
|
5495
5510
|
let inputDone = false;
|
|
5496
5511
|
let processing = false;
|
|
@@ -5633,6 +5648,7 @@ var AgentSession = class {
|
|
|
5633
5648
|
publicKey;
|
|
5634
5649
|
cachedContext = null;
|
|
5635
5650
|
abortController = null;
|
|
5651
|
+
historyMessages = [];
|
|
5636
5652
|
constructor(vault, config) {
|
|
5637
5653
|
this.vault = vault;
|
|
5638
5654
|
this.config = config;
|
|
@@ -5669,8 +5685,26 @@ var AgentSession = class {
|
|
|
5669
5685
|
} catch (err) {
|
|
5670
5686
|
throw new Error(`Authentication failed: ${err.message}`);
|
|
5671
5687
|
}
|
|
5672
|
-
if (this.config.
|
|
5673
|
-
this.conversationId = this.config.
|
|
5688
|
+
if (this.config.sessionId) {
|
|
5689
|
+
this.conversationId = this.config.sessionId;
|
|
5690
|
+
try {
|
|
5691
|
+
const conv = await this.client.getConversation(this.conversationId, this.publicKey);
|
|
5692
|
+
this.historyMessages = conv.messages || [];
|
|
5693
|
+
} catch (err) {
|
|
5694
|
+
if (err.message?.includes("401") || err.message?.includes("403")) {
|
|
5695
|
+
clearCachedToken(this.publicKey);
|
|
5696
|
+
const auth = await authenticateVault(this.client, this.vault, this.config.password);
|
|
5697
|
+
this.client.setAuthToken(auth.token);
|
|
5698
|
+
saveCachedToken(this.publicKey, auth.token, auth.expiresAt);
|
|
5699
|
+
const conv = await this.client.getConversation(this.conversationId, this.publicKey);
|
|
5700
|
+
this.historyMessages = conv.messages || [];
|
|
5701
|
+
} else {
|
|
5702
|
+
this.conversationId = null;
|
|
5703
|
+
this.historyMessages = [];
|
|
5704
|
+
const conv = await this.client.createConversation(this.publicKey);
|
|
5705
|
+
this.conversationId = conv.id;
|
|
5706
|
+
}
|
|
5707
|
+
}
|
|
5674
5708
|
} else {
|
|
5675
5709
|
const conv = await this.client.createConversation(this.publicKey);
|
|
5676
5710
|
this.conversationId = conv.id;
|
|
@@ -5680,6 +5714,9 @@ var AgentSession = class {
|
|
|
5680
5714
|
getConversationId() {
|
|
5681
5715
|
return this.conversationId;
|
|
5682
5716
|
}
|
|
5717
|
+
getHistoryMessages() {
|
|
5718
|
+
return this.historyMessages;
|
|
5719
|
+
}
|
|
5683
5720
|
getVaultAddresses() {
|
|
5684
5721
|
return this.cachedContext?.addresses || {};
|
|
5685
5722
|
}
|
|
@@ -5785,15 +5822,14 @@ var AgentSession = class {
|
|
|
5785
5822
|
} else if (responseText) {
|
|
5786
5823
|
ui.onAssistantMessage(responseText);
|
|
5787
5824
|
}
|
|
5788
|
-
const
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
const results = await this.executeActions(nonSignActions, ui);
|
|
5825
|
+
const actions = streamResult.actions.filter((a) => a.type !== "sign_tx");
|
|
5826
|
+
if (actions.length > 0) {
|
|
5827
|
+
const results = await this.executeActions(actions, ui);
|
|
5792
5828
|
const hasBuildSuccess = results.some(
|
|
5793
5829
|
(r) => r.success && r.action.startsWith("build_")
|
|
5794
5830
|
);
|
|
5795
5831
|
if (hasBuildSuccess && this.executor.hasPendingTransaction()) {
|
|
5796
|
-
if (this.config.verbose) process.stderr.write(`[session] build_* action produced pending tx, auto-
|
|
5832
|
+
if (this.config.verbose) process.stderr.write(`[session] build_* action produced pending tx, auto-signing client-side
|
|
5797
5833
|
`);
|
|
5798
5834
|
const signAction = {
|
|
5799
5835
|
id: `tx_sign_${Date.now()}`,
|
|
@@ -5803,11 +5839,11 @@ var AgentSession = class {
|
|
|
5803
5839
|
auto_execute: true
|
|
5804
5840
|
};
|
|
5805
5841
|
const signResults = await this.executeActions([signAction], ui);
|
|
5806
|
-
const
|
|
5807
|
-
|
|
5808
|
-
await this.processMessageLoop(null, [
|
|
5842
|
+
const signResult = signResults[0];
|
|
5843
|
+
if (signResult) {
|
|
5844
|
+
await this.processMessageLoop(null, [signResult], ui);
|
|
5845
|
+
return;
|
|
5809
5846
|
}
|
|
5810
|
-
return;
|
|
5811
5847
|
}
|
|
5812
5848
|
if (results.length > 0) {
|
|
5813
5849
|
for (const result of results) {
|
|
@@ -5833,27 +5869,6 @@ var AgentSession = class {
|
|
|
5833
5869
|
}
|
|
5834
5870
|
return;
|
|
5835
5871
|
}
|
|
5836
|
-
} else if (backendSignActions.length > 0 && this.executor.hasPendingTransaction()) {
|
|
5837
|
-
if (this.config.verbose) process.stderr.write(`[session] Backend sent sign_tx action, using it
|
|
5838
|
-
`);
|
|
5839
|
-
const results = await this.executeActions(backendSignActions, ui);
|
|
5840
|
-
if (results.length > 0) {
|
|
5841
|
-
for (const result of results) {
|
|
5842
|
-
await this.processMessageLoop(null, [result], ui);
|
|
5843
|
-
}
|
|
5844
|
-
return;
|
|
5845
|
-
}
|
|
5846
|
-
} else if (backendSignActions.length > 0 && !this.executor.hasPendingTransaction()) {
|
|
5847
|
-
if (this.config.verbose) process.stderr.write(`[session] Backend sent sign_tx but no pending tx, reporting error
|
|
5848
|
-
`);
|
|
5849
|
-
const errorResult = {
|
|
5850
|
-
action: "sign_tx",
|
|
5851
|
-
action_id: backendSignActions[0].id,
|
|
5852
|
-
success: false,
|
|
5853
|
-
error: "No pending transaction. The swap transaction data was not received."
|
|
5854
|
-
};
|
|
5855
|
-
await this.processMessageLoop(null, [errorResult], ui);
|
|
5856
|
-
return;
|
|
5857
5872
|
}
|
|
5858
5873
|
ui.onDone();
|
|
5859
5874
|
}
|
|
@@ -5911,6 +5926,7 @@ var AgentSession = class {
|
|
|
5911
5926
|
this.cancel();
|
|
5912
5927
|
this.cachedContext = null;
|
|
5913
5928
|
this.conversationId = null;
|
|
5929
|
+
this.historyMessages = [];
|
|
5914
5930
|
}
|
|
5915
5931
|
};
|
|
5916
5932
|
function parseInlineToolCalls(text) {
|
|
@@ -6021,6 +6037,15 @@ var ChatTUI = class {
|
|
|
6021
6037
|
*/
|
|
6022
6038
|
async start() {
|
|
6023
6039
|
this.printHeader();
|
|
6040
|
+
const sessionId = this.session.getConversationId();
|
|
6041
|
+
if (sessionId) {
|
|
6042
|
+
console.log(chalk8.gray(` Session: ${sessionId}`));
|
|
6043
|
+
console.log("");
|
|
6044
|
+
}
|
|
6045
|
+
const history = this.session.getHistoryMessages();
|
|
6046
|
+
if (history.length > 0) {
|
|
6047
|
+
this.printHistory(history);
|
|
6048
|
+
}
|
|
6024
6049
|
this.printHelp();
|
|
6025
6050
|
this.showPrompt();
|
|
6026
6051
|
this.rl.on("line", async (line) => {
|
|
@@ -6229,6 +6254,30 @@ var ChatTUI = class {
|
|
|
6229
6254
|
console.log(chalk8.bold.cyan(` \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D`));
|
|
6230
6255
|
console.log("");
|
|
6231
6256
|
}
|
|
6257
|
+
printHistory(messages) {
|
|
6258
|
+
console.log(chalk8.gray(" \u2500\u2500 Session History \u2500\u2500"));
|
|
6259
|
+
console.log("");
|
|
6260
|
+
for (const msg of messages) {
|
|
6261
|
+
if (msg.content_type === "action_result") continue;
|
|
6262
|
+
const ts = this.formatHistoryTimestamp(msg.created_at);
|
|
6263
|
+
if (msg.role === "user") {
|
|
6264
|
+
console.log(`${chalk8.gray(ts)} ${chalk8.green.bold("You")}: ${msg.content}`);
|
|
6265
|
+
} else if (msg.role === "assistant") {
|
|
6266
|
+
console.log(`${chalk8.gray(ts)} ${chalk8.cyan.bold("Agent")}: ${renderMarkdown(msg.content)}`);
|
|
6267
|
+
}
|
|
6268
|
+
}
|
|
6269
|
+
console.log("");
|
|
6270
|
+
console.log(chalk8.gray(" \u2500\u2500 End of History \u2500\u2500"));
|
|
6271
|
+
console.log("");
|
|
6272
|
+
}
|
|
6273
|
+
formatHistoryTimestamp(iso) {
|
|
6274
|
+
try {
|
|
6275
|
+
const d = new Date(iso);
|
|
6276
|
+
return `[${d.getHours().toString().padStart(2, "0")}:${d.getMinutes().toString().padStart(2, "0")}:${d.getSeconds().toString().padStart(2, "0")}]`;
|
|
6277
|
+
} catch {
|
|
6278
|
+
return "[--:--:--]";
|
|
6279
|
+
}
|
|
6280
|
+
}
|
|
6232
6281
|
printHelp() {
|
|
6233
6282
|
console.log(chalk8.gray(" Commands: /help, /clear, /quit"));
|
|
6234
6283
|
console.log(chalk8.gray(" Press Ctrl+C to cancel a response, or to exit"));
|
|
@@ -6277,7 +6326,7 @@ async function executeAgent(ctx2, options) {
|
|
|
6277
6326
|
vaultName: vault.name,
|
|
6278
6327
|
password: options.password,
|
|
6279
6328
|
viaAgent: options.viaAgent,
|
|
6280
|
-
|
|
6329
|
+
sessionId: options.sessionId,
|
|
6281
6330
|
verbose: options.verbose
|
|
6282
6331
|
};
|
|
6283
6332
|
const session = new AgentSession(vault, config);
|
|
@@ -6304,6 +6353,79 @@ async function executeAgent(ctx2, options) {
|
|
|
6304
6353
|
}
|
|
6305
6354
|
}
|
|
6306
6355
|
}
|
|
6356
|
+
async function executeAgentSessionsList(ctx2, options) {
|
|
6357
|
+
const vault = await ctx2.ensureActiveVault();
|
|
6358
|
+
const backendUrl = options.backendUrl || process.env.VULTISIG_AGENT_URL || "http://localhost:9998";
|
|
6359
|
+
const client = await createAuthenticatedClient(backendUrl, vault, options.password);
|
|
6360
|
+
const publicKey = vault.publicKeys.ecdsa;
|
|
6361
|
+
const PAGE_SIZE = 100;
|
|
6362
|
+
const allConversations = [];
|
|
6363
|
+
let totalCount = 0;
|
|
6364
|
+
let skip = 0;
|
|
6365
|
+
while (true) {
|
|
6366
|
+
const page = await client.listConversations(publicKey, skip, PAGE_SIZE);
|
|
6367
|
+
totalCount = page.total_count;
|
|
6368
|
+
allConversations.push(...page.conversations);
|
|
6369
|
+
if (allConversations.length >= totalCount || page.conversations.length < PAGE_SIZE) break;
|
|
6370
|
+
skip += PAGE_SIZE;
|
|
6371
|
+
}
|
|
6372
|
+
if (isJsonOutput()) {
|
|
6373
|
+
outputJson({
|
|
6374
|
+
sessions: allConversations.map((c) => ({
|
|
6375
|
+
id: c.id,
|
|
6376
|
+
title: c.title,
|
|
6377
|
+
created_at: c.created_at,
|
|
6378
|
+
updated_at: c.updated_at
|
|
6379
|
+
})),
|
|
6380
|
+
total_count: totalCount
|
|
6381
|
+
});
|
|
6382
|
+
return;
|
|
6383
|
+
}
|
|
6384
|
+
if (allConversations.length === 0) {
|
|
6385
|
+
printResult("No sessions found.");
|
|
6386
|
+
return;
|
|
6387
|
+
}
|
|
6388
|
+
const table = new Table({
|
|
6389
|
+
head: [chalk9.cyan("ID"), chalk9.cyan("Title"), chalk9.cyan("Created"), chalk9.cyan("Updated")]
|
|
6390
|
+
});
|
|
6391
|
+
for (const conv of allConversations) {
|
|
6392
|
+
table.push([
|
|
6393
|
+
conv.id,
|
|
6394
|
+
conv.title || chalk9.gray("(untitled)"),
|
|
6395
|
+
formatDate(conv.created_at),
|
|
6396
|
+
formatDate(conv.updated_at)
|
|
6397
|
+
]);
|
|
6398
|
+
}
|
|
6399
|
+
printResult(table.toString());
|
|
6400
|
+
printResult(chalk9.gray(`
|
|
6401
|
+
${totalCount} session(s) total`));
|
|
6402
|
+
}
|
|
6403
|
+
async function executeAgentSessionsDelete(ctx2, sessionId, options) {
|
|
6404
|
+
const vault = await ctx2.ensureActiveVault();
|
|
6405
|
+
const backendUrl = options.backendUrl || process.env.VULTISIG_AGENT_URL || "http://localhost:9998";
|
|
6406
|
+
const client = await createAuthenticatedClient(backendUrl, vault, options.password);
|
|
6407
|
+
const publicKey = vault.publicKeys.ecdsa;
|
|
6408
|
+
await client.deleteConversation(sessionId, publicKey);
|
|
6409
|
+
if (isJsonOutput()) {
|
|
6410
|
+
outputJson({ deleted: sessionId });
|
|
6411
|
+
return;
|
|
6412
|
+
}
|
|
6413
|
+
printResult(chalk9.green(`Session ${sessionId} deleted.`));
|
|
6414
|
+
}
|
|
6415
|
+
async function createAuthenticatedClient(backendUrl, vault, password) {
|
|
6416
|
+
const client = new AgentClient(backendUrl);
|
|
6417
|
+
const auth = await authenticateVault(client, vault, password);
|
|
6418
|
+
client.setAuthToken(auth.token);
|
|
6419
|
+
return client;
|
|
6420
|
+
}
|
|
6421
|
+
function formatDate(iso) {
|
|
6422
|
+
try {
|
|
6423
|
+
const d = new Date(iso);
|
|
6424
|
+
return d.toLocaleDateString() + " " + d.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
6425
|
+
} catch {
|
|
6426
|
+
return iso;
|
|
6427
|
+
}
|
|
6428
|
+
}
|
|
6307
6429
|
|
|
6308
6430
|
// src/interactive/completer.ts
|
|
6309
6431
|
import { Chain as Chain10 } from "@vultisig/sdk";
|
|
@@ -6465,7 +6587,7 @@ function findChainByName(name) {
|
|
|
6465
6587
|
}
|
|
6466
6588
|
|
|
6467
6589
|
// src/interactive/event-buffer.ts
|
|
6468
|
-
import
|
|
6590
|
+
import chalk10 from "chalk";
|
|
6469
6591
|
var EventBuffer = class {
|
|
6470
6592
|
eventBuffer = [];
|
|
6471
6593
|
isCommandRunning = false;
|
|
@@ -6505,17 +6627,17 @@ var EventBuffer = class {
|
|
|
6505
6627
|
displayEvent(message, type) {
|
|
6506
6628
|
switch (type) {
|
|
6507
6629
|
case "success":
|
|
6508
|
-
console.log(
|
|
6630
|
+
console.log(chalk10.green(message));
|
|
6509
6631
|
break;
|
|
6510
6632
|
case "warning":
|
|
6511
|
-
console.log(
|
|
6633
|
+
console.log(chalk10.yellow(message));
|
|
6512
6634
|
break;
|
|
6513
6635
|
case "error":
|
|
6514
|
-
console.error(
|
|
6636
|
+
console.error(chalk10.red(message));
|
|
6515
6637
|
break;
|
|
6516
6638
|
case "info":
|
|
6517
6639
|
default:
|
|
6518
|
-
console.log(
|
|
6640
|
+
console.log(chalk10.blue(message));
|
|
6519
6641
|
break;
|
|
6520
6642
|
}
|
|
6521
6643
|
}
|
|
@@ -6526,13 +6648,13 @@ var EventBuffer = class {
|
|
|
6526
6648
|
if (this.eventBuffer.length === 0) {
|
|
6527
6649
|
return;
|
|
6528
6650
|
}
|
|
6529
|
-
console.log(
|
|
6651
|
+
console.log(chalk10.gray("\n--- Background Events ---"));
|
|
6530
6652
|
this.eventBuffer.forEach((event) => {
|
|
6531
6653
|
const timeStr = event.timestamp.toLocaleTimeString();
|
|
6532
6654
|
const message = `[${timeStr}] ${event.message}`;
|
|
6533
6655
|
this.displayEvent(message, event.type);
|
|
6534
6656
|
});
|
|
6535
|
-
console.log(
|
|
6657
|
+
console.log(chalk10.gray("--- End Events ---\n"));
|
|
6536
6658
|
}
|
|
6537
6659
|
/**
|
|
6538
6660
|
* Setup all vault event listeners
|
|
@@ -6642,13 +6764,13 @@ var EventBuffer = class {
|
|
|
6642
6764
|
|
|
6643
6765
|
// src/interactive/session.ts
|
|
6644
6766
|
import { fiatCurrencies as fiatCurrencies3 } from "@vultisig/sdk";
|
|
6645
|
-
import
|
|
6767
|
+
import chalk12 from "chalk";
|
|
6646
6768
|
import ora3 from "ora";
|
|
6647
6769
|
import * as readline3 from "readline";
|
|
6648
6770
|
|
|
6649
6771
|
// src/interactive/shell-commands.ts
|
|
6650
|
-
import
|
|
6651
|
-
import
|
|
6772
|
+
import chalk11 from "chalk";
|
|
6773
|
+
import Table2 from "cli-table3";
|
|
6652
6774
|
import inquirer6 from "inquirer";
|
|
6653
6775
|
import ora2 from "ora";
|
|
6654
6776
|
function formatTimeRemaining(ms) {
|
|
@@ -6664,25 +6786,25 @@ function formatTimeRemaining(ms) {
|
|
|
6664
6786
|
async function executeLock(ctx2) {
|
|
6665
6787
|
const vault = ctx2.getActiveVault();
|
|
6666
6788
|
if (!vault) {
|
|
6667
|
-
console.log(
|
|
6668
|
-
console.log(
|
|
6789
|
+
console.log(chalk11.red("No active vault."));
|
|
6790
|
+
console.log(chalk11.yellow('Use "vault <name>" to switch to a vault first.'));
|
|
6669
6791
|
return;
|
|
6670
6792
|
}
|
|
6671
6793
|
ctx2.lockVault(vault.id);
|
|
6672
|
-
console.log(
|
|
6673
|
-
console.log(
|
|
6794
|
+
console.log(chalk11.green("\n+ Vault locked"));
|
|
6795
|
+
console.log(chalk11.gray("Password cache cleared. You will need to enter the password again."));
|
|
6674
6796
|
}
|
|
6675
6797
|
async function executeUnlock(ctx2) {
|
|
6676
6798
|
const vault = ctx2.getActiveVault();
|
|
6677
6799
|
if (!vault) {
|
|
6678
|
-
console.log(
|
|
6679
|
-
console.log(
|
|
6800
|
+
console.log(chalk11.red("No active vault."));
|
|
6801
|
+
console.log(chalk11.yellow('Use "vault <name>" to switch to a vault first.'));
|
|
6680
6802
|
return;
|
|
6681
6803
|
}
|
|
6682
6804
|
if (ctx2.isVaultUnlocked(vault.id)) {
|
|
6683
6805
|
const timeRemaining = ctx2.getUnlockTimeRemaining(vault.id);
|
|
6684
|
-
console.log(
|
|
6685
|
-
console.log(
|
|
6806
|
+
console.log(chalk11.yellow("\nVault is already unlocked."));
|
|
6807
|
+
console.log(chalk11.gray(`Time remaining: ${formatTimeRemaining(timeRemaining)}`));
|
|
6686
6808
|
return;
|
|
6687
6809
|
}
|
|
6688
6810
|
const { password } = await inquirer6.prompt([
|
|
@@ -6699,19 +6821,19 @@ async function executeUnlock(ctx2) {
|
|
|
6699
6821
|
ctx2.cachePassword(vault.id, password);
|
|
6700
6822
|
const timeRemaining = ctx2.getUnlockTimeRemaining(vault.id);
|
|
6701
6823
|
spinner.succeed("Vault unlocked");
|
|
6702
|
-
console.log(
|
|
6824
|
+
console.log(chalk11.green(`
|
|
6703
6825
|
+ Vault unlocked for ${formatTimeRemaining(timeRemaining)}`));
|
|
6704
6826
|
} catch (err) {
|
|
6705
6827
|
spinner.fail("Failed to unlock vault");
|
|
6706
|
-
console.error(
|
|
6828
|
+
console.error(chalk11.red(`
|
|
6707
6829
|
x ${err.message}`));
|
|
6708
6830
|
}
|
|
6709
6831
|
}
|
|
6710
6832
|
async function executeStatus(ctx2) {
|
|
6711
6833
|
const vault = ctx2.getActiveVault();
|
|
6712
6834
|
if (!vault) {
|
|
6713
|
-
console.log(
|
|
6714
|
-
console.log(
|
|
6835
|
+
console.log(chalk11.red("No active vault."));
|
|
6836
|
+
console.log(chalk11.yellow('Use "vault <name>" to switch to a vault first.'));
|
|
6715
6837
|
return;
|
|
6716
6838
|
}
|
|
6717
6839
|
const isUnlocked = ctx2.isVaultUnlocked(vault.id);
|
|
@@ -6742,30 +6864,30 @@ async function executeStatus(ctx2) {
|
|
|
6742
6864
|
displayStatus(status);
|
|
6743
6865
|
}
|
|
6744
6866
|
function displayStatus(status) {
|
|
6745
|
-
console.log(
|
|
6746
|
-
console.log(
|
|
6747
|
-
console.log(
|
|
6748
|
-
console.log(
|
|
6749
|
-
console.log(` Name: ${
|
|
6867
|
+
console.log(chalk11.cyan("\n+----------------------------------------+"));
|
|
6868
|
+
console.log(chalk11.cyan("| Vault Status |"));
|
|
6869
|
+
console.log(chalk11.cyan("+----------------------------------------+\n"));
|
|
6870
|
+
console.log(chalk11.bold("Vault:"));
|
|
6871
|
+
console.log(` Name: ${chalk11.green(status.name)}`);
|
|
6750
6872
|
console.log(` ID: ${status.id}`);
|
|
6751
|
-
console.log(` Type: ${
|
|
6752
|
-
console.log(
|
|
6873
|
+
console.log(` Type: ${chalk11.yellow(status.type)}`);
|
|
6874
|
+
console.log(chalk11.bold("\nSecurity:"));
|
|
6753
6875
|
if (status.isUnlocked) {
|
|
6754
|
-
console.log(` Status: ${
|
|
6876
|
+
console.log(` Status: ${chalk11.green("Unlocked")} ${chalk11.green("\u{1F513}")}`);
|
|
6755
6877
|
console.log(` Expires: ${status.timeRemainingFormatted}`);
|
|
6756
6878
|
} else {
|
|
6757
|
-
console.log(` Status: ${
|
|
6879
|
+
console.log(` Status: ${chalk11.yellow("Locked")} ${chalk11.yellow("\u{1F512}")}`);
|
|
6758
6880
|
}
|
|
6759
|
-
console.log(` Encrypted: ${status.isEncrypted ?
|
|
6760
|
-
console.log(` Backed Up: ${status.isBackedUp ?
|
|
6761
|
-
console.log(
|
|
6881
|
+
console.log(` Encrypted: ${status.isEncrypted ? chalk11.green("Yes") : chalk11.gray("No")}`);
|
|
6882
|
+
console.log(` Backed Up: ${status.isBackedUp ? chalk11.green("Yes") : chalk11.yellow("No")}`);
|
|
6883
|
+
console.log(chalk11.bold("\nMPC Configuration:"));
|
|
6762
6884
|
console.log(` Library: ${status.libType}`);
|
|
6763
|
-
console.log(` Threshold: ${
|
|
6764
|
-
console.log(
|
|
6885
|
+
console.log(` Threshold: ${chalk11.cyan(status.threshold)} of ${chalk11.cyan(status.totalSigners)}`);
|
|
6886
|
+
console.log(chalk11.bold("\nSigning Modes:"));
|
|
6765
6887
|
status.availableSigningModes.forEach((mode) => {
|
|
6766
6888
|
console.log(` - ${mode}`);
|
|
6767
6889
|
});
|
|
6768
|
-
console.log(
|
|
6890
|
+
console.log(chalk11.bold("\nDetails:"));
|
|
6769
6891
|
console.log(` Chains: ${status.chains}`);
|
|
6770
6892
|
console.log(` Currency: ${status.currency.toUpperCase()}`);
|
|
6771
6893
|
console.log(` Created: ${new Date(status.createdAt).toLocaleString()}`);
|
|
@@ -6773,8 +6895,8 @@ function displayStatus(status) {
|
|
|
6773
6895
|
`);
|
|
6774
6896
|
}
|
|
6775
6897
|
function showHelp() {
|
|
6776
|
-
const table = new
|
|
6777
|
-
head: [
|
|
6898
|
+
const table = new Table2({
|
|
6899
|
+
head: [chalk11.bold("Available Commands")],
|
|
6778
6900
|
colWidths: [50],
|
|
6779
6901
|
chars: {
|
|
6780
6902
|
mid: "",
|
|
@@ -6788,7 +6910,7 @@ function showHelp() {
|
|
|
6788
6910
|
}
|
|
6789
6911
|
});
|
|
6790
6912
|
table.push(
|
|
6791
|
-
[
|
|
6913
|
+
[chalk11.bold("Vault Management:")],
|
|
6792
6914
|
[" vaults - List all vaults"],
|
|
6793
6915
|
[" vault <name> - Switch to vault"],
|
|
6794
6916
|
[" import <file> - Import vault from file"],
|
|
@@ -6797,7 +6919,7 @@ function showHelp() {
|
|
|
6797
6919
|
[" info - Show vault details"],
|
|
6798
6920
|
[" export [path] - Export vault to file"],
|
|
6799
6921
|
[""],
|
|
6800
|
-
[
|
|
6922
|
+
[chalk11.bold("Wallet Operations:")],
|
|
6801
6923
|
[" balance [chain] - Show balances"],
|
|
6802
6924
|
[" send <chain> <to> <amount> - Send transaction"],
|
|
6803
6925
|
[" tx-status <chain> <txHash> - Check transaction status"],
|
|
@@ -6806,22 +6928,22 @@ function showHelp() {
|
|
|
6806
6928
|
[" chains [--add/--remove/--add-all] - Manage chains"],
|
|
6807
6929
|
[" tokens <chain> - Manage tokens"],
|
|
6808
6930
|
[""],
|
|
6809
|
-
[
|
|
6931
|
+
[chalk11.bold("Swap Operations:")],
|
|
6810
6932
|
[" swap-chains - List swap-enabled chains"],
|
|
6811
6933
|
[" swap-quote <from> <to> <amount> - Get quote"],
|
|
6812
6934
|
[" swap <from> <to> <amount> - Execute swap"],
|
|
6813
6935
|
[""],
|
|
6814
|
-
[
|
|
6936
|
+
[chalk11.bold("Session Commands (shell only):")],
|
|
6815
6937
|
[" lock - Lock vault"],
|
|
6816
6938
|
[" unlock - Unlock vault"],
|
|
6817
6939
|
[" status - Show vault status"],
|
|
6818
6940
|
[""],
|
|
6819
|
-
[
|
|
6941
|
+
[chalk11.bold("Settings:")],
|
|
6820
6942
|
[" currency [code] - View/set currency"],
|
|
6821
6943
|
[" server - Check server status"],
|
|
6822
6944
|
[" address-book - Manage saved addresses"],
|
|
6823
6945
|
[""],
|
|
6824
|
-
[
|
|
6946
|
+
[chalk11.bold("Help & Navigation:")],
|
|
6825
6947
|
[" help, ? - Show this help"],
|
|
6826
6948
|
[" .clear - Clear screen"],
|
|
6827
6949
|
[" .exit - Exit shell"]
|
|
@@ -6959,12 +7081,12 @@ var ShellSession = class {
|
|
|
6959
7081
|
*/
|
|
6960
7082
|
async start() {
|
|
6961
7083
|
console.clear();
|
|
6962
|
-
console.log(
|
|
6963
|
-
console.log(
|
|
6964
|
-
console.log(
|
|
7084
|
+
console.log(chalk12.cyan.bold("\n=============================================="));
|
|
7085
|
+
console.log(chalk12.cyan.bold(" Vultisig Interactive Shell"));
|
|
7086
|
+
console.log(chalk12.cyan.bold("==============================================\n"));
|
|
6965
7087
|
await this.loadAllVaults();
|
|
6966
7088
|
this.displayVaultList();
|
|
6967
|
-
console.log(
|
|
7089
|
+
console.log(chalk12.gray('Type "help" for available commands, "exit" to quit\n'));
|
|
6968
7090
|
this.promptLoop().catch(() => {
|
|
6969
7091
|
});
|
|
6970
7092
|
}
|
|
@@ -6998,12 +7120,12 @@ var ShellSession = class {
|
|
|
6998
7120
|
const now = Date.now();
|
|
6999
7121
|
if (now - this.lastSigintTime < this.DOUBLE_CTRL_C_TIMEOUT) {
|
|
7000
7122
|
rl.close();
|
|
7001
|
-
console.log(
|
|
7123
|
+
console.log(chalk12.yellow("\nGoodbye!"));
|
|
7002
7124
|
this.ctx.dispose();
|
|
7003
7125
|
process.exit(0);
|
|
7004
7126
|
}
|
|
7005
7127
|
this.lastSigintTime = now;
|
|
7006
|
-
console.log(
|
|
7128
|
+
console.log(chalk12.yellow("\n(Press Ctrl+C again to exit)"));
|
|
7007
7129
|
rl.close();
|
|
7008
7130
|
resolve("");
|
|
7009
7131
|
});
|
|
@@ -7098,7 +7220,7 @@ var ShellSession = class {
|
|
|
7098
7220
|
stopAllSpinners();
|
|
7099
7221
|
process.stdout.write("\x1B[?25h");
|
|
7100
7222
|
process.stdout.write("\r\x1B[K");
|
|
7101
|
-
console.log(
|
|
7223
|
+
console.log(chalk12.yellow("\nCancelling operation..."));
|
|
7102
7224
|
};
|
|
7103
7225
|
const cleanup = () => {
|
|
7104
7226
|
process.removeListener("SIGINT", onSigint);
|
|
@@ -7135,10 +7257,10 @@ var ShellSession = class {
|
|
|
7135
7257
|
stopAllSpinners();
|
|
7136
7258
|
process.stdout.write("\x1B[?25h");
|
|
7137
7259
|
process.stdout.write("\r\x1B[K");
|
|
7138
|
-
console.log(
|
|
7260
|
+
console.log(chalk12.yellow("Operation cancelled"));
|
|
7139
7261
|
return;
|
|
7140
7262
|
}
|
|
7141
|
-
console.error(
|
|
7263
|
+
console.error(chalk12.red(`
|
|
7142
7264
|
Error: ${error2.message}`));
|
|
7143
7265
|
}
|
|
7144
7266
|
}
|
|
@@ -7171,7 +7293,7 @@ Error: ${error2.message}`));
|
|
|
7171
7293
|
break;
|
|
7172
7294
|
case "rename":
|
|
7173
7295
|
if (args.length === 0) {
|
|
7174
|
-
console.log(
|
|
7296
|
+
console.log(chalk12.yellow("Usage: rename <newName>"));
|
|
7175
7297
|
return;
|
|
7176
7298
|
}
|
|
7177
7299
|
await executeRename(this.ctx, args.join(" "));
|
|
@@ -7247,41 +7369,41 @@ Error: ${error2.message}`));
|
|
|
7247
7369
|
// Exit
|
|
7248
7370
|
case "exit":
|
|
7249
7371
|
case "quit":
|
|
7250
|
-
console.log(
|
|
7372
|
+
console.log(chalk12.yellow("\nGoodbye!"));
|
|
7251
7373
|
this.ctx.dispose();
|
|
7252
7374
|
process.exit(0);
|
|
7253
7375
|
break;
|
|
7254
7376
|
// eslint requires break even after process.exit
|
|
7255
7377
|
default:
|
|
7256
|
-
console.log(
|
|
7257
|
-
console.log(
|
|
7378
|
+
console.log(chalk12.yellow(`Unknown command: ${command}`));
|
|
7379
|
+
console.log(chalk12.gray('Type "help" for available commands'));
|
|
7258
7380
|
break;
|
|
7259
7381
|
}
|
|
7260
7382
|
}
|
|
7261
7383
|
// ===== Command Helpers =====
|
|
7262
7384
|
async switchVault(args) {
|
|
7263
7385
|
if (args.length === 0) {
|
|
7264
|
-
console.log(
|
|
7265
|
-
console.log(
|
|
7386
|
+
console.log(chalk12.yellow("Usage: vault <name>"));
|
|
7387
|
+
console.log(chalk12.gray('Run "vaults" to see available vaults'));
|
|
7266
7388
|
return;
|
|
7267
7389
|
}
|
|
7268
7390
|
const vaultName = args.join(" ");
|
|
7269
7391
|
const vault = this.ctx.findVaultByName(vaultName);
|
|
7270
7392
|
if (!vault) {
|
|
7271
|
-
console.log(
|
|
7272
|
-
console.log(
|
|
7393
|
+
console.log(chalk12.red(`Vault not found: ${vaultName}`));
|
|
7394
|
+
console.log(chalk12.gray('Run "vaults" to see available vaults'));
|
|
7273
7395
|
return;
|
|
7274
7396
|
}
|
|
7275
7397
|
await this.ctx.setActiveVault(vault);
|
|
7276
|
-
console.log(
|
|
7398
|
+
console.log(chalk12.green(`
|
|
7277
7399
|
+ Switched to: ${vault.name}`));
|
|
7278
7400
|
const isUnlocked = this.ctx.isVaultUnlocked(vault.id);
|
|
7279
|
-
const status = isUnlocked ?
|
|
7401
|
+
const status = isUnlocked ? chalk12.green("Unlocked") : chalk12.yellow("Locked");
|
|
7280
7402
|
console.log(`Status: ${status}`);
|
|
7281
7403
|
}
|
|
7282
7404
|
async importVault(args) {
|
|
7283
7405
|
if (args.length === 0) {
|
|
7284
|
-
console.log(
|
|
7406
|
+
console.log(chalk12.yellow("Usage: import <file>"));
|
|
7285
7407
|
return;
|
|
7286
7408
|
}
|
|
7287
7409
|
const filePath = args.join(" ");
|
|
@@ -7296,45 +7418,45 @@ Error: ${error2.message}`));
|
|
|
7296
7418
|
async createVault(args) {
|
|
7297
7419
|
const type = args[0]?.toLowerCase();
|
|
7298
7420
|
if (!type || type !== "fast" && type !== "secure") {
|
|
7299
|
-
console.log(
|
|
7300
|
-
console.log(
|
|
7301
|
-
console.log(
|
|
7421
|
+
console.log(chalk12.yellow("Usage: create <fast|secure>"));
|
|
7422
|
+
console.log(chalk12.gray(" create fast - Create a fast vault (server-assisted 2-of-2)"));
|
|
7423
|
+
console.log(chalk12.gray(" create secure - Create a secure vault (multi-device MPC)"));
|
|
7302
7424
|
return;
|
|
7303
7425
|
}
|
|
7304
7426
|
let vault;
|
|
7305
7427
|
if (type === "fast") {
|
|
7306
7428
|
const name = await this.prompt("Vault name");
|
|
7307
7429
|
if (!name) {
|
|
7308
|
-
console.log(
|
|
7430
|
+
console.log(chalk12.red("Name is required"));
|
|
7309
7431
|
return;
|
|
7310
7432
|
}
|
|
7311
7433
|
const password = await this.promptPassword("Vault password");
|
|
7312
7434
|
if (!password) {
|
|
7313
|
-
console.log(
|
|
7435
|
+
console.log(chalk12.red("Password is required"));
|
|
7314
7436
|
return;
|
|
7315
7437
|
}
|
|
7316
7438
|
const email = await this.prompt("Email for verification");
|
|
7317
7439
|
if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
|
7318
|
-
console.log(
|
|
7440
|
+
console.log(chalk12.red("Valid email is required"));
|
|
7319
7441
|
return;
|
|
7320
7442
|
}
|
|
7321
7443
|
vault = await this.withCancellation((signal) => executeCreateFast(this.ctx, { name, password, email, signal }));
|
|
7322
7444
|
} else {
|
|
7323
7445
|
const name = await this.prompt("Vault name");
|
|
7324
7446
|
if (!name) {
|
|
7325
|
-
console.log(
|
|
7447
|
+
console.log(chalk12.red("Name is required"));
|
|
7326
7448
|
return;
|
|
7327
7449
|
}
|
|
7328
7450
|
const sharesStr = await this.prompt("Total shares (devices)", "3");
|
|
7329
7451
|
const shares = parseInt(sharesStr, 10);
|
|
7330
7452
|
if (isNaN(shares) || shares < 2) {
|
|
7331
|
-
console.log(
|
|
7453
|
+
console.log(chalk12.red("Must have at least 2 shares"));
|
|
7332
7454
|
return;
|
|
7333
7455
|
}
|
|
7334
7456
|
const thresholdStr = await this.prompt("Signing threshold", "2");
|
|
7335
7457
|
const threshold = parseInt(thresholdStr, 10);
|
|
7336
7458
|
if (isNaN(threshold) || threshold < 1 || threshold > shares) {
|
|
7337
|
-
console.log(
|
|
7459
|
+
console.log(chalk12.red(`Threshold must be between 1 and ${shares}`));
|
|
7338
7460
|
return;
|
|
7339
7461
|
}
|
|
7340
7462
|
const password = await this.promptPassword("Vault password (optional, press Enter to skip)");
|
|
@@ -7356,37 +7478,37 @@ Error: ${error2.message}`));
|
|
|
7356
7478
|
async importSeedphrase(args) {
|
|
7357
7479
|
const type = args[0]?.toLowerCase();
|
|
7358
7480
|
if (!type || type !== "fast" && type !== "secure") {
|
|
7359
|
-
console.log(
|
|
7360
|
-
console.log(
|
|
7361
|
-
console.log(
|
|
7481
|
+
console.log(chalk12.cyan("Usage: create-from-seedphrase <fast|secure>"));
|
|
7482
|
+
console.log(chalk12.gray(" fast - Import with VultiServer (2-of-2)"));
|
|
7483
|
+
console.log(chalk12.gray(" secure - Import with device coordination (N-of-M)"));
|
|
7362
7484
|
return;
|
|
7363
7485
|
}
|
|
7364
|
-
console.log(
|
|
7486
|
+
console.log(chalk12.cyan("\nEnter your recovery phrase (words separated by spaces):"));
|
|
7365
7487
|
const mnemonic = await this.promptPassword("Seedphrase");
|
|
7366
7488
|
const validation = await this.ctx.sdk.validateSeedphrase(mnemonic);
|
|
7367
7489
|
if (!validation.valid) {
|
|
7368
|
-
console.log(
|
|
7490
|
+
console.log(chalk12.red(`Invalid seedphrase: ${validation.error}`));
|
|
7369
7491
|
if (validation.invalidWords?.length) {
|
|
7370
|
-
console.log(
|
|
7492
|
+
console.log(chalk12.yellow(`Invalid words: ${validation.invalidWords.join(", ")}`));
|
|
7371
7493
|
}
|
|
7372
7494
|
return;
|
|
7373
7495
|
}
|
|
7374
|
-
console.log(
|
|
7496
|
+
console.log(chalk12.green(`\u2713 Valid ${validation.wordCount}-word seedphrase`));
|
|
7375
7497
|
let vault;
|
|
7376
7498
|
if (type === "fast") {
|
|
7377
7499
|
const name = await this.prompt("Vault name");
|
|
7378
7500
|
if (!name) {
|
|
7379
|
-
console.log(
|
|
7501
|
+
console.log(chalk12.red("Name is required"));
|
|
7380
7502
|
return;
|
|
7381
7503
|
}
|
|
7382
7504
|
const password = await this.promptPassword("Vault password");
|
|
7383
7505
|
if (!password) {
|
|
7384
|
-
console.log(
|
|
7506
|
+
console.log(chalk12.red("Password is required"));
|
|
7385
7507
|
return;
|
|
7386
7508
|
}
|
|
7387
7509
|
const email = await this.prompt("Email for verification");
|
|
7388
7510
|
if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
|
7389
|
-
console.log(
|
|
7511
|
+
console.log(chalk12.red("Valid email is required"));
|
|
7390
7512
|
return;
|
|
7391
7513
|
}
|
|
7392
7514
|
const discoverStr = await this.prompt("Discover chains with balances? (y/n)", "y");
|
|
@@ -7404,19 +7526,19 @@ Error: ${error2.message}`));
|
|
|
7404
7526
|
} else {
|
|
7405
7527
|
const name = await this.prompt("Vault name");
|
|
7406
7528
|
if (!name) {
|
|
7407
|
-
console.log(
|
|
7529
|
+
console.log(chalk12.red("Name is required"));
|
|
7408
7530
|
return;
|
|
7409
7531
|
}
|
|
7410
7532
|
const sharesStr = await this.prompt("Total shares (devices)", "3");
|
|
7411
7533
|
const shares = parseInt(sharesStr, 10);
|
|
7412
7534
|
if (isNaN(shares) || shares < 2) {
|
|
7413
|
-
console.log(
|
|
7535
|
+
console.log(chalk12.red("Must have at least 2 shares"));
|
|
7414
7536
|
return;
|
|
7415
7537
|
}
|
|
7416
7538
|
const thresholdStr = await this.prompt("Signing threshold", "2");
|
|
7417
7539
|
const threshold = parseInt(thresholdStr, 10);
|
|
7418
7540
|
if (isNaN(threshold) || threshold < 1 || threshold > shares) {
|
|
7419
|
-
console.log(
|
|
7541
|
+
console.log(chalk12.red(`Threshold must be between 1 and ${shares}`));
|
|
7420
7542
|
return;
|
|
7421
7543
|
}
|
|
7422
7544
|
const password = await this.promptPassword("Vault password (optional, Enter to skip)");
|
|
@@ -7460,8 +7582,8 @@ Error: ${error2.message}`));
|
|
|
7460
7582
|
}
|
|
7461
7583
|
}
|
|
7462
7584
|
if (!fiatCurrencies3.includes(currency)) {
|
|
7463
|
-
console.log(
|
|
7464
|
-
console.log(
|
|
7585
|
+
console.log(chalk12.red(`Invalid currency: ${currency}`));
|
|
7586
|
+
console.log(chalk12.yellow(`Supported currencies: ${fiatCurrencies3.join(", ")}`));
|
|
7465
7587
|
return;
|
|
7466
7588
|
}
|
|
7467
7589
|
const raw = args.includes("--raw");
|
|
@@ -7469,7 +7591,7 @@ Error: ${error2.message}`));
|
|
|
7469
7591
|
}
|
|
7470
7592
|
async runSend(args) {
|
|
7471
7593
|
if (args.length < 3) {
|
|
7472
|
-
console.log(
|
|
7594
|
+
console.log(chalk12.yellow("Usage: send <chain> <to> <amount> [--token <tokenId>] [--memo <memo>]"));
|
|
7473
7595
|
return;
|
|
7474
7596
|
}
|
|
7475
7597
|
const [chainStr, to, amount, ...rest] = args;
|
|
@@ -7489,7 +7611,7 @@ Error: ${error2.message}`));
|
|
|
7489
7611
|
await this.withAbortHandler((signal) => executeSend(this.ctx, { chain, to, amount, tokenId, memo, signal }));
|
|
7490
7612
|
} catch (err) {
|
|
7491
7613
|
if (err.message === "Transaction cancelled by user" || err.message === "Operation cancelled" || err.message === "Operation aborted") {
|
|
7492
|
-
console.log(
|
|
7614
|
+
console.log(chalk12.yellow("\nTransaction cancelled"));
|
|
7493
7615
|
return;
|
|
7494
7616
|
}
|
|
7495
7617
|
throw err;
|
|
@@ -7497,7 +7619,7 @@ Error: ${error2.message}`));
|
|
|
7497
7619
|
}
|
|
7498
7620
|
async runTxStatus(args) {
|
|
7499
7621
|
if (args.length < 2) {
|
|
7500
|
-
console.log(
|
|
7622
|
+
console.log(chalk12.yellow("Usage: tx-status <chain> <txHash> [--no-wait]"));
|
|
7501
7623
|
return;
|
|
7502
7624
|
}
|
|
7503
7625
|
const [chainStr, txHash, ...rest] = args;
|
|
@@ -7515,8 +7637,8 @@ Error: ${error2.message}`));
|
|
|
7515
7637
|
} else if (args[i] === "--add" && i + 1 < args.length) {
|
|
7516
7638
|
const chain = findChainByName(args[i + 1]);
|
|
7517
7639
|
if (!chain) {
|
|
7518
|
-
console.log(
|
|
7519
|
-
console.log(
|
|
7640
|
+
console.log(chalk12.red(`Unknown chain: ${args[i + 1]}`));
|
|
7641
|
+
console.log(chalk12.gray("Use tab completion to see available chains"));
|
|
7520
7642
|
return;
|
|
7521
7643
|
}
|
|
7522
7644
|
addChain = chain;
|
|
@@ -7524,8 +7646,8 @@ Error: ${error2.message}`));
|
|
|
7524
7646
|
} else if (args[i] === "--remove" && i + 1 < args.length) {
|
|
7525
7647
|
const chain = findChainByName(args[i + 1]);
|
|
7526
7648
|
if (!chain) {
|
|
7527
|
-
console.log(
|
|
7528
|
-
console.log(
|
|
7649
|
+
console.log(chalk12.red(`Unknown chain: ${args[i + 1]}`));
|
|
7650
|
+
console.log(chalk12.gray("Use tab completion to see available chains"));
|
|
7529
7651
|
return;
|
|
7530
7652
|
}
|
|
7531
7653
|
removeChain = chain;
|
|
@@ -7536,7 +7658,7 @@ Error: ${error2.message}`));
|
|
|
7536
7658
|
}
|
|
7537
7659
|
async runTokens(args) {
|
|
7538
7660
|
if (args.length === 0) {
|
|
7539
|
-
console.log(
|
|
7661
|
+
console.log(chalk12.yellow("Usage: tokens <chain> [--add <address>] [--remove <tokenId>]"));
|
|
7540
7662
|
return;
|
|
7541
7663
|
}
|
|
7542
7664
|
const chainStr = args[0];
|
|
@@ -7557,7 +7679,7 @@ Error: ${error2.message}`));
|
|
|
7557
7679
|
async runSwapQuote(args) {
|
|
7558
7680
|
if (args.length < 3) {
|
|
7559
7681
|
console.log(
|
|
7560
|
-
|
|
7682
|
+
chalk12.yellow("Usage: swap-quote <fromChain> <toChain> <amount> [--from-token <addr>] [--to-token <addr>]")
|
|
7561
7683
|
);
|
|
7562
7684
|
return;
|
|
7563
7685
|
}
|
|
@@ -7581,7 +7703,7 @@ Error: ${error2.message}`));
|
|
|
7581
7703
|
async runSwap(args) {
|
|
7582
7704
|
if (args.length < 3) {
|
|
7583
7705
|
console.log(
|
|
7584
|
-
|
|
7706
|
+
chalk12.yellow(
|
|
7585
7707
|
"Usage: swap <fromChain> <toChain> <amount> [--from-token <addr>] [--to-token <addr>] [--slippage <pct>]"
|
|
7586
7708
|
)
|
|
7587
7709
|
);
|
|
@@ -7612,7 +7734,7 @@ Error: ${error2.message}`));
|
|
|
7612
7734
|
);
|
|
7613
7735
|
} catch (err) {
|
|
7614
7736
|
if (err.message === "Swap cancelled by user" || err.message === "Operation cancelled" || err.message === "Operation aborted") {
|
|
7615
|
-
console.log(
|
|
7737
|
+
console.log(chalk12.yellow("\nSwap cancelled"));
|
|
7616
7738
|
return;
|
|
7617
7739
|
}
|
|
7618
7740
|
throw err;
|
|
@@ -7674,24 +7796,24 @@ Error: ${error2.message}`));
|
|
|
7674
7796
|
}
|
|
7675
7797
|
getPrompt() {
|
|
7676
7798
|
const vault = this.ctx.getActiveVault();
|
|
7677
|
-
if (!vault) return
|
|
7799
|
+
if (!vault) return chalk12.cyan("wallet> ");
|
|
7678
7800
|
const isUnlocked = this.ctx.isVaultUnlocked(vault.id);
|
|
7679
|
-
const status = isUnlocked ?
|
|
7680
|
-
return
|
|
7801
|
+
const status = isUnlocked ? chalk12.green("\u{1F513}") : chalk12.yellow("\u{1F512}");
|
|
7802
|
+
return chalk12.cyan(`wallet[${vault.name}]${status}> `);
|
|
7681
7803
|
}
|
|
7682
7804
|
displayVaultList() {
|
|
7683
7805
|
const vaults = Array.from(this.ctx.getVaults().values());
|
|
7684
7806
|
const activeVault = this.ctx.getActiveVault();
|
|
7685
7807
|
if (vaults.length === 0) {
|
|
7686
|
-
console.log(
|
|
7808
|
+
console.log(chalk12.yellow('No vaults found. Use "create" or "import <file>" to add a vault.\n'));
|
|
7687
7809
|
return;
|
|
7688
7810
|
}
|
|
7689
|
-
console.log(
|
|
7811
|
+
console.log(chalk12.cyan("Loaded Vaults:\n"));
|
|
7690
7812
|
vaults.forEach((vault) => {
|
|
7691
7813
|
const isActive = vault.id === activeVault?.id;
|
|
7692
7814
|
const isUnlocked = this.ctx.isVaultUnlocked(vault.id);
|
|
7693
|
-
const activeMarker = isActive ?
|
|
7694
|
-
const lockIcon = isUnlocked ?
|
|
7815
|
+
const activeMarker = isActive ? chalk12.green(" (active)") : "";
|
|
7816
|
+
const lockIcon = isUnlocked ? chalk12.green("\u{1F513}") : chalk12.yellow("\u{1F512}");
|
|
7695
7817
|
console.log(` ${lockIcon} ${vault.name}${activeMarker} - ${vault.type}`);
|
|
7696
7818
|
});
|
|
7697
7819
|
console.log();
|
|
@@ -7699,10 +7821,10 @@ Error: ${error2.message}`));
|
|
|
7699
7821
|
};
|
|
7700
7822
|
|
|
7701
7823
|
// src/lib/errors.ts
|
|
7702
|
-
import
|
|
7824
|
+
import chalk13 from "chalk";
|
|
7703
7825
|
|
|
7704
7826
|
// src/lib/version.ts
|
|
7705
|
-
import
|
|
7827
|
+
import chalk14 from "chalk";
|
|
7706
7828
|
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync2 } from "fs";
|
|
7707
7829
|
import { homedir as homedir2 } from "os";
|
|
7708
7830
|
import { join as join2 } from "path";
|
|
@@ -7710,7 +7832,7 @@ var cachedVersion = null;
|
|
|
7710
7832
|
function getVersion() {
|
|
7711
7833
|
if (cachedVersion) return cachedVersion;
|
|
7712
7834
|
if (true) {
|
|
7713
|
-
cachedVersion = "0.
|
|
7835
|
+
cachedVersion = "0.8.0";
|
|
7714
7836
|
return cachedVersion;
|
|
7715
7837
|
}
|
|
7716
7838
|
try {
|
|
@@ -7807,7 +7929,7 @@ function formatVersionShort() {
|
|
|
7807
7929
|
}
|
|
7808
7930
|
function formatVersionDetailed() {
|
|
7809
7931
|
const lines = [];
|
|
7810
|
-
lines.push(
|
|
7932
|
+
lines.push(chalk14.bold(`Vultisig CLI v${getVersion()}`));
|
|
7811
7933
|
lines.push("");
|
|
7812
7934
|
lines.push(` Node.js: ${process.version}`);
|
|
7813
7935
|
lines.push(` Platform: ${process.platform}-${process.arch}`);
|
|
@@ -8197,14 +8319,15 @@ async function findVaultByNameOrId(sdk, nameOrId) {
|
|
|
8197
8319
|
if (byPartialId) return byPartialId;
|
|
8198
8320
|
return null;
|
|
8199
8321
|
}
|
|
8200
|
-
async function init(vaultOverride, unlockPassword) {
|
|
8322
|
+
async function init(vaultOverride, unlockPassword, passwordTTL) {
|
|
8201
8323
|
if (!ctx) {
|
|
8202
8324
|
const vaultSelector = vaultOverride || process.env.VULTISIG_VAULT;
|
|
8203
8325
|
if (unlockPassword && vaultSelector) {
|
|
8204
8326
|
cachePassword(vaultSelector, unlockPassword);
|
|
8205
8327
|
}
|
|
8206
8328
|
const sdk = new Vultisig7({
|
|
8207
|
-
onPasswordRequired: createPasswordCallback()
|
|
8329
|
+
onPasswordRequired: createPasswordCallback(),
|
|
8330
|
+
...passwordTTL !== void 0 ? { passwordCache: { defaultTTL: passwordTTL } } : {}
|
|
8208
8331
|
});
|
|
8209
8332
|
await sdk.initialize();
|
|
8210
8333
|
ctx = new CLIContext(sdk);
|
|
@@ -8712,24 +8835,56 @@ rujiraCmd.command("withdraw <asset> <amount> <l1Address>").description("Withdraw
|
|
|
8712
8835
|
}
|
|
8713
8836
|
)
|
|
8714
8837
|
);
|
|
8715
|
-
program.command("agent").description("AI-powered chat interface for wallet operations").option("--via-agent", "Use NDJSON pipe mode for agent-to-agent communication").option("--verbose", "Show detailed tool call parameters and debug output").option("--backend-url <url>", "Agent backend URL (default: http://localhost:9998)").option("--password <password>", "Vault password for signing operations").option("--
|
|
8716
|
-
const
|
|
8838
|
+
var agentCmd = program.command("agent").description("AI-powered chat interface for wallet operations").option("--via-agent", "Use NDJSON pipe mode for agent-to-agent communication").option("--verbose", "Show detailed tool call parameters and debug output").option("--backend-url <url>", "Agent backend URL (default: http://localhost:9998)").option("--password <password>", "Vault password for signing operations").option("--password-ttl <ms>", "Password cache TTL in milliseconds (default: 300000, 86400000/24h for --via-agent)").option("--session-id <id>", "Resume an existing session").action(async (options) => {
|
|
8839
|
+
const MAX_TTL = 864e5;
|
|
8840
|
+
let passwordTTL;
|
|
8841
|
+
if (options.passwordTtl) {
|
|
8842
|
+
const parsed = parseInt(options.passwordTtl, 10);
|
|
8843
|
+
if (Number.isNaN(parsed) || parsed < 0) {
|
|
8844
|
+
throw new Error(`Invalid --password-ttl value: "${options.passwordTtl}". Expected a non-negative integer in milliseconds.`);
|
|
8845
|
+
}
|
|
8846
|
+
passwordTTL = parsed;
|
|
8847
|
+
} else if (options.viaAgent) {
|
|
8848
|
+
passwordTTL = MAX_TTL;
|
|
8849
|
+
}
|
|
8850
|
+
const context = await init(program.opts().vault, options.password, passwordTTL);
|
|
8717
8851
|
await executeAgent(context, {
|
|
8718
8852
|
viaAgent: options.viaAgent,
|
|
8719
8853
|
verbose: options.verbose,
|
|
8720
8854
|
backendUrl: options.backendUrl,
|
|
8721
8855
|
password: options.password,
|
|
8722
|
-
|
|
8856
|
+
sessionId: options.sessionId
|
|
8723
8857
|
});
|
|
8724
8858
|
});
|
|
8859
|
+
var sessionsCmd = agentCmd.command("sessions").description("Manage agent chat sessions");
|
|
8860
|
+
sessionsCmd.command("list").description("List chat sessions for the current vault").option("--backend-url <url>", "Agent backend URL (default: http://localhost:9998)").option("--password <password>", "Vault password for authentication").action(
|
|
8861
|
+
withExit(async (options) => {
|
|
8862
|
+
const parentOpts = agentCmd.opts();
|
|
8863
|
+
const context = await init(program.opts().vault, options.password || parentOpts.password);
|
|
8864
|
+
await executeAgentSessionsList(context, {
|
|
8865
|
+
backendUrl: options.backendUrl || parentOpts.backendUrl,
|
|
8866
|
+
password: options.password || parentOpts.password
|
|
8867
|
+
});
|
|
8868
|
+
})
|
|
8869
|
+
);
|
|
8870
|
+
sessionsCmd.command("delete <id>").description("Delete a chat session").option("--backend-url <url>", "Agent backend URL (default: http://localhost:9998)").option("--password <password>", "Vault password for authentication").action(
|
|
8871
|
+
withExit(async (id, options) => {
|
|
8872
|
+
const parentOpts = agentCmd.opts();
|
|
8873
|
+
const context = await init(program.opts().vault, options.password || parentOpts.password);
|
|
8874
|
+
await executeAgentSessionsDelete(context, id, {
|
|
8875
|
+
backendUrl: options.backendUrl || parentOpts.backendUrl,
|
|
8876
|
+
password: options.password || parentOpts.password
|
|
8877
|
+
});
|
|
8878
|
+
})
|
|
8879
|
+
);
|
|
8725
8880
|
program.command("version").description("Show detailed version information").action(
|
|
8726
8881
|
withExit(async () => {
|
|
8727
8882
|
printResult(formatVersionDetailed());
|
|
8728
8883
|
const result = await checkForUpdates();
|
|
8729
8884
|
if (result?.updateAvailable && result.latestVersion) {
|
|
8730
8885
|
info("");
|
|
8731
|
-
info(
|
|
8732
|
-
info(
|
|
8886
|
+
info(chalk15.yellow(`Update available: ${result.currentVersion} -> ${result.latestVersion}`));
|
|
8887
|
+
info(chalk15.gray(`Run "${getUpdateCommand()}" to update`));
|
|
8733
8888
|
}
|
|
8734
8889
|
})
|
|
8735
8890
|
);
|
|
@@ -8738,22 +8893,22 @@ program.command("update").description("Check for updates and show update command
|
|
|
8738
8893
|
info("Checking for updates...");
|
|
8739
8894
|
const result = await checkForUpdates();
|
|
8740
8895
|
if (!result) {
|
|
8741
|
-
printResult(
|
|
8896
|
+
printResult(chalk15.gray("Update checking is disabled"));
|
|
8742
8897
|
return;
|
|
8743
8898
|
}
|
|
8744
8899
|
if (result.updateAvailable && result.latestVersion) {
|
|
8745
8900
|
printResult("");
|
|
8746
|
-
printResult(
|
|
8901
|
+
printResult(chalk15.green(`Update available: ${result.currentVersion} -> ${result.latestVersion}`));
|
|
8747
8902
|
printResult("");
|
|
8748
8903
|
if (options.check) {
|
|
8749
8904
|
printResult(`Run "${getUpdateCommand()}" to update`);
|
|
8750
8905
|
} else {
|
|
8751
8906
|
const updateCmd = getUpdateCommand();
|
|
8752
8907
|
printResult(`To update, run:`);
|
|
8753
|
-
printResult(
|
|
8908
|
+
printResult(chalk15.cyan(` ${updateCmd}`));
|
|
8754
8909
|
}
|
|
8755
8910
|
} else {
|
|
8756
|
-
printResult(
|
|
8911
|
+
printResult(chalk15.green(`You're on the latest version (${result.currentVersion})`));
|
|
8757
8912
|
}
|
|
8758
8913
|
})
|
|
8759
8914
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vultisig/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Command-line wallet for Vultisig - multi-chain MPC wallet management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -53,8 +53,8 @@
|
|
|
53
53
|
"@cosmjs/proto-signing": "^0.38.1",
|
|
54
54
|
"@cosmjs/stargate": "^0.38.1",
|
|
55
55
|
"@noble/hashes": "^2.0.1",
|
|
56
|
-
"@vultisig/rujira": "^
|
|
57
|
-
"@vultisig/sdk": "^0.
|
|
56
|
+
"@vultisig/rujira": "^4.0.0",
|
|
57
|
+
"@vultisig/sdk": "^0.8.0",
|
|
58
58
|
"chalk": "^5.6.2",
|
|
59
59
|
"cli-table3": "^0.6.5",
|
|
60
60
|
"commander": "^14.0.3",
|