@ritkey/cli 0.1.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/LICENSE +21 -0
- package/dist/index.js +600 -0
- package/dist/index.js.map +1 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 mmorgsmorgan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,600 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
|
|
6
|
+
// src/commands/login.ts
|
|
7
|
+
import { promises as fs2 } from "fs";
|
|
8
|
+
|
|
9
|
+
// src/config.ts
|
|
10
|
+
import { promises as fs } from "fs";
|
|
11
|
+
import path from "path";
|
|
12
|
+
import os from "os";
|
|
13
|
+
var DEFAULT_BASE_URL = "http://localhost:3000";
|
|
14
|
+
function configFilePath() {
|
|
15
|
+
return path.join(os.homedir(), ".ritkey", "config.json");
|
|
16
|
+
}
|
|
17
|
+
async function readConfigFile() {
|
|
18
|
+
try {
|
|
19
|
+
const raw = await fs.readFile(configFilePath(), "utf8");
|
|
20
|
+
return JSON.parse(raw);
|
|
21
|
+
} catch (err) {
|
|
22
|
+
if (err.code === "ENOENT") return null;
|
|
23
|
+
throw err;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async function writeConfigFile(cfg) {
|
|
27
|
+
const p = configFilePath();
|
|
28
|
+
await fs.mkdir(path.dirname(p), { recursive: true });
|
|
29
|
+
await fs.writeFile(p, JSON.stringify(cfg, null, 2) + "\n", { mode: 384 });
|
|
30
|
+
}
|
|
31
|
+
async function resolveConfig(opts) {
|
|
32
|
+
if (opts.apiUrl || opts.apiKey) {
|
|
33
|
+
return {
|
|
34
|
+
baseUrl: opts.apiUrl ?? process.env.RITKEY_API_URL ?? DEFAULT_BASE_URL,
|
|
35
|
+
apiKey: opts.apiKey ?? process.env.RITKEY_API_KEY,
|
|
36
|
+
source: "flags"
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
if (process.env.RITKEY_API_URL || process.env.RITKEY_API_KEY) {
|
|
40
|
+
return {
|
|
41
|
+
baseUrl: process.env.RITKEY_API_URL ?? DEFAULT_BASE_URL,
|
|
42
|
+
apiKey: process.env.RITKEY_API_KEY,
|
|
43
|
+
source: "env"
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const file = await readConfigFile();
|
|
47
|
+
if (file?.baseUrl || file?.apiKey) {
|
|
48
|
+
return {
|
|
49
|
+
baseUrl: file.baseUrl ?? DEFAULT_BASE_URL,
|
|
50
|
+
apiKey: file.apiKey,
|
|
51
|
+
source: "file"
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
baseUrl: DEFAULT_BASE_URL,
|
|
56
|
+
source: "default"
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// src/output.ts
|
|
61
|
+
var isColorOn = process.stdout.isTTY === true && process.env.NO_COLOR !== "1";
|
|
62
|
+
function paint(code, s) {
|
|
63
|
+
return isColorOn ? `\x1B[${code}m${s}\x1B[0m` : s;
|
|
64
|
+
}
|
|
65
|
+
var c = {
|
|
66
|
+
dim: (s) => paint("2", s),
|
|
67
|
+
bold: (s) => paint("1", s),
|
|
68
|
+
red: (s) => paint("31", s),
|
|
69
|
+
green: (s) => paint("32", s),
|
|
70
|
+
yellow: (s) => paint("33", s),
|
|
71
|
+
blue: (s) => paint("34", s),
|
|
72
|
+
cyan: (s) => paint("36", s),
|
|
73
|
+
magenta: (s) => paint("35", s)
|
|
74
|
+
};
|
|
75
|
+
function table(rows, opts) {
|
|
76
|
+
const headers = opts?.headers ?? [];
|
|
77
|
+
const data = headers.length ? [headers, ...rows] : rows;
|
|
78
|
+
const stringified = data.map((r) => r.map((v) => v == null ? "" : String(v)));
|
|
79
|
+
const widths = [];
|
|
80
|
+
for (const row of stringified) {
|
|
81
|
+
for (let i = 0; i < row.length; i++) {
|
|
82
|
+
const cell = row[i] ?? "";
|
|
83
|
+
if (!widths[i] || cell.length > widths[i]) widths[i] = cell.length;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const lines = [];
|
|
87
|
+
for (let r = 0; r < stringified.length; r++) {
|
|
88
|
+
const row = stringified[r];
|
|
89
|
+
const padded = row.map((cell, i) => (cell ?? "").padEnd(widths[i] ?? 0));
|
|
90
|
+
const line = padded.join(" ");
|
|
91
|
+
if (headers.length && r === 0) {
|
|
92
|
+
lines.push(c.bold(line));
|
|
93
|
+
lines.push(c.dim(widths.map((w) => "-".repeat(w)).join(" ")));
|
|
94
|
+
} else {
|
|
95
|
+
lines.push(line);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return lines.join("\n");
|
|
99
|
+
}
|
|
100
|
+
function short(s, head = 8, tail = 6) {
|
|
101
|
+
if (!s) return c.dim("\u2014");
|
|
102
|
+
if (s.length <= head + tail + 1) return s;
|
|
103
|
+
return `${s.slice(0, head)}\u2026${s.slice(-tail)}`;
|
|
104
|
+
}
|
|
105
|
+
function ok(msg) {
|
|
106
|
+
console.log(`${c.green("\u2713")} ${msg}`);
|
|
107
|
+
}
|
|
108
|
+
function error(msg) {
|
|
109
|
+
console.error(`${c.red("\u2717")} ${msg}`);
|
|
110
|
+
}
|
|
111
|
+
function errorFromSdk(err) {
|
|
112
|
+
const e = err;
|
|
113
|
+
const status = e.status ? c.dim(`[${e.status}] `) : "";
|
|
114
|
+
const msg = e.message ?? String(err);
|
|
115
|
+
return `${status}${msg}`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/commands/login.ts
|
|
119
|
+
function registerAuthCommands(program2) {
|
|
120
|
+
program2.command("login").description("Save Ritkey service URL + API key to ~/.ritkey/config.json").option("-u, --url <url>", "Service base URL", "http://localhost:3000").requiredOption("-k, --key <apiKey>", "API key").action(async (opts) => {
|
|
121
|
+
await writeConfigFile({ baseUrl: opts.url, apiKey: opts.key });
|
|
122
|
+
ok(`Saved config to ${configFilePath()}`);
|
|
123
|
+
console.log(` baseUrl: ${opts.url}`);
|
|
124
|
+
});
|
|
125
|
+
program2.command("logout").description("Remove ~/.ritkey/config.json").action(async () => {
|
|
126
|
+
try {
|
|
127
|
+
await fs2.unlink(configFilePath());
|
|
128
|
+
ok("Logged out.");
|
|
129
|
+
} catch (err) {
|
|
130
|
+
if (err.code === "ENOENT") {
|
|
131
|
+
console.log(c.dim("Already logged out."));
|
|
132
|
+
} else {
|
|
133
|
+
error(`logout: ${err.message}`);
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
program2.command("whoami").description("Show resolved config (env \u2192 flags \u2192 config file)").action(async function() {
|
|
139
|
+
const cfg = await resolveConfig(this.optsWithGlobals());
|
|
140
|
+
console.log(`baseUrl: ${cfg.baseUrl}`);
|
|
141
|
+
console.log(`apiKey: ${cfg.apiKey ? c.green("set") : c.dim("not set")}`);
|
|
142
|
+
console.log(`source: ${cfg.source}`);
|
|
143
|
+
if (cfg.source === "file") {
|
|
144
|
+
console.log(c.dim(` ${configFilePath()}`));
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// src/client.ts
|
|
150
|
+
import { RitkeyClient } from "@ritkey/sdk";
|
|
151
|
+
async function makeClient(opts) {
|
|
152
|
+
const cfg = await resolveConfig(opts);
|
|
153
|
+
return new RitkeyClient({ baseUrl: cfg.baseUrl, apiKey: cfg.apiKey });
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// src/commands/wallets.ts
|
|
157
|
+
function gopts(cmd) {
|
|
158
|
+
return cmd.optsWithGlobals();
|
|
159
|
+
}
|
|
160
|
+
function registerWalletCommands(program2) {
|
|
161
|
+
program2.command("wallets").description("List wallets owned by this API key").action(async function() {
|
|
162
|
+
const client = await makeClient(gopts(this));
|
|
163
|
+
try {
|
|
164
|
+
const r = await client.wallets.list();
|
|
165
|
+
if (r.count === 0) {
|
|
166
|
+
console.log(c.dim("No wallets. Create one with: ritkey wallet new"));
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
console.log(
|
|
170
|
+
table(
|
|
171
|
+
r.wallets.map((w) => [
|
|
172
|
+
short(w.id),
|
|
173
|
+
w.address,
|
|
174
|
+
w.label || c.dim("\u2014"),
|
|
175
|
+
w.status === "active" ? c.green(w.status) : c.dim(w.status),
|
|
176
|
+
w.createdAt.split("T")[0]
|
|
177
|
+
]),
|
|
178
|
+
{ headers: ["ID", "Address", "Label", "Status", "Created"] }
|
|
179
|
+
)
|
|
180
|
+
);
|
|
181
|
+
} catch (err) {
|
|
182
|
+
error(`list wallets: ${errorFromSdk(err)}`);
|
|
183
|
+
process.exit(1);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
const wallet = program2.command("wallet").description("Per-wallet commands");
|
|
187
|
+
wallet.command("show <walletId>").description("Show wallet details").action(async function(walletId) {
|
|
188
|
+
const client = await makeClient(gopts(this));
|
|
189
|
+
try {
|
|
190
|
+
const [w, bal] = await Promise.all([
|
|
191
|
+
client.wallets.get(walletId),
|
|
192
|
+
client.wallets.balance(walletId).catch(() => null)
|
|
193
|
+
]);
|
|
194
|
+
console.log(c.bold(`Wallet ${w.id}`));
|
|
195
|
+
console.log(` address: ${w.address}`);
|
|
196
|
+
console.log(` label: ${w.label || c.dim("\u2014")}`);
|
|
197
|
+
console.log(` status: ${w.status}`);
|
|
198
|
+
console.log(` created: ${w.createdAt}`);
|
|
199
|
+
if (bal) {
|
|
200
|
+
console.log(` native: ${bal.native.formatted} ${bal.native.symbol}`);
|
|
201
|
+
console.log(
|
|
202
|
+
` escrow: ${bal.ritualWallet.formatted} RITUAL ${bal.ritualWallet.isLocked ? c.yellow("(locked)") : ""}`
|
|
203
|
+
);
|
|
204
|
+
} else {
|
|
205
|
+
console.log(c.dim(" balance: (rpc unavailable)"));
|
|
206
|
+
}
|
|
207
|
+
} catch (err) {
|
|
208
|
+
error(`show wallet: ${errorFromSdk(err)}`);
|
|
209
|
+
process.exit(1);
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
wallet.command("new").description("Create a new threshold (Shamir 2-of-3) wallet").option("-l, --label <label>", "Human label").action(async function(opts) {
|
|
213
|
+
const client = await makeClient(gopts(this));
|
|
214
|
+
try {
|
|
215
|
+
const w = await client.wallets.create({ label: opts.label });
|
|
216
|
+
ok(`Wallet created: ${w.address}`);
|
|
217
|
+
console.log();
|
|
218
|
+
console.log(c.bold("SAVE THESE \u2014 they are shown only once:"));
|
|
219
|
+
console.log(` ${c.cyan("walletId ")} ${w.walletId}`);
|
|
220
|
+
console.log(` ${c.cyan("address ")} ${w.address}`);
|
|
221
|
+
console.log(` ${c.yellow("agentShard ")} ${w.agentShard}`);
|
|
222
|
+
console.log(` ${c.yellow("backupShard ")} ${w.backupShard}`);
|
|
223
|
+
console.log();
|
|
224
|
+
console.log(
|
|
225
|
+
c.dim(
|
|
226
|
+
"You will need agentShard for every signing call. Store backupShard offline (cold storage)."
|
|
227
|
+
)
|
|
228
|
+
);
|
|
229
|
+
} catch (err) {
|
|
230
|
+
error(`create wallet: ${errorFromSdk(err)}`);
|
|
231
|
+
process.exit(1);
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
wallet.command("import <privateKey>").description("Import an existing private key into Ritkey").option("-l, --label <label>", "Human label").action(async function(privateKey, opts) {
|
|
235
|
+
const client = await makeClient(gopts(this));
|
|
236
|
+
try {
|
|
237
|
+
const w = await client.wallets.import_({ privateKey, label: opts.label });
|
|
238
|
+
ok(`Wallet imported: ${w.address}`);
|
|
239
|
+
console.log();
|
|
240
|
+
console.log(c.bold("SAVE THESE \u2014 they are shown only once:"));
|
|
241
|
+
console.log(` ${c.cyan("walletId ")} ${w.walletId}`);
|
|
242
|
+
console.log(` ${c.yellow("agentShard ")} ${w.agentShard}`);
|
|
243
|
+
console.log(` ${c.yellow("backupShard ")} ${w.backupShard}`);
|
|
244
|
+
} catch (err) {
|
|
245
|
+
error(`import wallet: ${errorFromSdk(err)}`);
|
|
246
|
+
process.exit(1);
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
wallet.command("balance <walletId>").description("Quick on-chain balance check").action(async function(walletId) {
|
|
250
|
+
const client = await makeClient(gopts(this));
|
|
251
|
+
try {
|
|
252
|
+
const b = await client.wallets.balance(walletId);
|
|
253
|
+
console.log(`${c.bold(b.address)}`);
|
|
254
|
+
console.log(` native: ${b.native.formatted} ${b.native.symbol}`);
|
|
255
|
+
console.log(
|
|
256
|
+
` escrow: ${b.ritualWallet.formatted} RITUAL ${b.ritualWallet.isLocked ? c.yellow("(locked)") : ""}`
|
|
257
|
+
);
|
|
258
|
+
} catch (err) {
|
|
259
|
+
error(`balance: ${errorFromSdk(err)}`);
|
|
260
|
+
process.exit(1);
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
wallet.command("send <walletId>").description("Sign and broadcast a transaction").requiredOption("--to <address>", "Destination address").requiredOption("--value <ritual>", "Amount in RITUAL (decimal)").requiredOption("--agent-shard <hex>", "Your agent key shard").option("--data <hex>", "Calldata (default 0x)").action(async function(walletId, opts) {
|
|
264
|
+
const client = await makeClient(gopts(this));
|
|
265
|
+
try {
|
|
266
|
+
const tx = await client.wallets.send({
|
|
267
|
+
walletId,
|
|
268
|
+
agentShard: opts.agentShard,
|
|
269
|
+
to: opts.to,
|
|
270
|
+
value: opts.value,
|
|
271
|
+
data: opts.data
|
|
272
|
+
});
|
|
273
|
+
ok(`Sent ${opts.value} RITUAL`);
|
|
274
|
+
console.log(` hash: ${tx.hash}`);
|
|
275
|
+
console.log(` explorer: ${tx.explorer}`);
|
|
276
|
+
} catch (err) {
|
|
277
|
+
error(`send: ${errorFromSdk(err)}`);
|
|
278
|
+
process.exit(1);
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
wallet.command("fund <walletId>").description("Claim one-time faucet drip (1 per wallet, lifetime)").action(async function(walletId) {
|
|
282
|
+
const client = await makeClient(gopts(this));
|
|
283
|
+
try {
|
|
284
|
+
const r = await client.wallets.fund(walletId);
|
|
285
|
+
ok(`Funded ${r.amount} RITUAL`);
|
|
286
|
+
console.log(` hash: ${r.hash}`);
|
|
287
|
+
} catch (err) {
|
|
288
|
+
error(`fund: ${errorFromSdk(err)}`);
|
|
289
|
+
process.exit(1);
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
wallet.command("export-key <walletId>").description(
|
|
293
|
+
"Export the private key. WARNING: archives the wallet after export."
|
|
294
|
+
).requiredOption("--agent-shard <hex>", "Your agent key shard").option("--backup-shard <hex>", "Optional backup shard for full offline reconstruction").action(async function(walletId, opts) {
|
|
295
|
+
const client = await makeClient(gopts(this));
|
|
296
|
+
try {
|
|
297
|
+
const r = await client.wallets.exportKey({
|
|
298
|
+
walletId,
|
|
299
|
+
agentShard: opts.agentShard,
|
|
300
|
+
backupShard: opts.backupShard
|
|
301
|
+
});
|
|
302
|
+
ok(`Exported \u2014 wallet is now ARCHIVED.`);
|
|
303
|
+
console.log(` address: ${r.address}`);
|
|
304
|
+
console.log(` privateKey: ${c.yellow(r.privateKey)}`);
|
|
305
|
+
console.log(
|
|
306
|
+
c.dim(
|
|
307
|
+
"Import this into MetaMask/Rabby. Sweep funds out first if you want to keep using this address."
|
|
308
|
+
)
|
|
309
|
+
);
|
|
310
|
+
} catch (err) {
|
|
311
|
+
error(`export-key: ${errorFromSdk(err)}`);
|
|
312
|
+
process.exit(1);
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
wallet.command("sweep <walletId>").description("Sweep all native RITUAL to an address, then archive the wallet").requiredOption("--to <address>", "Destination address for the sweep").requiredOption("--agent-shard <hex>", "Your agent key shard").action(async function(walletId, opts) {
|
|
316
|
+
const client = await makeClient(gopts(this));
|
|
317
|
+
try {
|
|
318
|
+
const r = await client.wallets.sweepAndArchive({
|
|
319
|
+
walletId,
|
|
320
|
+
agentShard: opts.agentShard,
|
|
321
|
+
sweepTo: opts.to
|
|
322
|
+
});
|
|
323
|
+
ok(`Wallet archived ${r.swept ? `(swept to ${r.sweepTo})` : "(nothing to sweep)"}`);
|
|
324
|
+
if (r.sweepTxHash) console.log(` hash: ${r.sweepTxHash}`);
|
|
325
|
+
} catch (err) {
|
|
326
|
+
error(`sweep: ${errorFromSdk(err)}`);
|
|
327
|
+
process.exit(1);
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// src/commands/events.ts
|
|
333
|
+
function gopts2(cmd) {
|
|
334
|
+
return cmd.optsWithGlobals();
|
|
335
|
+
}
|
|
336
|
+
function colorType(t) {
|
|
337
|
+
if (t.startsWith("alert.")) return c.red(t);
|
|
338
|
+
if (t.startsWith("wallet.")) return c.cyan(t);
|
|
339
|
+
if (t.startsWith("tx.")) return c.yellow(t);
|
|
340
|
+
if (t.startsWith("key.")) return c.magenta(t);
|
|
341
|
+
return t;
|
|
342
|
+
}
|
|
343
|
+
function registerEventCommands(program2) {
|
|
344
|
+
const events = program2.command("events").description("Wallet event stream");
|
|
345
|
+
events.command("list", { isDefault: true }).description("List recent events (newest first)").option("-w, --wallet <id>", "Filter by wallet").option("-t, --type <type>", "Filter by event type").option("-n, --limit <n>", "Max results", "50").action(async function(opts) {
|
|
346
|
+
const client = await makeClient(gopts2(this));
|
|
347
|
+
try {
|
|
348
|
+
const r = await client.events.list({
|
|
349
|
+
walletId: opts.wallet,
|
|
350
|
+
type: opts.type,
|
|
351
|
+
limit: Number(opts.limit)
|
|
352
|
+
});
|
|
353
|
+
if (r.length === 0) {
|
|
354
|
+
console.log(c.dim("No events."));
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
console.log(
|
|
358
|
+
table(
|
|
359
|
+
r.map((e) => [
|
|
360
|
+
e.timestamp.replace("T", " ").replace(/\.\d+Z$/, "Z"),
|
|
361
|
+
colorType(e.type),
|
|
362
|
+
short(e.id, 8, 0),
|
|
363
|
+
e.walletId ? short(e.walletId, 8, 0) : c.dim("\u2014")
|
|
364
|
+
]),
|
|
365
|
+
{ headers: ["Time", "Type", "Event", "Wallet"] }
|
|
366
|
+
)
|
|
367
|
+
);
|
|
368
|
+
} catch (err) {
|
|
369
|
+
error(`list events: ${errorFromSdk(err)}`);
|
|
370
|
+
process.exit(1);
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
events.command("watch").description("Live tail of new events (Ctrl-C to stop)").option("-w, --wallet <id>", "Filter by wallet").option("-t, --types <types>", "Comma-separated event types").option("-i, --interval <ms>", "Poll interval ms", "3000").action(async function(opts) {
|
|
374
|
+
const client = await makeClient(gopts2(this));
|
|
375
|
+
const types = opts.types ? opts.types.split(",").map((t) => t.trim()) : void 0;
|
|
376
|
+
console.log(c.dim("Watching events\u2026 (Ctrl-C to stop)"));
|
|
377
|
+
const stop = client.events.subscribe({
|
|
378
|
+
types,
|
|
379
|
+
walletId: opts.wallet,
|
|
380
|
+
intervalMs: Number(opts.interval),
|
|
381
|
+
onEvent: (e) => {
|
|
382
|
+
const t = e.timestamp.replace("T", " ").replace(/\.\d+Z$/, "Z");
|
|
383
|
+
console.log(`${c.dim(t)} ${colorType(e.type)} ${short(e.id, 8, 0)}`);
|
|
384
|
+
},
|
|
385
|
+
onError: (err) => error(`poll: ${errorFromSdk(err)}`)
|
|
386
|
+
});
|
|
387
|
+
process.on("SIGINT", () => {
|
|
388
|
+
stop();
|
|
389
|
+
console.log();
|
|
390
|
+
console.log(c.dim("stopped."));
|
|
391
|
+
process.exit(0);
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// src/commands/alerts.ts
|
|
397
|
+
function gopts3(cmd) {
|
|
398
|
+
return cmd.optsWithGlobals();
|
|
399
|
+
}
|
|
400
|
+
function colorSeverity(s) {
|
|
401
|
+
if (s === "critical") return c.red(s);
|
|
402
|
+
if (s === "warn") return c.yellow(s);
|
|
403
|
+
return c.dim(s);
|
|
404
|
+
}
|
|
405
|
+
function registerAlertCommands(program2) {
|
|
406
|
+
program2.command("alerts").description("List alert rules owned by this API key").option("-w, --wallet <id>", "Scope to a single wallet").action(async function(opts) {
|
|
407
|
+
const client = await makeClient(gopts3(this));
|
|
408
|
+
try {
|
|
409
|
+
const r = opts.wallet ? await client.alerts.listForWallet(opts.wallet) : await client.alerts.list();
|
|
410
|
+
if (r.count === 0) {
|
|
411
|
+
console.log(c.dim("No alert rules. Create one with: ritkey alert new"));
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
console.log(
|
|
415
|
+
table(
|
|
416
|
+
r.rules.map((rule) => [
|
|
417
|
+
short(rule.id, 8, 0),
|
|
418
|
+
rule.kind,
|
|
419
|
+
rule.walletId ? short(rule.walletId, 8, 0) : c.dim("all"),
|
|
420
|
+
colorSeverity(rule.severity),
|
|
421
|
+
rule.enabled ? c.green("on") : c.dim("off"),
|
|
422
|
+
rule.label || c.dim("\u2014")
|
|
423
|
+
]),
|
|
424
|
+
{
|
|
425
|
+
headers: ["Rule", "Kind", "Wallet", "Severity", "State", "Label"]
|
|
426
|
+
}
|
|
427
|
+
)
|
|
428
|
+
);
|
|
429
|
+
} catch (err) {
|
|
430
|
+
error(`list alerts: ${errorFromSdk(err)}`);
|
|
431
|
+
process.exit(1);
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
const alert = program2.command("alert").description("Per-rule commands");
|
|
435
|
+
alert.command("new").description("Create an alert rule").requiredOption("-w, --wallet <id>", "Wallet ID").requiredOption(
|
|
436
|
+
"-k, --kind <kind>",
|
|
437
|
+
"Rule kind: spend_threshold | unusual_recipient | key_export_warning | balance_low"
|
|
438
|
+
).option("--threshold <ritual>", "For spend_threshold: trigger above this amount").option("--floor <ritual>", "For balance_low: trigger below this amount").option("--whitelist <addrs>", "For unusual_recipient: comma-separated addresses").option("-s, --severity <level>", "info | warn | critical", "warn").option("-l, --label <text>", "Human label").action(async function(opts) {
|
|
439
|
+
const client = await makeClient(gopts3(this));
|
|
440
|
+
let config;
|
|
441
|
+
switch (opts.kind) {
|
|
442
|
+
case "spend_threshold":
|
|
443
|
+
if (!opts.threshold) {
|
|
444
|
+
error("--threshold required for spend_threshold");
|
|
445
|
+
process.exit(1);
|
|
446
|
+
}
|
|
447
|
+
config = { thresholdRitual: opts.threshold };
|
|
448
|
+
break;
|
|
449
|
+
case "balance_low":
|
|
450
|
+
if (!opts.floor) {
|
|
451
|
+
error("--floor required for balance_low");
|
|
452
|
+
process.exit(1);
|
|
453
|
+
}
|
|
454
|
+
config = { floorRitual: opts.floor };
|
|
455
|
+
break;
|
|
456
|
+
case "unusual_recipient":
|
|
457
|
+
if (!opts.whitelist) {
|
|
458
|
+
error("--whitelist required for unusual_recipient");
|
|
459
|
+
process.exit(1);
|
|
460
|
+
}
|
|
461
|
+
config = {
|
|
462
|
+
whitelist: opts.whitelist.split(",").map((s) => s.trim())
|
|
463
|
+
};
|
|
464
|
+
break;
|
|
465
|
+
case "key_export_warning":
|
|
466
|
+
config = {};
|
|
467
|
+
break;
|
|
468
|
+
default:
|
|
469
|
+
error(`unknown kind: ${opts.kind}`);
|
|
470
|
+
process.exit(1);
|
|
471
|
+
}
|
|
472
|
+
try {
|
|
473
|
+
const rule = await client.alerts.create({
|
|
474
|
+
walletId: opts.wallet,
|
|
475
|
+
kind: opts.kind,
|
|
476
|
+
config,
|
|
477
|
+
severity: opts.severity,
|
|
478
|
+
label: opts.label
|
|
479
|
+
});
|
|
480
|
+
ok(`Created alert rule ${rule.id} (${rule.kind})`);
|
|
481
|
+
} catch (err) {
|
|
482
|
+
error(`create alert: ${errorFromSdk(err)}`);
|
|
483
|
+
process.exit(1);
|
|
484
|
+
}
|
|
485
|
+
});
|
|
486
|
+
alert.command("toggle <ruleId>").description("Flip a rule between enabled and disabled").action(async function(ruleId) {
|
|
487
|
+
const client = await makeClient(gopts3(this));
|
|
488
|
+
try {
|
|
489
|
+
const current = await client.alerts.get(ruleId);
|
|
490
|
+
const updated = await client.alerts.update(ruleId, {
|
|
491
|
+
enabled: !current.enabled
|
|
492
|
+
});
|
|
493
|
+
ok(`Rule ${ruleId} is now ${updated.enabled ? "enabled" : "disabled"}`);
|
|
494
|
+
} catch (err) {
|
|
495
|
+
error(`toggle: ${errorFromSdk(err)}`);
|
|
496
|
+
process.exit(1);
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
alert.command("rm <ruleId>").description("Delete an alert rule").action(async function(ruleId) {
|
|
500
|
+
const client = await makeClient(gopts3(this));
|
|
501
|
+
try {
|
|
502
|
+
await client.alerts.delete(ruleId);
|
|
503
|
+
ok(`Deleted rule ${ruleId}`);
|
|
504
|
+
} catch (err) {
|
|
505
|
+
error(`delete: ${errorFromSdk(err)}`);
|
|
506
|
+
process.exit(1);
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// src/commands/webhooks.ts
|
|
512
|
+
function gopts4(cmd) {
|
|
513
|
+
return cmd.optsWithGlobals();
|
|
514
|
+
}
|
|
515
|
+
function registerWebhookCommands(program2) {
|
|
516
|
+
program2.command("webhooks").description("List webhook subscriptions").action(async function() {
|
|
517
|
+
const client = await makeClient(gopts4(this));
|
|
518
|
+
try {
|
|
519
|
+
const r = await client.webhooks.list();
|
|
520
|
+
if (r.count === 0) {
|
|
521
|
+
console.log(c.dim("No webhooks. Create one with: ritkey webhook new --url ..."));
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
console.log(
|
|
525
|
+
table(
|
|
526
|
+
r.subscriptions.map((s) => [
|
|
527
|
+
short(s.id, 8, 0),
|
|
528
|
+
s.url,
|
|
529
|
+
s.eventsFilter.join(","),
|
|
530
|
+
s.status === "active" ? c.green(s.status) : c.dim(s.status),
|
|
531
|
+
s.lastDeliveryAt ?? c.dim("\u2014")
|
|
532
|
+
]),
|
|
533
|
+
{ headers: ["ID", "URL", "Filter", "Status", "Last delivery"] }
|
|
534
|
+
)
|
|
535
|
+
);
|
|
536
|
+
} catch (err) {
|
|
537
|
+
error(`list webhooks: ${errorFromSdk(err)}`);
|
|
538
|
+
process.exit(1);
|
|
539
|
+
}
|
|
540
|
+
});
|
|
541
|
+
const webhook = program2.command("webhook").description("Per-subscription commands");
|
|
542
|
+
webhook.command("new").description("Register a webhook subscription").requiredOption("-u, --url <url>", "HTTPS endpoint that will receive POST deliveries").option("-e, --events <types>", "Comma-separated event types (default: *)").option("-l, --label <label>", "Human label").action(async function(opts) {
|
|
543
|
+
const client = await makeClient(gopts4(this));
|
|
544
|
+
const events = opts.events ? opts.events.split(",").map((s) => s.trim()) : void 0;
|
|
545
|
+
try {
|
|
546
|
+
const w = await client.webhooks.create({
|
|
547
|
+
url: opts.url,
|
|
548
|
+
events,
|
|
549
|
+
label: opts.label
|
|
550
|
+
});
|
|
551
|
+
ok(`Webhook created: ${w.id}`);
|
|
552
|
+
console.log();
|
|
553
|
+
console.log(c.bold("SAVE THIS \u2014 shown only once:"));
|
|
554
|
+
console.log(` ${c.yellow("secret ")} ${w.secret}`);
|
|
555
|
+
console.log();
|
|
556
|
+
console.log(
|
|
557
|
+
c.dim(
|
|
558
|
+
'Use it to verify HMAC signatures: SDK provides verifyWebhook(rawBody, headers["ritkey-signature"], secret).'
|
|
559
|
+
)
|
|
560
|
+
);
|
|
561
|
+
} catch (err) {
|
|
562
|
+
error(`create webhook: ${errorFromSdk(err)}`);
|
|
563
|
+
process.exit(1);
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
webhook.command("test <webhookId>").description("Send a webhook.test event to the subscription URL").action(async function(webhookId) {
|
|
567
|
+
const client = await makeClient(gopts4(this));
|
|
568
|
+
try {
|
|
569
|
+
await client.webhooks.test(webhookId);
|
|
570
|
+
ok(`Test event enqueued for ${webhookId}`);
|
|
571
|
+
} catch (err) {
|
|
572
|
+
error(`test webhook: ${errorFromSdk(err)}`);
|
|
573
|
+
process.exit(1);
|
|
574
|
+
}
|
|
575
|
+
});
|
|
576
|
+
webhook.command("rm <webhookId>").description("Delete a webhook subscription").action(async function(webhookId) {
|
|
577
|
+
const client = await makeClient(gopts4(this));
|
|
578
|
+
try {
|
|
579
|
+
await client.webhooks.delete(webhookId);
|
|
580
|
+
ok(`Deleted ${webhookId}`);
|
|
581
|
+
} catch (err) {
|
|
582
|
+
error(`delete webhook: ${errorFromSdk(err)}`);
|
|
583
|
+
process.exit(1);
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// src/index.ts
|
|
589
|
+
var program = new Command();
|
|
590
|
+
program.name("ritkey").description("Ritkey CLI \u2014 wallets, events, alerts, webhooks").version("0.1.0").option(
|
|
591
|
+
"--api-url <url>",
|
|
592
|
+
"Override service base URL (env: RITKEY_API_URL)"
|
|
593
|
+
).option("--api-key <key>", "Override API key (env: RITKEY_API_KEY)");
|
|
594
|
+
registerAuthCommands(program);
|
|
595
|
+
registerWalletCommands(program);
|
|
596
|
+
registerEventCommands(program);
|
|
597
|
+
registerAlertCommands(program);
|
|
598
|
+
registerWebhookCommands(program);
|
|
599
|
+
await program.parseAsync(process.argv);
|
|
600
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/login.ts","../src/config.ts","../src/output.ts","../src/client.ts","../src/commands/wallets.ts","../src/commands/events.ts","../src/commands/alerts.ts","../src/commands/webhooks.ts"],"sourcesContent":["/**\n * @ritkey/cli — operator tool for Ritkey.\n *\n * ritkey login --url ... --key ...\n * ritkey wallets\n * ritkey wallet new\n * ritkey events watch\n * ritkey alerts\n * ritkey webhooks\n */\nimport { Command } from 'commander';\nimport { registerAuthCommands } from './commands/login.js';\nimport { registerWalletCommands } from './commands/wallets.js';\nimport { registerEventCommands } from './commands/events.js';\nimport { registerAlertCommands } from './commands/alerts.js';\nimport { registerWebhookCommands } from './commands/webhooks.js';\n\nconst program = new Command();\n\nprogram\n .name('ritkey')\n .description('Ritkey CLI — wallets, events, alerts, webhooks')\n .version('0.1.0')\n .option(\n '--api-url <url>',\n 'Override service base URL (env: RITKEY_API_URL)'\n )\n .option('--api-key <key>', 'Override API key (env: RITKEY_API_KEY)');\n\nregisterAuthCommands(program);\nregisterWalletCommands(program);\nregisterEventCommands(program);\nregisterAlertCommands(program);\nregisterWebhookCommands(program);\n\nawait program.parseAsync(process.argv);\n","/**\n * Auth / config commands.\n *\n * ritkey login --url URL --key KEY write ~/.ritkey/config.json\n * ritkey logout remove ~/.ritkey/config.json\n * ritkey whoami print effective config\n */\nimport { promises as fs } from 'node:fs';\nimport type { Command } from 'commander';\nimport {\n configFilePath,\n readConfigFile,\n resolveConfig,\n writeConfigFile,\n} from '../config.js';\nimport { c, ok, error } from '../output.js';\n\nexport function registerAuthCommands(program: Command): void {\n program\n .command('login')\n .description('Save Ritkey service URL + API key to ~/.ritkey/config.json')\n .option('-u, --url <url>', 'Service base URL', 'http://localhost:3000')\n .requiredOption('-k, --key <apiKey>', 'API key')\n .action(async (opts: { url: string; key: string }) => {\n await writeConfigFile({ baseUrl: opts.url, apiKey: opts.key });\n ok(`Saved config to ${configFilePath()}`);\n console.log(` baseUrl: ${opts.url}`);\n });\n\n program\n .command('logout')\n .description('Remove ~/.ritkey/config.json')\n .action(async () => {\n try {\n await fs.unlink(configFilePath());\n ok('Logged out.');\n } catch (err: any) {\n if (err.code === 'ENOENT') {\n console.log(c.dim('Already logged out.'));\n } else {\n error(`logout: ${err.message}`);\n process.exit(1);\n }\n }\n });\n\n program\n .command('whoami')\n .description('Show resolved config (env → flags → config file)')\n .action(async function (this: Command) {\n const cfg = await resolveConfig(this.optsWithGlobals());\n console.log(`baseUrl: ${cfg.baseUrl}`);\n console.log(`apiKey: ${cfg.apiKey ? c.green('set') : c.dim('not set')}`);\n console.log(`source: ${cfg.source}`);\n if (cfg.source === 'file') {\n console.log(c.dim(` ${configFilePath()}`));\n }\n });\n}\n","/**\n * CLI config loading.\n *\n * Resolution order (first hit wins):\n * 1. CLI flags (--api-url, --api-key) — handled by commander\n * 2. Env vars (RITKEY_API_URL, RITKEY_API_KEY)\n * 3. Config file ~/.ritkey/config.json\n *\n * `ritkey login` writes the config file.\n */\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\n\nexport interface ResolvedConfig {\n baseUrl: string;\n apiKey?: string;\n source: 'flags' | 'env' | 'file' | 'default';\n}\n\ninterface FileConfig {\n baseUrl?: string;\n apiKey?: string;\n}\n\nconst DEFAULT_BASE_URL = 'http://localhost:3000';\n\nexport function configFilePath(): string {\n return path.join(os.homedir(), '.ritkey', 'config.json');\n}\n\nexport async function readConfigFile(): Promise<FileConfig | null> {\n try {\n const raw = await fs.readFile(configFilePath(), 'utf8');\n return JSON.parse(raw) as FileConfig;\n } catch (err: any) {\n if (err.code === 'ENOENT') return null;\n throw err;\n }\n}\n\nexport async function writeConfigFile(cfg: FileConfig): Promise<void> {\n const p = configFilePath();\n await fs.mkdir(path.dirname(p), { recursive: true });\n await fs.writeFile(p, JSON.stringify(cfg, null, 2) + '\\n', { mode: 0o600 });\n}\n\nexport async function resolveConfig(opts: {\n apiUrl?: string;\n apiKey?: string;\n}): Promise<ResolvedConfig> {\n if (opts.apiUrl || opts.apiKey) {\n return {\n baseUrl: opts.apiUrl ?? process.env.RITKEY_API_URL ?? DEFAULT_BASE_URL,\n apiKey: opts.apiKey ?? process.env.RITKEY_API_KEY,\n source: 'flags',\n };\n }\n if (process.env.RITKEY_API_URL || process.env.RITKEY_API_KEY) {\n return {\n baseUrl: process.env.RITKEY_API_URL ?? DEFAULT_BASE_URL,\n apiKey: process.env.RITKEY_API_KEY,\n source: 'env',\n };\n }\n const file = await readConfigFile();\n if (file?.baseUrl || file?.apiKey) {\n return {\n baseUrl: file.baseUrl ?? DEFAULT_BASE_URL,\n apiKey: file.apiKey,\n source: 'file',\n };\n }\n return {\n baseUrl: DEFAULT_BASE_URL,\n source: 'default',\n };\n}\n","/**\n * Output helpers.\n *\n * No `chalk` dependency — raw ANSI escape codes are tiny and tree-shakeable.\n * Colors are disabled when stdout isn't a TTY (e.g. piped to a file) or when\n * NO_COLOR=1 is set.\n */\n\nconst isColorOn =\n process.stdout.isTTY === true && process.env.NO_COLOR !== '1';\n\nfunction paint(code: string, s: string): string {\n return isColorOn ? `\\x1b[${code}m${s}\\x1b[0m` : s;\n}\n\nexport const c = {\n dim: (s: string) => paint('2', s),\n bold: (s: string) => paint('1', s),\n red: (s: string) => paint('31', s),\n green: (s: string) => paint('32', s),\n yellow: (s: string) => paint('33', s),\n blue: (s: string) => paint('34', s),\n cyan: (s: string) => paint('36', s),\n magenta: (s: string) => paint('35', s),\n};\n\n/** Tiny table formatter — pads each column to the longest cell. */\nexport function table(\n rows: Array<Array<string | number | null | undefined>>,\n opts?: { headers?: string[] }\n): string {\n const headers = opts?.headers ?? [];\n const data = headers.length ? [headers, ...rows] : rows;\n const stringified = data.map((r) => r.map((v) => (v == null ? '' : String(v))));\n\n const widths: number[] = [];\n for (const row of stringified) {\n for (let i = 0; i < row.length; i++) {\n const cell = row[i] ?? '';\n if (!widths[i] || cell.length > widths[i]!) widths[i] = cell.length;\n }\n }\n\n const lines: string[] = [];\n for (let r = 0; r < stringified.length; r++) {\n const row = stringified[r]!;\n const padded = row.map((cell, i) => (cell ?? '').padEnd(widths[i] ?? 0));\n const line = padded.join(' ');\n if (headers.length && r === 0) {\n lines.push(c.bold(line));\n lines.push(c.dim(widths.map((w) => '-'.repeat(w)).join(' ')));\n } else {\n lines.push(line);\n }\n }\n return lines.join('\\n');\n}\n\n/** Short prefix of a hex / uuid string for display. */\nexport function short(s: string | null | undefined, head = 8, tail = 6): string {\n if (!s) return c.dim('—');\n if (s.length <= head + tail + 1) return s;\n return `${s.slice(0, head)}…${s.slice(-tail)}`;\n}\n\nexport function ok(msg: string): void {\n console.log(`${c.green('✓')} ${msg}`);\n}\nexport function info(msg: string): void {\n console.log(`${c.cyan('›')} ${msg}`);\n}\nexport function warn(msg: string): void {\n console.warn(`${c.yellow('!')} ${msg}`);\n}\nexport function error(msg: string): void {\n console.error(`${c.red('✗')} ${msg}`);\n}\n\n/** Render an SDK error as a one-line message + optional details. */\nexport function errorFromSdk(err: unknown): string {\n const e = err as { status?: number; message?: string; body?: any };\n const status = e.status ? c.dim(`[${e.status}] `) : '';\n const msg = e.message ?? String(err);\n return `${status}${msg}`;\n}\n","/**\n * SDK client factory — wraps RitkeyClient with global config resolution.\n *\n * Every command receives the apiUrl/apiKey via commander's `program.opts()`,\n * which are merged with env + config file by resolveConfig.\n */\nimport { RitkeyClient } from '@ritkey/sdk';\nimport { resolveConfig } from './config.js';\n\nexport async function makeClient(opts: {\n apiUrl?: string;\n apiKey?: string;\n}): Promise<RitkeyClient> {\n const cfg = await resolveConfig(opts);\n return new RitkeyClient({ baseUrl: cfg.baseUrl, apiKey: cfg.apiKey });\n}\n","/**\n * Wallet commands.\n *\n * ritkey wallets list\n * ritkey wallet <id> show details\n * ritkey wallet new [--label] create\n * ritkey wallet import <pk> import\n * ritkey wallet balance <id> quick balance\n * ritkey wallet send <id> --to ADDR --value 0.5 --agent-shard ...\n * ritkey wallet export-key <id> --agent-shard ...\n * ritkey wallet sweep <id> --to ADDR --agent-shard ...\n */\nimport type { Command } from 'commander';\nimport { makeClient } from '../client.js';\nimport { c, table, short, ok, error, errorFromSdk } from '../output.js';\n\ninterface GlobalOpts {\n apiUrl?: string;\n apiKey?: string;\n}\n\nfunction gopts(cmd: Command): GlobalOpts {\n return cmd.optsWithGlobals() as GlobalOpts;\n}\n\nexport function registerWalletCommands(program: Command): void {\n // ── ritkey wallets ───────────────────────────────────────\n program\n .command('wallets')\n .description('List wallets owned by this API key')\n .action(async function (this: Command) {\n const client = await makeClient(gopts(this));\n try {\n const r = await client.wallets.list();\n if (r.count === 0) {\n console.log(c.dim('No wallets. Create one with: ritkey wallet new'));\n return;\n }\n console.log(\n table(\n r.wallets.map((w) => [\n short(w.id),\n w.address,\n w.label || c.dim('—'),\n w.status === 'active' ? c.green(w.status) : c.dim(w.status),\n w.createdAt.split('T')[0],\n ]),\n { headers: ['ID', 'Address', 'Label', 'Status', 'Created'] }\n )\n );\n } catch (err) {\n error(`list wallets: ${errorFromSdk(err)}`);\n process.exit(1);\n }\n });\n\n // ── ritkey wallet ──────────────────────────────────────────\n const wallet = program.command('wallet').description('Per-wallet commands');\n\n wallet\n .command('show <walletId>')\n .description('Show wallet details')\n .action(async function (this: Command, walletId: string) {\n const client = await makeClient(gopts(this));\n try {\n const [w, bal] = await Promise.all([\n client.wallets.get(walletId),\n client.wallets.balance(walletId).catch(() => null),\n ]);\n console.log(c.bold(`Wallet ${w.id}`));\n console.log(` address: ${w.address}`);\n console.log(` label: ${w.label || c.dim('—')}`);\n console.log(` status: ${w.status}`);\n console.log(` created: ${w.createdAt}`);\n if (bal) {\n console.log(` native: ${bal.native.formatted} ${bal.native.symbol}`);\n console.log(\n ` escrow: ${bal.ritualWallet.formatted} RITUAL ${\n bal.ritualWallet.isLocked ? c.yellow('(locked)') : ''\n }`\n );\n } else {\n console.log(c.dim(' balance: (rpc unavailable)'));\n }\n } catch (err) {\n error(`show wallet: ${errorFromSdk(err)}`);\n process.exit(1);\n }\n });\n\n wallet\n .command('new')\n .description('Create a new threshold (Shamir 2-of-3) wallet')\n .option('-l, --label <label>', 'Human label')\n .action(async function (\n this: Command,\n opts: { label?: string }\n ) {\n const client = await makeClient(gopts(this));\n try {\n const w = await client.wallets.create({ label: opts.label });\n ok(`Wallet created: ${w.address}`);\n console.log();\n console.log(c.bold('SAVE THESE — they are shown only once:'));\n console.log(` ${c.cyan('walletId ')} ${w.walletId}`);\n console.log(` ${c.cyan('address ')} ${w.address}`);\n console.log(` ${c.yellow('agentShard ')} ${w.agentShard}`);\n console.log(` ${c.yellow('backupShard ')} ${w.backupShard}`);\n console.log();\n console.log(\n c.dim(\n 'You will need agentShard for every signing call. Store backupShard offline (cold storage).'\n )\n );\n } catch (err) {\n error(`create wallet: ${errorFromSdk(err)}`);\n process.exit(1);\n }\n });\n\n wallet\n .command('import <privateKey>')\n .description('Import an existing private key into Ritkey')\n .option('-l, --label <label>', 'Human label')\n .action(async function (\n this: Command,\n privateKey: string,\n opts: { label?: string }\n ) {\n const client = await makeClient(gopts(this));\n try {\n const w = await client.wallets.import_({ privateKey, label: opts.label });\n ok(`Wallet imported: ${w.address}`);\n console.log();\n console.log(c.bold('SAVE THESE — they are shown only once:'));\n console.log(` ${c.cyan('walletId ')} ${w.walletId}`);\n console.log(` ${c.yellow('agentShard ')} ${w.agentShard}`);\n console.log(` ${c.yellow('backupShard ')} ${w.backupShard}`);\n } catch (err) {\n error(`import wallet: ${errorFromSdk(err)}`);\n process.exit(1);\n }\n });\n\n wallet\n .command('balance <walletId>')\n .description('Quick on-chain balance check')\n .action(async function (this: Command, walletId: string) {\n const client = await makeClient(gopts(this));\n try {\n const b = await client.wallets.balance(walletId);\n console.log(`${c.bold(b.address)}`);\n console.log(` native: ${b.native.formatted} ${b.native.symbol}`);\n console.log(\n ` escrow: ${b.ritualWallet.formatted} RITUAL ${\n b.ritualWallet.isLocked ? c.yellow('(locked)') : ''\n }`\n );\n } catch (err) {\n error(`balance: ${errorFromSdk(err)}`);\n process.exit(1);\n }\n });\n\n wallet\n .command('send <walletId>')\n .description('Sign and broadcast a transaction')\n .requiredOption('--to <address>', 'Destination address')\n .requiredOption('--value <ritual>', 'Amount in RITUAL (decimal)')\n .requiredOption('--agent-shard <hex>', 'Your agent key shard')\n .option('--data <hex>', 'Calldata (default 0x)')\n .action(async function (\n this: Command,\n walletId: string,\n opts: { to: string; value: string; agentShard: string; data?: string }\n ) {\n const client = await makeClient(gopts(this));\n try {\n const tx = await client.wallets.send({\n walletId,\n agentShard: opts.agentShard,\n to: opts.to,\n value: opts.value,\n data: opts.data,\n });\n ok(`Sent ${opts.value} RITUAL`);\n console.log(` hash: ${tx.hash}`);\n console.log(` explorer: ${tx.explorer}`);\n } catch (err) {\n error(`send: ${errorFromSdk(err)}`);\n process.exit(1);\n }\n });\n\n wallet\n .command('fund <walletId>')\n .description('Claim one-time faucet drip (1 per wallet, lifetime)')\n .action(async function (this: Command, walletId: string) {\n const client = await makeClient(gopts(this));\n try {\n const r = await client.wallets.fund(walletId);\n ok(`Funded ${r.amount} RITUAL`);\n console.log(` hash: ${r.hash}`);\n } catch (err) {\n error(`fund: ${errorFromSdk(err)}`);\n process.exit(1);\n }\n });\n\n wallet\n .command('export-key <walletId>')\n .description(\n 'Export the private key. WARNING: archives the wallet after export.'\n )\n .requiredOption('--agent-shard <hex>', 'Your agent key shard')\n .option('--backup-shard <hex>', 'Optional backup shard for full offline reconstruction')\n .action(async function (\n this: Command,\n walletId: string,\n opts: { agentShard: string; backupShard?: string }\n ) {\n const client = await makeClient(gopts(this));\n try {\n const r = await client.wallets.exportKey({\n walletId,\n agentShard: opts.agentShard,\n backupShard: opts.backupShard,\n });\n ok(`Exported — wallet is now ARCHIVED.`);\n console.log(` address: ${r.address}`);\n console.log(` privateKey: ${c.yellow(r.privateKey)}`);\n console.log(\n c.dim(\n 'Import this into MetaMask/Rabby. Sweep funds out first if you want to keep using this address.'\n )\n );\n } catch (err) {\n error(`export-key: ${errorFromSdk(err)}`);\n process.exit(1);\n }\n });\n\n wallet\n .command('sweep <walletId>')\n .description('Sweep all native RITUAL to an address, then archive the wallet')\n .requiredOption('--to <address>', 'Destination address for the sweep')\n .requiredOption('--agent-shard <hex>', 'Your agent key shard')\n .action(async function (\n this: Command,\n walletId: string,\n opts: { to: string; agentShard: string }\n ) {\n const client = await makeClient(gopts(this));\n try {\n const r = await client.wallets.sweepAndArchive({\n walletId,\n agentShard: opts.agentShard,\n sweepTo: opts.to,\n });\n ok(`Wallet archived ${r.swept ? `(swept to ${r.sweepTo})` : '(nothing to sweep)'}`);\n if (r.sweepTxHash) console.log(` hash: ${r.sweepTxHash}`);\n } catch (err) {\n error(`sweep: ${errorFromSdk(err)}`);\n process.exit(1);\n }\n });\n}\n","/**\n * Event commands.\n *\n * ritkey events list recent\n * ritkey events --wallet <id> filter by wallet\n * ritkey events --type tx.sent filter by type\n * ritkey events watch live tail\n */\nimport type { Command } from 'commander';\nimport type { EventType } from '@ritkey/sdk';\nimport { makeClient } from '../client.js';\nimport { c, table, short, error, errorFromSdk } from '../output.js';\n\ninterface GlobalOpts {\n apiUrl?: string;\n apiKey?: string;\n}\nfunction gopts(cmd: Command): GlobalOpts {\n return cmd.optsWithGlobals() as GlobalOpts;\n}\n\nfunction colorType(t: string): string {\n if (t.startsWith('alert.')) return c.red(t);\n if (t.startsWith('wallet.')) return c.cyan(t);\n if (t.startsWith('tx.')) return c.yellow(t);\n if (t.startsWith('key.')) return c.magenta(t);\n return t;\n}\n\nexport function registerEventCommands(program: Command): void {\n const events = program.command('events').description('Wallet event stream');\n\n events\n .command('list', { isDefault: true })\n .description('List recent events (newest first)')\n .option('-w, --wallet <id>', 'Filter by wallet')\n .option('-t, --type <type>', 'Filter by event type')\n .option('-n, --limit <n>', 'Max results', '50')\n .action(async function (\n this: Command,\n opts: { wallet?: string; type?: string; limit: string }\n ) {\n const client = await makeClient(gopts(this));\n try {\n const r = await client.events.list({\n walletId: opts.wallet,\n type: opts.type as EventType | undefined,\n limit: Number(opts.limit),\n });\n if (r.length === 0) {\n console.log(c.dim('No events.'));\n return;\n }\n console.log(\n table(\n r.map((e) => [\n e.timestamp.replace('T', ' ').replace(/\\.\\d+Z$/, 'Z'),\n colorType(e.type),\n short(e.id, 8, 0),\n e.walletId ? short(e.walletId, 8, 0) : c.dim('—'),\n ]),\n { headers: ['Time', 'Type', 'Event', 'Wallet'] }\n )\n );\n } catch (err) {\n error(`list events: ${errorFromSdk(err)}`);\n process.exit(1);\n }\n });\n\n events\n .command('watch')\n .description('Live tail of new events (Ctrl-C to stop)')\n .option('-w, --wallet <id>', 'Filter by wallet')\n .option('-t, --types <types>', 'Comma-separated event types')\n .option('-i, --interval <ms>', 'Poll interval ms', '3000')\n .action(async function (\n this: Command,\n opts: { wallet?: string; types?: string; interval: string }\n ) {\n const client = await makeClient(gopts(this));\n const types = opts.types\n ? (opts.types.split(',').map((t) => t.trim()) as EventType[])\n : undefined;\n\n console.log(c.dim('Watching events… (Ctrl-C to stop)'));\n\n const stop = client.events.subscribe({\n types,\n walletId: opts.wallet,\n intervalMs: Number(opts.interval),\n onEvent: (e) => {\n const t = e.timestamp.replace('T', ' ').replace(/\\.\\d+Z$/, 'Z');\n console.log(`${c.dim(t)} ${colorType(e.type)} ${short(e.id, 8, 0)}`);\n },\n onError: (err) => error(`poll: ${errorFromSdk(err)}`),\n });\n\n process.on('SIGINT', () => {\n stop();\n console.log();\n console.log(c.dim('stopped.'));\n process.exit(0);\n });\n });\n}\n","/**\n * Alert rule commands.\n *\n * ritkey alerts list\n * ritkey alert new --wallet ID --kind spend_threshold --threshold 0.5\n * ritkey alert new --wallet ID --kind unusual_recipient --whitelist 0xaaa,0xbbb\n * ritkey alert new --wallet ID --kind key_export_warning\n * ritkey alert new --wallet ID --kind balance_low --floor 0.1\n * ritkey alert toggle <ruleId>\n * ritkey alert rm <ruleId>\n */\nimport type { Command } from 'commander';\nimport type { AlertKind, AlertConfig } from '@ritkey/sdk';\nimport { makeClient } from '../client.js';\nimport { c, table, short, ok, error, errorFromSdk } from '../output.js';\n\ninterface GlobalOpts {\n apiUrl?: string;\n apiKey?: string;\n}\nfunction gopts(cmd: Command): GlobalOpts {\n return cmd.optsWithGlobals() as GlobalOpts;\n}\n\nfunction colorSeverity(s: string): string {\n if (s === 'critical') return c.red(s);\n if (s === 'warn') return c.yellow(s);\n return c.dim(s);\n}\n\nexport function registerAlertCommands(program: Command): void {\n program\n .command('alerts')\n .description('List alert rules owned by this API key')\n .option('-w, --wallet <id>', 'Scope to a single wallet')\n .action(async function (this: Command, opts: { wallet?: string }) {\n const client = await makeClient(gopts(this));\n try {\n const r = opts.wallet\n ? await client.alerts.listForWallet(opts.wallet)\n : await client.alerts.list();\n if (r.count === 0) {\n console.log(c.dim('No alert rules. Create one with: ritkey alert new'));\n return;\n }\n console.log(\n table(\n r.rules.map((rule) => [\n short(rule.id, 8, 0),\n rule.kind,\n rule.walletId ? short(rule.walletId, 8, 0) : c.dim('all'),\n colorSeverity(rule.severity),\n rule.enabled ? c.green('on') : c.dim('off'),\n rule.label || c.dim('—'),\n ]),\n {\n headers: ['Rule', 'Kind', 'Wallet', 'Severity', 'State', 'Label'],\n }\n )\n );\n } catch (err) {\n error(`list alerts: ${errorFromSdk(err)}`);\n process.exit(1);\n }\n });\n\n const alert = program.command('alert').description('Per-rule commands');\n\n alert\n .command('new')\n .description('Create an alert rule')\n .requiredOption('-w, --wallet <id>', 'Wallet ID')\n .requiredOption(\n '-k, --kind <kind>',\n 'Rule kind: spend_threshold | unusual_recipient | key_export_warning | balance_low'\n )\n .option('--threshold <ritual>', 'For spend_threshold: trigger above this amount')\n .option('--floor <ritual>', 'For balance_low: trigger below this amount')\n .option('--whitelist <addrs>', 'For unusual_recipient: comma-separated addresses')\n .option('-s, --severity <level>', 'info | warn | critical', 'warn')\n .option('-l, --label <text>', 'Human label')\n .action(async function (\n this: Command,\n opts: {\n wallet: string;\n kind: string;\n threshold?: string;\n floor?: string;\n whitelist?: string;\n severity: string;\n label?: string;\n }\n ) {\n const client = await makeClient(gopts(this));\n let config: AlertConfig;\n switch (opts.kind as AlertKind) {\n case 'spend_threshold':\n if (!opts.threshold) {\n error('--threshold required for spend_threshold');\n process.exit(1);\n }\n config = { thresholdRitual: opts.threshold };\n break;\n case 'balance_low':\n if (!opts.floor) {\n error('--floor required for balance_low');\n process.exit(1);\n }\n config = { floorRitual: opts.floor };\n break;\n case 'unusual_recipient':\n if (!opts.whitelist) {\n error('--whitelist required for unusual_recipient');\n process.exit(1);\n }\n config = {\n whitelist: opts.whitelist.split(',').map((s) => s.trim()),\n };\n break;\n case 'key_export_warning':\n config = {};\n break;\n default:\n error(`unknown kind: ${opts.kind}`);\n process.exit(1);\n }\n try {\n const rule = await client.alerts.create({\n walletId: opts.wallet,\n kind: opts.kind as AlertKind,\n config: config!,\n severity: opts.severity as 'info' | 'warn' | 'critical',\n label: opts.label,\n });\n ok(`Created alert rule ${rule.id} (${rule.kind})`);\n } catch (err) {\n error(`create alert: ${errorFromSdk(err)}`);\n process.exit(1);\n }\n });\n\n alert\n .command('toggle <ruleId>')\n .description('Flip a rule between enabled and disabled')\n .action(async function (this: Command, ruleId: string) {\n const client = await makeClient(gopts(this));\n try {\n const current = await client.alerts.get(ruleId);\n const updated = await client.alerts.update(ruleId, {\n enabled: !current.enabled,\n });\n ok(`Rule ${ruleId} is now ${updated.enabled ? 'enabled' : 'disabled'}`);\n } catch (err) {\n error(`toggle: ${errorFromSdk(err)}`);\n process.exit(1);\n }\n });\n\n alert\n .command('rm <ruleId>')\n .description('Delete an alert rule')\n .action(async function (this: Command, ruleId: string) {\n const client = await makeClient(gopts(this));\n try {\n await client.alerts.delete(ruleId);\n ok(`Deleted rule ${ruleId}`);\n } catch (err) {\n error(`delete: ${errorFromSdk(err)}`);\n process.exit(1);\n }\n });\n}\n","/**\n * Webhook subscription commands.\n *\n * ritkey webhooks list\n * ritkey webhook new --url URL [--events tx.sent,alert.*]\n * ritkey webhook test <id>\n * ritkey webhook rm <id>\n */\nimport type { Command } from 'commander';\nimport type { EventType } from '@ritkey/sdk';\nimport { makeClient } from '../client.js';\nimport { c, table, short, ok, error, errorFromSdk } from '../output.js';\n\ninterface GlobalOpts {\n apiUrl?: string;\n apiKey?: string;\n}\nfunction gopts(cmd: Command): GlobalOpts {\n return cmd.optsWithGlobals() as GlobalOpts;\n}\n\nexport function registerWebhookCommands(program: Command): void {\n program\n .command('webhooks')\n .description('List webhook subscriptions')\n .action(async function (this: Command) {\n const client = await makeClient(gopts(this));\n try {\n const r = await client.webhooks.list();\n if (r.count === 0) {\n console.log(c.dim('No webhooks. Create one with: ritkey webhook new --url ...'));\n return;\n }\n console.log(\n table(\n r.subscriptions.map((s) => [\n short(s.id, 8, 0),\n s.url,\n s.eventsFilter.join(','),\n s.status === 'active' ? c.green(s.status) : c.dim(s.status),\n s.lastDeliveryAt ?? c.dim('—'),\n ]),\n { headers: ['ID', 'URL', 'Filter', 'Status', 'Last delivery'] }\n )\n );\n } catch (err) {\n error(`list webhooks: ${errorFromSdk(err)}`);\n process.exit(1);\n }\n });\n\n const webhook = program.command('webhook').description('Per-subscription commands');\n\n webhook\n .command('new')\n .description('Register a webhook subscription')\n .requiredOption('-u, --url <url>', 'HTTPS endpoint that will receive POST deliveries')\n .option('-e, --events <types>', 'Comma-separated event types (default: *)')\n .option('-l, --label <label>', 'Human label')\n .action(async function (\n this: Command,\n opts: { url: string; events?: string; label?: string }\n ) {\n const client = await makeClient(gopts(this));\n const events = opts.events\n ? (opts.events.split(',').map((s) => s.trim()) as (EventType | '*')[])\n : undefined;\n try {\n const w = await client.webhooks.create({\n url: opts.url,\n events,\n label: opts.label,\n });\n ok(`Webhook created: ${w.id}`);\n console.log();\n console.log(c.bold('SAVE THIS — shown only once:'));\n console.log(` ${c.yellow('secret ')} ${w.secret}`);\n console.log();\n console.log(\n c.dim(\n 'Use it to verify HMAC signatures: SDK provides verifyWebhook(rawBody, headers[\"ritkey-signature\"], secret).'\n )\n );\n } catch (err) {\n error(`create webhook: ${errorFromSdk(err)}`);\n process.exit(1);\n }\n });\n\n webhook\n .command('test <webhookId>')\n .description('Send a webhook.test event to the subscription URL')\n .action(async function (this: Command, webhookId: string) {\n const client = await makeClient(gopts(this));\n try {\n await client.webhooks.test(webhookId);\n ok(`Test event enqueued for ${webhookId}`);\n } catch (err) {\n error(`test webhook: ${errorFromSdk(err)}`);\n process.exit(1);\n }\n });\n\n webhook\n .command('rm <webhookId>')\n .description('Delete a webhook subscription')\n .action(async function (this: Command, webhookId: string) {\n const client = await makeClient(gopts(this));\n try {\n await client.webhooks.delete(webhookId);\n ok(`Deleted ${webhookId}`);\n } catch (err) {\n error(`delete webhook: ${errorFromSdk(err)}`);\n process.exit(1);\n }\n });\n}\n"],"mappings":"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","names":["fs","program","fs","program","gopts","program","gopts","program","gopts","program"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ritkey/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Command-line operator tool for Ritkey — wallets, events, alerts, webhooks",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Chiefmmorgs <chiefmmorgs@gmail.com>",
|
|
7
|
+
"homepage": "https://github.com/mmorgsmorgan/ritual-agentic-wallet-#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/mmorgsmorgan/ritual-agentic-wallet-.git",
|
|
11
|
+
"directory": "packages/cli"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/mmorgsmorgan/ritual-agentic-wallet-/issues"
|
|
15
|
+
},
|
|
16
|
+
"type": "module",
|
|
17
|
+
"bin": {
|
|
18
|
+
"ritkey": "dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"README.md",
|
|
23
|
+
"LICENSE"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsup",
|
|
27
|
+
"dev": "tsx src/index.ts",
|
|
28
|
+
"prepublishOnly": "npm run build"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=18"
|
|
35
|
+
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"ritkey",
|
|
38
|
+
"ritual",
|
|
39
|
+
"wallet",
|
|
40
|
+
"cli",
|
|
41
|
+
"mpc",
|
|
42
|
+
"ai-agents"
|
|
43
|
+
],
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@ritkey/sdk": "file:../sdk",
|
|
46
|
+
"commander": "^12.1.0"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^22.15.21",
|
|
50
|
+
"tsup": "^8.5.1",
|
|
51
|
+
"tsx": "^4.19.4",
|
|
52
|
+
"typescript": "^5.8.3"
|
|
53
|
+
}
|
|
54
|
+
}
|