@getbags/cash 0.2.1 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -38
- package/SKILL.md +77 -29
- package/dist/api.d.ts +25 -1
- package/dist/api.js +25 -4
- package/dist/detect.d.ts +33 -0
- package/dist/detect.js +105 -0
- package/dist/doctor.d.ts +47 -0
- package/dist/doctor.js +212 -0
- package/dist/errors.d.ts +6 -0
- package/dist/errors.js +18 -0
- package/dist/fetch-hints.d.ts +18 -0
- package/dist/fetch-hints.js +17 -0
- package/dist/index.js +68 -50
- package/dist/install-apply.d.ts +29 -0
- package/dist/install-apply.js +55 -0
- package/dist/install-command.d.ts +17 -0
- package/dist/install-command.js +173 -0
- package/dist/install-plan.d.ts +68 -0
- package/dist/install-plan.js +337 -0
- package/dist/mcp-instructions.d.ts +7 -0
- package/dist/mcp-instructions.js +38 -0
- package/dist/mcp-server.d.ts +72 -0
- package/dist/mcp-server.js +293 -0
- package/dist/parse.d.ts +22 -1
- package/dist/parse.js +275 -14
- package/dist/policies.d.ts +26 -0
- package/dist/policies.js +69 -0
- package/package.json +10 -5
package/dist/parse.js
CHANGED
|
@@ -1,4 +1,47 @@
|
|
|
1
1
|
import { walletDepositsVisible } from './deposits-visible.js';
|
|
2
|
+
const VALID_CLIENTS = ['cursor', 'claude', 'codex'];
|
|
3
|
+
/**
|
|
4
|
+
* Per-command usage strings - the same text the flag-error paths print, so
|
|
5
|
+
* `bags <cmd> --help` never disagrees with a bad-flag error.
|
|
6
|
+
*/
|
|
7
|
+
const COMMAND_USAGE = {
|
|
8
|
+
redeem: 'usage: bags redeem <code> | bags redeem --test',
|
|
9
|
+
balance: 'usage: bags balance',
|
|
10
|
+
result: 'usage: bags result <id> [--field path] [--offset N] [--limit N]',
|
|
11
|
+
discover: 'usage: bags discover [query] [--format json|pretty]',
|
|
12
|
+
search: 'usage: bags search <query> [--format json|pretty]',
|
|
13
|
+
check: 'usage: bags check <url> [flags]',
|
|
14
|
+
fetch: 'usage: bags fetch <url> [flags]',
|
|
15
|
+
sessions: 'usage: bags sessions list|close [id] [--all --yes]',
|
|
16
|
+
init: 'usage: bags init [--dry-run] [--client cursor|claude|codex] [--scope project|user]',
|
|
17
|
+
doctor: 'usage: bags doctor [--scope project|user] [--client cursor|claude|codex]',
|
|
18
|
+
fund: 'usage: bags fund [--open] [--create] [--network NAME]',
|
|
19
|
+
transactions: 'usage: bags transactions [--limit N] [--cursor C] [--format json|pretty]',
|
|
20
|
+
policies: 'usage: bags policies get|set [--key=value ...]',
|
|
21
|
+
keys: 'usage: bags keys create|list|revoke',
|
|
22
|
+
register: 'usage: bags register <origin>',
|
|
23
|
+
mcp: 'usage: bags mcp',
|
|
24
|
+
};
|
|
25
|
+
function parseClientList(raw) {
|
|
26
|
+
const parts = raw
|
|
27
|
+
.split(',')
|
|
28
|
+
.map((p) => p.trim())
|
|
29
|
+
.filter(Boolean);
|
|
30
|
+
if (parts.length === 0) {
|
|
31
|
+
return { error: 'usage: bags init [--client cursor|claude|codex] (repeatable or comma-separated)' };
|
|
32
|
+
}
|
|
33
|
+
const out = [];
|
|
34
|
+
for (const part of parts) {
|
|
35
|
+
if (part !== 'cursor' && part !== 'claude' && part !== 'codex') {
|
|
36
|
+
return {
|
|
37
|
+
error: 'usage: bags init [--client cursor|claude|codex] (repeatable or comma-separated)',
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
if (!out.includes(part))
|
|
41
|
+
out.push(part);
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
2
45
|
function takeFormat(rest, usage) {
|
|
3
46
|
let format = 'pretty';
|
|
4
47
|
const out = [];
|
|
@@ -27,13 +70,44 @@ export function parseArgs(argv) {
|
|
|
27
70
|
return { command: 'help' };
|
|
28
71
|
}
|
|
29
72
|
const [cmd, ...rest] = argv;
|
|
73
|
+
// -h/--help on any command prints that command's usage (stdout, exit 0).
|
|
74
|
+
if (rest.includes('-h') || rest.includes('--help')) {
|
|
75
|
+
const known = cmd in COMMAND_USAGE;
|
|
76
|
+
if (!known)
|
|
77
|
+
return { command: 'error', message: `unknown command: ${cmd}` };
|
|
78
|
+
return { command: 'usage', message: COMMAND_USAGE[cmd] };
|
|
79
|
+
}
|
|
30
80
|
switch (cmd) {
|
|
31
81
|
case 'redeem': {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
82
|
+
let code;
|
|
83
|
+
let test = false;
|
|
84
|
+
for (const arg of rest) {
|
|
85
|
+
if (arg === '--test') {
|
|
86
|
+
test = true;
|
|
87
|
+
}
|
|
88
|
+
else if (arg.startsWith('-')) {
|
|
89
|
+
return {
|
|
90
|
+
command: 'error',
|
|
91
|
+
message: 'usage: bags redeem <code> | bags redeem --test',
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
else if (!code) {
|
|
95
|
+
code = arg;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
return {
|
|
99
|
+
command: 'error',
|
|
100
|
+
message: 'usage: bags redeem <code> | bags redeem --test',
|
|
101
|
+
};
|
|
102
|
+
}
|
|
35
103
|
}
|
|
36
|
-
|
|
104
|
+
if (!test && !code) {
|
|
105
|
+
return {
|
|
106
|
+
command: 'error',
|
|
107
|
+
message: 'usage: bags redeem <code> | bags redeem --test',
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return { command: 'redeem', code, test };
|
|
37
111
|
}
|
|
38
112
|
case 'balance':
|
|
39
113
|
return { command: 'balance' };
|
|
@@ -199,8 +273,145 @@ export function parseArgs(argv) {
|
|
|
199
273
|
}
|
|
200
274
|
return { command: 'sessions', action, sessionId, channelId, all, yes, format: parsed.format };
|
|
201
275
|
}
|
|
202
|
-
case 'init':
|
|
203
|
-
|
|
276
|
+
case 'init': {
|
|
277
|
+
let dryRun = false;
|
|
278
|
+
let scope = 'user';
|
|
279
|
+
const clients = [];
|
|
280
|
+
for (let i = 0; i < rest.length; i++) {
|
|
281
|
+
const arg = rest[i];
|
|
282
|
+
if (arg === '--dry-run') {
|
|
283
|
+
dryRun = true;
|
|
284
|
+
}
|
|
285
|
+
else if (arg === '--scope') {
|
|
286
|
+
const value = rest[++i];
|
|
287
|
+
if (value !== 'project' && value !== 'user') {
|
|
288
|
+
return {
|
|
289
|
+
command: 'error',
|
|
290
|
+
message: 'usage: bags init [--scope project|user]',
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
scope = value;
|
|
294
|
+
}
|
|
295
|
+
else if (arg.startsWith('--scope=')) {
|
|
296
|
+
const value = arg.slice('--scope='.length);
|
|
297
|
+
if (value !== 'project' && value !== 'user') {
|
|
298
|
+
return {
|
|
299
|
+
command: 'error',
|
|
300
|
+
message: 'usage: bags init [--scope project|user]',
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
scope = value;
|
|
304
|
+
}
|
|
305
|
+
else if (arg === '--client') {
|
|
306
|
+
const value = rest[++i];
|
|
307
|
+
if (!value) {
|
|
308
|
+
return {
|
|
309
|
+
command: 'error',
|
|
310
|
+
message: 'usage: bags init [--client cursor|claude|codex] (repeatable or comma-separated)',
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
const parsed = parseClientList(value);
|
|
314
|
+
if ('error' in parsed)
|
|
315
|
+
return { command: 'error', message: parsed.error };
|
|
316
|
+
for (const c of parsed) {
|
|
317
|
+
if (!clients.includes(c))
|
|
318
|
+
clients.push(c);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
else if (arg.startsWith('--client=')) {
|
|
322
|
+
const parsed = parseClientList(arg.slice('--client='.length));
|
|
323
|
+
if ('error' in parsed)
|
|
324
|
+
return { command: 'error', message: parsed.error };
|
|
325
|
+
for (const c of parsed) {
|
|
326
|
+
if (!clients.includes(c))
|
|
327
|
+
clients.push(c);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
else if (arg.startsWith('-')) {
|
|
331
|
+
return {
|
|
332
|
+
command: 'error',
|
|
333
|
+
message: 'usage: bags init [--dry-run] [--client cursor|claude|codex] [--scope project|user]',
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
return {
|
|
338
|
+
command: 'error',
|
|
339
|
+
message: 'usage: bags init [--dry-run] [--client cursor|claude|codex] [--scope project|user]',
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
// Keep only known clients (defensive; parseClientList already validates).
|
|
344
|
+
const filtered = clients.filter((c) => VALID_CLIENTS.includes(c));
|
|
345
|
+
return { command: 'init', dryRun, clients: filtered, scope };
|
|
346
|
+
}
|
|
347
|
+
case 'mcp':
|
|
348
|
+
return { command: 'mcp' };
|
|
349
|
+
case 'doctor': {
|
|
350
|
+
let scope;
|
|
351
|
+
const clients = [];
|
|
352
|
+
for (let i = 0; i < rest.length; i++) {
|
|
353
|
+
const arg = rest[i];
|
|
354
|
+
if (arg === '--scope') {
|
|
355
|
+
const value = rest[++i];
|
|
356
|
+
if (value !== 'project' && value !== 'user') {
|
|
357
|
+
return {
|
|
358
|
+
command: 'error',
|
|
359
|
+
message: 'usage: bags doctor [--scope project|user] [--client cursor|claude|codex]',
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
scope = value;
|
|
363
|
+
}
|
|
364
|
+
else if (arg.startsWith('--scope=')) {
|
|
365
|
+
const value = arg.slice('--scope='.length);
|
|
366
|
+
if (value !== 'project' && value !== 'user') {
|
|
367
|
+
return {
|
|
368
|
+
command: 'error',
|
|
369
|
+
message: 'usage: bags doctor [--scope project|user] [--client cursor|claude|codex]',
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
scope = value;
|
|
373
|
+
}
|
|
374
|
+
else if (arg === '--client') {
|
|
375
|
+
const value = rest[++i];
|
|
376
|
+
if (!value) {
|
|
377
|
+
return {
|
|
378
|
+
command: 'error',
|
|
379
|
+
message: 'usage: bags doctor [--client cursor|claude|codex] (repeatable or comma-separated)',
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
const parsed = parseClientList(value);
|
|
383
|
+
if ('error' in parsed)
|
|
384
|
+
return { command: 'error', message: parsed.error };
|
|
385
|
+
for (const c of parsed) {
|
|
386
|
+
if (!clients.includes(c))
|
|
387
|
+
clients.push(c);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
else if (arg.startsWith('--client=')) {
|
|
391
|
+
const parsed = parseClientList(arg.slice('--client='.length));
|
|
392
|
+
if ('error' in parsed)
|
|
393
|
+
return { command: 'error', message: parsed.error };
|
|
394
|
+
for (const c of parsed) {
|
|
395
|
+
if (!clients.includes(c))
|
|
396
|
+
clients.push(c);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
else if (arg.startsWith('-')) {
|
|
400
|
+
return {
|
|
401
|
+
command: 'error',
|
|
402
|
+
message: 'usage: bags doctor [--scope project|user] [--client cursor|claude|codex]',
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
return {
|
|
407
|
+
command: 'error',
|
|
408
|
+
message: 'usage: bags doctor [--scope project|user] [--client cursor|claude|codex]',
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
const filtered = clients.filter((c) => VALID_CLIENTS.includes(c));
|
|
413
|
+
return { command: 'doctor', clients: filtered, scope };
|
|
414
|
+
}
|
|
204
415
|
case 'fund': {
|
|
205
416
|
let open = false;
|
|
206
417
|
let create = false;
|
|
@@ -229,6 +440,34 @@ export function parseArgs(argv) {
|
|
|
229
440
|
}
|
|
230
441
|
return { command: 'fund', open, create, network };
|
|
231
442
|
}
|
|
443
|
+
case 'result': {
|
|
444
|
+
const id = rest[0];
|
|
445
|
+
if (!id || !/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i.test(id))
|
|
446
|
+
return { command: 'error', message: COMMAND_USAGE.result };
|
|
447
|
+
const out = {
|
|
448
|
+
command: 'result',
|
|
449
|
+
id,
|
|
450
|
+
};
|
|
451
|
+
for (let i = 1; i < rest.length; i += 2) {
|
|
452
|
+
const flag = rest[i], value = rest[i + 1];
|
|
453
|
+
if (!value || !['--field', '--offset', '--limit'].includes(flag))
|
|
454
|
+
return { command: 'error', message: COMMAND_USAGE.result };
|
|
455
|
+
if (flag === '--field')
|
|
456
|
+
out.field = value;
|
|
457
|
+
else {
|
|
458
|
+
const n = Number(value);
|
|
459
|
+
if (!Number.isSafeInteger(n) ||
|
|
460
|
+
n < (flag === '--offset' ? 0 : 1) ||
|
|
461
|
+
(flag === '--limit' && n > 100))
|
|
462
|
+
return { command: 'error', message: COMMAND_USAGE.result };
|
|
463
|
+
if (flag === '--offset')
|
|
464
|
+
out.offset = n;
|
|
465
|
+
else
|
|
466
|
+
out.limit = n;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return out;
|
|
470
|
+
}
|
|
232
471
|
case 'transactions': {
|
|
233
472
|
const parsed = takeFormat(rest, 'usage: bags transactions [--limit N] [--cursor C] [--format json|pretty]');
|
|
234
473
|
if ('error' in parsed)
|
|
@@ -439,24 +678,39 @@ Usage:
|
|
|
439
678
|
npx @getbags/cash <command>
|
|
440
679
|
|
|
441
680
|
Workflow: balance → discover|search → check → fetch
|
|
442
|
-
MPP
|
|
681
|
+
MPP: one-shot tempo:charge; new hosted sessions are unavailable
|
|
443
682
|
|
|
444
683
|
Commands:
|
|
445
684
|
redeem <code> Redeem an invite code and save the wallet token
|
|
685
|
+
redeem --test Mint a sandbox wallet (no invite; Base Sepolia + Solana devnet)
|
|
446
686
|
balance Show wallet balance and caps
|
|
447
|
-
${fundLine} discover [query] List BAGS merchant endpoints (BAGS first)
|
|
687
|
+
${fundLine} discover [query] List BAGS merchant endpoints (BAGS first; includes \$0.01 /api/v1)
|
|
448
688
|
search <query> NL search: BAGS catalog + ecosystem index
|
|
449
689
|
check <url> Probe an endpoint for schema + exact quote (no pay)
|
|
450
690
|
fetch <url> [flags] Pay and proxy an x402 / MPP endpoint
|
|
451
|
-
sessions list
|
|
691
|
+
sessions list List existing MPP session reservations
|
|
692
|
+
sessions close <id> Request cleanup; unsupported close preserves the hold
|
|
693
|
+
result <id> [flags] Read retained output without another payment
|
|
452
694
|
transactions List wallet ledger / spend history
|
|
453
695
|
policies get|set Read or update spend policies
|
|
454
696
|
keys create|list|revoke Manage per-agent wallet keys
|
|
455
697
|
register <origin> Register an origin into the discover index
|
|
456
|
-
init
|
|
698
|
+
init [flags] Register MCP + skill + routing rule for detected clients
|
|
699
|
+
mcp Serve wallet tools over stdio (JSON-RPC on stdout)
|
|
700
|
+
doctor [flags] Verify token, MCP registration, skill, and routing rule
|
|
701
|
+
|
|
702
|
+
Init flags:
|
|
703
|
+
--dry-run Print the plan without writing files
|
|
704
|
+
--client <name> Force cursor|claude|codex even without a marker dir (repeatable)
|
|
705
|
+
--scope project|user Config scope (default: user — ambient on this machine)
|
|
706
|
+
|
|
707
|
+
Doctor flags:
|
|
708
|
+
--client <name> Target cursor|claude|codex (repeatable or comma-separated)
|
|
709
|
+
--scope project|user Check one scope (default: both project and user)
|
|
457
710
|
|
|
458
711
|
Hosted skill (prompt paste):
|
|
459
712
|
Set up https://www.getbags.app/wallet/skill.md
|
|
713
|
+
Human install: https://www.getbags.app/wallet/install
|
|
460
714
|
Onboard: https://www.getbags.app/wallet/onboard
|
|
461
715
|
|
|
462
716
|
Fetch / check flags:
|
|
@@ -466,10 +720,17 @@ Fetch / check flags:
|
|
|
466
720
|
--payment-protocol x402|mpp|auto Force rail (default: auto)
|
|
467
721
|
--format json|pretty Machine or human output
|
|
468
722
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
723
|
+
Result flags:
|
|
724
|
+
--field <path> Select a retained field (e.g. response.items)
|
|
725
|
+
--offset <N> Array offset (default: 0)
|
|
726
|
+
--limit <N> Array page size (1–100; default: 20)
|
|
727
|
+
|
|
728
|
+
Sessions (existing holds only; hosted close currently reports unsupported):
|
|
729
|
+
npx @getbags/cash sessions list
|
|
730
|
+
npx @getbags/cash sessions close <id>
|
|
731
|
+
npx @getbags/cash sessions close --all --yes
|
|
732
|
+
|
|
733
|
+
Alias: after \`npm i -g @getbags/cash\`, \`bags\` is equivalent to \`npx @getbags/cash\`.
|
|
473
734
|
|
|
474
735
|
Env:
|
|
475
736
|
BAGS_API_URL API base URL (default: https://www.getbags.app)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side policy patch construction for `bags policies set`.
|
|
3
|
+
*
|
|
4
|
+
* The wallet policies route validates a snake_case PatchSchema
|
|
5
|
+
* (src/app/api/wallet/policies/route.ts). Zod strips unknown keys there, so a
|
|
6
|
+
* misspelled or wrong-case flag used to return 200 with an unchanged policy —
|
|
7
|
+
* a silent no-op. This module normalizes every accepted spelling to
|
|
8
|
+
* snake_case and rejects unrecognized keys before the request leaves the CLI.
|
|
9
|
+
*/
|
|
10
|
+
export declare class PolicyPatchError extends Error {
|
|
11
|
+
constructor(message: string);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Normalize a flag key to the server's snake_case spelling.
|
|
15
|
+
* Accepts kebab-case (`per-call-cap-cents`), camelCase (`perCallCapCents`),
|
|
16
|
+
* and snake_case (`per_call_cap_cents`).
|
|
17
|
+
*/
|
|
18
|
+
export declare function policyKeyToSnake(key: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Build the PATCH body for `bags policies set --key=value ...`.
|
|
21
|
+
*
|
|
22
|
+
* Values coerce like before: integer-looking strings become numbers,
|
|
23
|
+
* `true`/`false` become booleans, anything else stays a string. Unknown keys
|
|
24
|
+
* throw (the server would silently strip them and report success).
|
|
25
|
+
*/
|
|
26
|
+
export declare function policyPatchFromSets(sets: Record<string, string>): Record<string, unknown>;
|
package/dist/policies.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side policy patch construction for `bags policies set`.
|
|
3
|
+
*
|
|
4
|
+
* The wallet policies route validates a snake_case PatchSchema
|
|
5
|
+
* (src/app/api/wallet/policies/route.ts). Zod strips unknown keys there, so a
|
|
6
|
+
* misspelled or wrong-case flag used to return 200 with an unchanged policy —
|
|
7
|
+
* a silent no-op. This module normalizes every accepted spelling to
|
|
8
|
+
* snake_case and rejects unrecognized keys before the request leaves the CLI.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Exact keys the server PatchSchema accepts. Keep in sync with
|
|
12
|
+
* src/app/api/wallet/policies/route.ts.
|
|
13
|
+
*/
|
|
14
|
+
const VALID_POLICY_KEYS = new Set([
|
|
15
|
+
'per_call_cap_cents',
|
|
16
|
+
'daily_cap_cents',
|
|
17
|
+
'weekly_cap_cents',
|
|
18
|
+
'monthly_cap_cents',
|
|
19
|
+
'total_cap_cents',
|
|
20
|
+
'human_approval_threshold_cents',
|
|
21
|
+
'origin_allowlist',
|
|
22
|
+
'origin_blocklist',
|
|
23
|
+
'status',
|
|
24
|
+
]);
|
|
25
|
+
export class PolicyPatchError extends Error {
|
|
26
|
+
constructor(message) {
|
|
27
|
+
super(message);
|
|
28
|
+
this.name = 'PolicyPatchError';
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Normalize a flag key to the server's snake_case spelling.
|
|
33
|
+
* Accepts kebab-case (`per-call-cap-cents`), camelCase (`perCallCapCents`),
|
|
34
|
+
* and snake_case (`per_call_cap_cents`).
|
|
35
|
+
*/
|
|
36
|
+
export function policyKeyToSnake(key) {
|
|
37
|
+
return key
|
|
38
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1_$2')
|
|
39
|
+
.replace(/-/g, '_')
|
|
40
|
+
.toLowerCase();
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Build the PATCH body for `bags policies set --key=value ...`.
|
|
44
|
+
*
|
|
45
|
+
* Values coerce like before: integer-looking strings become numbers,
|
|
46
|
+
* `true`/`false` become booleans, anything else stays a string. Unknown keys
|
|
47
|
+
* throw (the server would silently strip them and report success).
|
|
48
|
+
*/
|
|
49
|
+
export function policyPatchFromSets(sets) {
|
|
50
|
+
const patch = {};
|
|
51
|
+
for (const [key, value] of Object.entries(sets)) {
|
|
52
|
+
const snake = policyKeyToSnake(key);
|
|
53
|
+
if (!VALID_POLICY_KEYS.has(snake)) {
|
|
54
|
+
throw new PolicyPatchError(`unknown policy key: ${key}. ` +
|
|
55
|
+
`Valid keys: ${[...VALID_POLICY_KEYS].join(', ')}. ` +
|
|
56
|
+
`Example: bags policies set --per-call-cap-cents=100`);
|
|
57
|
+
}
|
|
58
|
+
const num = Number(value);
|
|
59
|
+
patch[snake] =
|
|
60
|
+
Number.isFinite(num) && String(num) === value
|
|
61
|
+
? num
|
|
62
|
+
: value === 'true'
|
|
63
|
+
? true
|
|
64
|
+
: value === 'false'
|
|
65
|
+
? false
|
|
66
|
+
: value;
|
|
67
|
+
}
|
|
68
|
+
return patch;
|
|
69
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getbags/cash",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "BAGS Cash CLI
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "BAGS Cash CLI \u2014 hosted agent wallet for x402 (balance \u2192 discover \u2192 check \u2192 fetch)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"bags": "dist/index.js"
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"scripts": {
|
|
17
17
|
"build": "tsc",
|
|
18
18
|
"dev": "tsc --watch",
|
|
19
|
-
"test": "vitest run",
|
|
19
|
+
"test": "bun run build && vitest run",
|
|
20
20
|
"test:watch": "vitest",
|
|
21
21
|
"prepublishOnly": "bun run build"
|
|
22
22
|
},
|
|
@@ -38,9 +38,14 @@
|
|
|
38
38
|
"engines": {
|
|
39
39
|
"node": ">=18"
|
|
40
40
|
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@modelcontextprotocol/sdk": "1.32.1",
|
|
43
|
+
"zod": "^4.6.5"
|
|
44
|
+
},
|
|
41
45
|
"devDependencies": {
|
|
42
46
|
"@types/node": "^25.0.3",
|
|
43
47
|
"typescript": "6.0.2",
|
|
44
|
-
"vitest": "^
|
|
45
|
-
}
|
|
48
|
+
"vitest": "^5.0.3"
|
|
49
|
+
},
|
|
50
|
+
"packageManager": "bun@1.4.2"
|
|
46
51
|
}
|