@caypo/canton-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/.turbo/turbo-build.log +14 -0
- package/.turbo/turbo-test.log +12 -0
- package/README.md +101 -0
- package/SPEC.md +41 -0
- package/dist/index.js +468 -0
- package/dist/index.js.map +1 -0
- package/package.json +59 -0
- package/src/commands/address.ts +23 -0
- package/src/commands/balance.ts +32 -0
- package/src/commands/init.ts +141 -0
- package/src/commands/mcp.ts +105 -0
- package/src/commands/pay.ts +53 -0
- package/src/commands/safeguards.ts +107 -0
- package/src/commands/send.ts +36 -0
- package/src/commands/traffic.ts +49 -0
- package/src/helpers/format.ts +29 -0
- package/src/helpers/load-agent.ts +28 -0
- package/src/index.ts +35 -0
- package/tsconfig.json +8 -0
- package/tsup.config.ts +12 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
|
|
2
|
+
> @caypo/canton-cli@0.1.0 build /Users/anil/Desktop/caypo/packages/cli
|
|
3
|
+
> tsup
|
|
4
|
+
|
|
5
|
+
CLI Building entry: src/index.ts
|
|
6
|
+
CLI Using tsconfig: tsconfig.json
|
|
7
|
+
CLI tsup v8.5.1
|
|
8
|
+
CLI Using tsup config: /Users/anil/Desktop/caypo/packages/cli/tsup.config.ts
|
|
9
|
+
CLI Target: es2022
|
|
10
|
+
CLI Cleaning output folder
|
|
11
|
+
ESM Build start
|
|
12
|
+
ESM dist/index.js 16.09 KB
|
|
13
|
+
ESM dist/index.js.map 32.52 KB
|
|
14
|
+
ESM ⚡️ Build success in 11ms
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
|
|
2
|
+
> @caypo/canton-cli@0.1.0 test /Users/anil/Desktop/caypo/packages/cli
|
|
3
|
+
> vitest run
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
RUN v3.2.4 /Users/anil/Desktop/caypo/packages/cli
|
|
7
|
+
|
|
8
|
+
No test files found, exiting with code 0
|
|
9
|
+
|
|
10
|
+
include: **/*.{test,spec}.?(c|m)[jt]s?(x)
|
|
11
|
+
exclude: **/node_modules/**, **/dist/**, **/cypress/**, **/.{idea,git,cache,output,temp}/**, **/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build,eslint,prettier}.config.*
|
|
12
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# @caypo/canton-cli
|
|
2
|
+
|
|
3
|
+
**CLI for AI agent banking on [Canton Network](https://canton.network)**
|
|
4
|
+
|
|
5
|
+
Manage your USDCx wallet, send payments, pay for APIs, and configure MCP server — all from the terminal.
|
|
6
|
+
|
|
7
|
+
[](../../LICENSE-APACHE)
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install -g @caypo/canton-cli
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Commands
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
SETUP
|
|
19
|
+
caypo init Set up wallet (PIN, ledger URL, JWT, party)
|
|
20
|
+
caypo address Show your Canton party ID
|
|
21
|
+
caypo balance Show USDCx balance and holdings
|
|
22
|
+
|
|
23
|
+
PAYMENTS
|
|
24
|
+
caypo send <amount> to <recipient> Send USDCx to a party
|
|
25
|
+
caypo pay <url> [--max-price N] Pay for API (auto 402 flow)
|
|
26
|
+
|
|
27
|
+
SAFEGUARDS
|
|
28
|
+
caypo safeguards View spending limits
|
|
29
|
+
caypo safeguards set-tx-limit <amt> Set per-transaction limit
|
|
30
|
+
caypo safeguards set-daily-limit <amt> Set daily spending limit
|
|
31
|
+
caypo safeguards lock Lock wallet
|
|
32
|
+
caypo safeguards unlock Unlock wallet
|
|
33
|
+
|
|
34
|
+
TRAFFIC
|
|
35
|
+
caypo traffic Validator traffic balance
|
|
36
|
+
|
|
37
|
+
MCP
|
|
38
|
+
caypo mcp install Install for Claude/Cursor/Windsurf
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Examples
|
|
42
|
+
|
|
43
|
+
### Set up a new wallet
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
$ caypo init
|
|
47
|
+
|
|
48
|
+
CAYPO — A bank account for AI agents on Canton Network
|
|
49
|
+
|
|
50
|
+
? Choose a PIN for your wallet: ****
|
|
51
|
+
? Confirm PIN: ****
|
|
52
|
+
? Canton Ledger URL: http://localhost:7575
|
|
53
|
+
? JWT bearer token: ****
|
|
54
|
+
? Agent display name: MyAgent
|
|
55
|
+
|
|
56
|
+
[OK] Party allocated
|
|
57
|
+
[OK] Keystore created
|
|
58
|
+
|
|
59
|
+
Party ID: MyAgent::1220abcdef...
|
|
60
|
+
Config: ~/.caypo/config.json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Check balance
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
$ caypo balance
|
|
67
|
+
|
|
68
|
+
Checking Account
|
|
69
|
+
|
|
70
|
+
Balance: 50.00 USDCx
|
|
71
|
+
Holdings: 3 UTXOs
|
|
72
|
+
Address: MyAgent::1220abcdef...
|
|
73
|
+
Network: testnet
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Pay for an API call
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
$ caypo pay https://mpp.cayvox.io/openai/v1/chat/completions --max-price 0.05
|
|
80
|
+
|
|
81
|
+
[OK] Paid 0.01 USDCx for API access
|
|
82
|
+
Update ID: upd-abc123
|
|
83
|
+
Status: 200
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Install MCP server
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
$ caypo mcp install
|
|
90
|
+
|
|
91
|
+
[OK] Claude Desktop
|
|
92
|
+
[OK] Cursor
|
|
93
|
+
[OK] Windsurf
|
|
94
|
+
|
|
95
|
+
MCP server installed for 3 tools.
|
|
96
|
+
Restart your AI tool to activate.
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## License
|
|
100
|
+
|
|
101
|
+
Apache-2.0 OR MIT
|
package/SPEC.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# @cayvox/canton-cli — CLI Specification (Production)
|
|
2
|
+
|
|
3
|
+
Binary: `canton-agent` (alias: `ca`)
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
SETUP
|
|
9
|
+
init Interactive: PIN, ledger URL, JWT, party allocation, MCP
|
|
10
|
+
address Party ID (e.g., Agent::1220abcd...)
|
|
11
|
+
balance All account balances
|
|
12
|
+
config Show/edit configuration
|
|
13
|
+
mcp install Install MCP server for Claude/Cursor/Windsurf
|
|
14
|
+
export-key Export private key (requires PIN)
|
|
15
|
+
|
|
16
|
+
CHECKING
|
|
17
|
+
send <amount> to <recipient> Send USDCx (party ID or ANS name)
|
|
18
|
+
history [--limit N] Transaction history
|
|
19
|
+
|
|
20
|
+
MPP PAYMENTS
|
|
21
|
+
pay <url> [--data json] [--method POST] [--max-price amount]
|
|
22
|
+
|
|
23
|
+
SAFEGUARDS
|
|
24
|
+
safeguards Show settings
|
|
25
|
+
safeguards set-tx-limit <amount>
|
|
26
|
+
safeguards set-daily-limit <amount>
|
|
27
|
+
safeguards lock / unlock
|
|
28
|
+
|
|
29
|
+
TRAFFIC
|
|
30
|
+
traffic Validator traffic balance
|
|
31
|
+
traffic purchase <cc-amount> Buy traffic with CC
|
|
32
|
+
|
|
33
|
+
PHASE 3+ (stubs in v1)
|
|
34
|
+
save, withdraw, rebalance, earnings
|
|
35
|
+
borrow, repay, health
|
|
36
|
+
exchange, rates
|
|
37
|
+
invest buy/sell/earn/strategy/auto/portfolio
|
|
38
|
+
claim-rewards
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Technology: commander + chalk + ora + inquirer
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Command as Command9 } from "commander";
|
|
5
|
+
|
|
6
|
+
// src/commands/init.ts
|
|
7
|
+
import { Command } from "commander";
|
|
8
|
+
import inquirer from "inquirer";
|
|
9
|
+
import ora from "ora";
|
|
10
|
+
import chalk2 from "chalk";
|
|
11
|
+
import {
|
|
12
|
+
CantonClient,
|
|
13
|
+
Keystore,
|
|
14
|
+
saveConfig,
|
|
15
|
+
DEFAULT_CONFIG,
|
|
16
|
+
SafeguardManager
|
|
17
|
+
} from "@caypo/canton-sdk";
|
|
18
|
+
|
|
19
|
+
// src/helpers/format.ts
|
|
20
|
+
import chalk from "chalk";
|
|
21
|
+
var label = (text) => chalk.gray(text);
|
|
22
|
+
var value = (text) => chalk.white.bold(text);
|
|
23
|
+
var success = (text) => chalk.green(text);
|
|
24
|
+
var warn = (text) => chalk.yellow(text);
|
|
25
|
+
var fail = (text) => chalk.red(text);
|
|
26
|
+
var accent = (text) => chalk.cyan(text);
|
|
27
|
+
var dim = (text) => chalk.dim(text);
|
|
28
|
+
function banner() {
|
|
29
|
+
console.log(chalk.cyan.bold("\n CAYPO") + chalk.gray(" \u2014 A bank account for AI agents on Canton Network\n"));
|
|
30
|
+
}
|
|
31
|
+
function keyValue(key, val) {
|
|
32
|
+
console.log(` ${label(key + ":")} ${value(val)}`);
|
|
33
|
+
}
|
|
34
|
+
function errorMessage(msg) {
|
|
35
|
+
console.log(`
|
|
36
|
+
${fail("\u2717")} ${msg}
|
|
37
|
+
`);
|
|
38
|
+
}
|
|
39
|
+
function successMessage(msg) {
|
|
40
|
+
console.log(`
|
|
41
|
+
${success("\u2713")} ${msg}
|
|
42
|
+
`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/commands/init.ts
|
|
46
|
+
var initCommand = new Command("init").description("Interactive wallet setup \u2014 create keystore, allocate party").action(async () => {
|
|
47
|
+
banner();
|
|
48
|
+
console.log(chalk2.gray(" Setting up your Canton agent wallet...\n"));
|
|
49
|
+
try {
|
|
50
|
+
const { pin } = await inquirer.prompt([
|
|
51
|
+
{
|
|
52
|
+
type: "password",
|
|
53
|
+
name: "pin",
|
|
54
|
+
message: "Choose a PIN for your wallet:",
|
|
55
|
+
mask: "*",
|
|
56
|
+
validate: (v) => v.length >= 4 || "PIN must be at least 4 characters"
|
|
57
|
+
}
|
|
58
|
+
]);
|
|
59
|
+
const { confirmPin } = await inquirer.prompt([
|
|
60
|
+
{
|
|
61
|
+
type: "password",
|
|
62
|
+
name: "confirmPin",
|
|
63
|
+
message: "Confirm PIN:",
|
|
64
|
+
mask: "*",
|
|
65
|
+
validate: (v) => v === pin || "PINs do not match"
|
|
66
|
+
}
|
|
67
|
+
]);
|
|
68
|
+
const { ledgerUrl } = await inquirer.prompt([
|
|
69
|
+
{
|
|
70
|
+
type: "input",
|
|
71
|
+
name: "ledgerUrl",
|
|
72
|
+
message: "Canton Ledger URL:",
|
|
73
|
+
default: "http://localhost:7575"
|
|
74
|
+
}
|
|
75
|
+
]);
|
|
76
|
+
const { jwt } = await inquirer.prompt([
|
|
77
|
+
{
|
|
78
|
+
type: "password",
|
|
79
|
+
name: "jwt",
|
|
80
|
+
message: "JWT bearer token:",
|
|
81
|
+
mask: "*",
|
|
82
|
+
validate: (v) => v.length > 0 || "JWT is required"
|
|
83
|
+
}
|
|
84
|
+
]);
|
|
85
|
+
const { userId } = await inquirer.prompt([
|
|
86
|
+
{
|
|
87
|
+
type: "input",
|
|
88
|
+
name: "userId",
|
|
89
|
+
message: "Ledger API user ID:",
|
|
90
|
+
default: "ledger-api-user"
|
|
91
|
+
}
|
|
92
|
+
]);
|
|
93
|
+
const { displayName } = await inquirer.prompt([
|
|
94
|
+
{
|
|
95
|
+
type: "input",
|
|
96
|
+
name: "displayName",
|
|
97
|
+
message: "Agent display name:",
|
|
98
|
+
default: "Agent"
|
|
99
|
+
}
|
|
100
|
+
]);
|
|
101
|
+
const spinner = ora("Allocating party on Canton ledger...").start();
|
|
102
|
+
const client = new CantonClient({ ledgerUrl, token: jwt, userId });
|
|
103
|
+
let partyId;
|
|
104
|
+
try {
|
|
105
|
+
const party = await client.allocateParty(displayName);
|
|
106
|
+
partyId = party.party;
|
|
107
|
+
spinner.succeed("Party allocated");
|
|
108
|
+
} catch (err) {
|
|
109
|
+
spinner.fail("Failed to allocate party");
|
|
110
|
+
errorMessage(err.message);
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
const keystoreSpinner = ora("Creating encrypted keystore...").start();
|
|
114
|
+
await Keystore.create(pin, { partyId, jwt, userId });
|
|
115
|
+
keystoreSpinner.succeed("Keystore created");
|
|
116
|
+
const config = {
|
|
117
|
+
...DEFAULT_CONFIG,
|
|
118
|
+
ledgerUrl,
|
|
119
|
+
partyId,
|
|
120
|
+
userId
|
|
121
|
+
};
|
|
122
|
+
await saveConfig(config);
|
|
123
|
+
const safeguards = new SafeguardManager();
|
|
124
|
+
safeguards.setTxLimit(DEFAULT_CONFIG.safeguards.txLimit);
|
|
125
|
+
safeguards.setDailyLimit(DEFAULT_CONFIG.safeguards.dailyLimit);
|
|
126
|
+
console.log("");
|
|
127
|
+
successMessage("Canton agent wallet created successfully!");
|
|
128
|
+
console.log("");
|
|
129
|
+
keyValue("Party ID", accent(partyId));
|
|
130
|
+
keyValue("Ledger URL", ledgerUrl);
|
|
131
|
+
keyValue("Config", "~/.caypo/config.json");
|
|
132
|
+
keyValue("Keystore", "~/.caypo/wallet.key");
|
|
133
|
+
console.log("");
|
|
134
|
+
console.log(chalk2.gray(" Next steps:"));
|
|
135
|
+
console.log(chalk2.gray(" caypo balance \u2014 Check your balance"));
|
|
136
|
+
console.log(chalk2.gray(" caypo mcp install \u2014 Install MCP server for AI tools"));
|
|
137
|
+
console.log(chalk2.gray(" caypo send 1 to <party> \u2014 Send USDCx"));
|
|
138
|
+
console.log("");
|
|
139
|
+
} catch (err) {
|
|
140
|
+
errorMessage(`Setup failed: ${err.message}`);
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// src/commands/balance.ts
|
|
146
|
+
import { Command as Command2 } from "commander";
|
|
147
|
+
import chalk3 from "chalk";
|
|
148
|
+
import ora2 from "ora";
|
|
149
|
+
|
|
150
|
+
// src/helpers/load-agent.ts
|
|
151
|
+
import { CantonAgent, loadConfig } from "@caypo/canton-sdk";
|
|
152
|
+
async function loadAgent() {
|
|
153
|
+
try {
|
|
154
|
+
const config = await loadConfig();
|
|
155
|
+
if (!config.partyId) {
|
|
156
|
+
errorMessage("No wallet configured. Run 'caypo init' first.");
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
return CantonAgent.create({
|
|
160
|
+
ledgerUrl: config.ledgerUrl,
|
|
161
|
+
partyId: config.partyId,
|
|
162
|
+
userId: config.userId,
|
|
163
|
+
network: config.network,
|
|
164
|
+
token: process.env.CANTON_JWT ?? ""
|
|
165
|
+
});
|
|
166
|
+
} catch (err) {
|
|
167
|
+
errorMessage(`Failed to load agent: ${err.message}`);
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// src/commands/balance.ts
|
|
173
|
+
var balanceCommand = new Command2("balance").description("Show USDCx checking balance").action(async () => {
|
|
174
|
+
banner();
|
|
175
|
+
const spinner = ora2("Fetching balance...").start();
|
|
176
|
+
try {
|
|
177
|
+
const agent = await loadAgent();
|
|
178
|
+
const bal = await agent.checking.balance();
|
|
179
|
+
spinner.stop();
|
|
180
|
+
console.log(chalk3.gray(" Checking Account\n"));
|
|
181
|
+
keyValue("Balance", accent(`${bal.available} USDCx`));
|
|
182
|
+
keyValue("Holdings", `${bal.holdingCount} UTXO${bal.holdingCount !== 1 ? "s" : ""}`);
|
|
183
|
+
keyValue("Address", agent.wallet.address);
|
|
184
|
+
keyValue("Network", agent.wallet.network);
|
|
185
|
+
console.log("");
|
|
186
|
+
} catch (err) {
|
|
187
|
+
spinner.fail(`Failed to fetch balance: ${err.message}`);
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// src/commands/send.ts
|
|
193
|
+
import { Command as Command3 } from "commander";
|
|
194
|
+
import ora3 from "ora";
|
|
195
|
+
var sendCommand = new Command3("send").description("Send USDCx to a recipient").argument("<amount>", "Amount of USDCx to send").argument("to", "Literal 'to' keyword").argument("<recipient>", "Recipient party ID").option("--memo <memo>", "Optional memo").action(async (amount, _to, recipient, opts) => {
|
|
196
|
+
banner();
|
|
197
|
+
const spinner = ora3(`Sending ${amount} USDCx to ${recipient}...`).start();
|
|
198
|
+
try {
|
|
199
|
+
const agent = await loadAgent();
|
|
200
|
+
const result = await agent.checking.send(recipient, amount, { memo: opts.memo });
|
|
201
|
+
spinner.stop();
|
|
202
|
+
successMessage(`Sent ${accent(amount + " USDCx")} successfully!`);
|
|
203
|
+
keyValue("Recipient", recipient);
|
|
204
|
+
keyValue("Update ID", result.updateId);
|
|
205
|
+
keyValue("Offset", String(result.completionOffset));
|
|
206
|
+
keyValue("Command ID", result.commandId);
|
|
207
|
+
console.log("");
|
|
208
|
+
} catch (err) {
|
|
209
|
+
spinner.fail("Transfer failed");
|
|
210
|
+
errorMessage(err.message);
|
|
211
|
+
process.exit(1);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// src/commands/pay.ts
|
|
216
|
+
import { Command as Command4 } from "commander";
|
|
217
|
+
import ora4 from "ora";
|
|
218
|
+
var payCommand = new Command4("pay").description("Pay for an API call via MPP (402 auto-pay)").argument("<url>", "URL to fetch").option("-d, --data <json>", "Request body (JSON)").option("-X, --method <method>", "HTTP method", "GET").option("--max-price <amount>", "Maximum price to pay").action(async (url, opts) => {
|
|
219
|
+
banner();
|
|
220
|
+
const spinner = ora4(`Fetching ${url}...`).start();
|
|
221
|
+
try {
|
|
222
|
+
const agent = await loadAgent();
|
|
223
|
+
const result = await agent.mpp.pay(url, {
|
|
224
|
+
method: opts.method,
|
|
225
|
+
body: opts.data,
|
|
226
|
+
maxPrice: opts.maxPrice,
|
|
227
|
+
headers: opts.data ? { "Content-Type": "application/json" } : void 0
|
|
228
|
+
});
|
|
229
|
+
spinner.stop();
|
|
230
|
+
if (result.paid) {
|
|
231
|
+
successMessage(`Paid ${accent(result.receipt.amount + " USDCx")} for API access`);
|
|
232
|
+
keyValue("Update ID", result.receipt.updateId);
|
|
233
|
+
keyValue("Command ID", result.receipt.commandId);
|
|
234
|
+
} else {
|
|
235
|
+
console.log(dim(" No payment required (non-402 response)"));
|
|
236
|
+
}
|
|
237
|
+
keyValue("Status", String(result.response.status));
|
|
238
|
+
const body = await result.response.text();
|
|
239
|
+
if (body) {
|
|
240
|
+
console.log(dim("\n Response:"));
|
|
241
|
+
console.log(dim(" " + body.slice(0, 500)));
|
|
242
|
+
if (body.length > 500) console.log(dim(" ... (truncated)"));
|
|
243
|
+
}
|
|
244
|
+
console.log("");
|
|
245
|
+
} catch (err) {
|
|
246
|
+
spinner.fail("Payment failed");
|
|
247
|
+
errorMessage(err.message);
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// src/commands/address.ts
|
|
253
|
+
import { Command as Command5 } from "commander";
|
|
254
|
+
var addressCommand = new Command5("address").description("Show your Canton party ID (address)").action(async () => {
|
|
255
|
+
banner();
|
|
256
|
+
try {
|
|
257
|
+
const agent = await loadAgent();
|
|
258
|
+
keyValue("Party ID", agent.wallet.address);
|
|
259
|
+
keyValue("Network", agent.wallet.network);
|
|
260
|
+
console.log("");
|
|
261
|
+
} catch (err) {
|
|
262
|
+
console.error(err.message);
|
|
263
|
+
process.exit(1);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// src/commands/safeguards.ts
|
|
268
|
+
import { Command as Command6 } from "commander";
|
|
269
|
+
import inquirer2 from "inquirer";
|
|
270
|
+
import chalk4 from "chalk";
|
|
271
|
+
import { SafeguardManager as SafeguardManager2 } from "@caypo/canton-sdk";
|
|
272
|
+
var safeguardsCommand = new Command6("safeguards").description("View and manage safeguard settings").action(async () => {
|
|
273
|
+
banner();
|
|
274
|
+
try {
|
|
275
|
+
const mgr = await SafeguardManager2.load();
|
|
276
|
+
const s = mgr.settings();
|
|
277
|
+
console.log(chalk4.gray(" Safeguard Settings\n"));
|
|
278
|
+
keyValue("Per-tx limit", accent(s.txLimit + " USDCx"));
|
|
279
|
+
keyValue("Daily limit", accent(s.dailyLimit + " USDCx"));
|
|
280
|
+
keyValue("Daily spent", s.dailySpent + " USDCx");
|
|
281
|
+
keyValue("Locked", s.locked ? warn("YES") : "no");
|
|
282
|
+
keyValue("Last reset", s.lastResetDate);
|
|
283
|
+
console.log("");
|
|
284
|
+
} catch (err) {
|
|
285
|
+
errorMessage(err.message);
|
|
286
|
+
process.exit(1);
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
safeguardsCommand.command("set-tx-limit").argument("<amount>", "Per-transaction limit in USDCx").description("Set per-transaction spending limit").action(async (amount) => {
|
|
290
|
+
try {
|
|
291
|
+
const mgr = await SafeguardManager2.load();
|
|
292
|
+
mgr.setTxLimit(amount);
|
|
293
|
+
successMessage(`Per-transaction limit set to ${accent(amount + " USDCx")}`);
|
|
294
|
+
} catch (err) {
|
|
295
|
+
errorMessage(err.message);
|
|
296
|
+
process.exit(1);
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
safeguardsCommand.command("set-daily-limit").argument("<amount>", "Daily spending limit in USDCx").description("Set daily spending limit").action(async (amount) => {
|
|
300
|
+
try {
|
|
301
|
+
const mgr = await SafeguardManager2.load();
|
|
302
|
+
mgr.setDailyLimit(amount);
|
|
303
|
+
successMessage(`Daily limit set to ${accent(amount + " USDCx")}`);
|
|
304
|
+
} catch (err) {
|
|
305
|
+
errorMessage(err.message);
|
|
306
|
+
process.exit(1);
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
safeguardsCommand.command("lock").description("Lock wallet \u2014 all transactions will be rejected").action(async () => {
|
|
310
|
+
try {
|
|
311
|
+
const { pin } = await inquirer2.prompt([
|
|
312
|
+
{
|
|
313
|
+
type: "password",
|
|
314
|
+
name: "pin",
|
|
315
|
+
message: "Set lock PIN:",
|
|
316
|
+
mask: "*"
|
|
317
|
+
}
|
|
318
|
+
]);
|
|
319
|
+
const mgr = await SafeguardManager2.load();
|
|
320
|
+
mgr.lock(pin);
|
|
321
|
+
successMessage("Wallet locked");
|
|
322
|
+
} catch (err) {
|
|
323
|
+
errorMessage(err.message);
|
|
324
|
+
process.exit(1);
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
safeguardsCommand.command("unlock").description("Unlock wallet").action(async () => {
|
|
328
|
+
try {
|
|
329
|
+
const { pin } = await inquirer2.prompt([
|
|
330
|
+
{
|
|
331
|
+
type: "password",
|
|
332
|
+
name: "pin",
|
|
333
|
+
message: "Enter lock PIN:",
|
|
334
|
+
mask: "*"
|
|
335
|
+
}
|
|
336
|
+
]);
|
|
337
|
+
const mgr = await SafeguardManager2.load();
|
|
338
|
+
mgr.unlock(pin);
|
|
339
|
+
successMessage("Wallet unlocked");
|
|
340
|
+
} catch (err) {
|
|
341
|
+
errorMessage(err.message);
|
|
342
|
+
process.exit(1);
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
// src/commands/traffic.ts
|
|
347
|
+
import { Command as Command7 } from "commander";
|
|
348
|
+
import ora5 from "ora";
|
|
349
|
+
import chalk5 from "chalk";
|
|
350
|
+
var trafficCommand = new Command7("traffic").description("Show validator traffic balance").action(async () => {
|
|
351
|
+
banner();
|
|
352
|
+
const spinner = ora5("Checking traffic balance...").start();
|
|
353
|
+
try {
|
|
354
|
+
const agent = await loadAgent();
|
|
355
|
+
const balance = await agent.traffic.trafficBalance();
|
|
356
|
+
const sufficient = balance.remaining > 1e3;
|
|
357
|
+
spinner.stop();
|
|
358
|
+
console.log(chalk5.gray(" Validator Traffic\n"));
|
|
359
|
+
keyValue("Total purchased", accent(String(balance.totalPurchased)));
|
|
360
|
+
keyValue("Consumed", String(balance.consumed));
|
|
361
|
+
keyValue("Remaining", sufficient ? accent(String(balance.remaining)) : warn(String(balance.remaining)));
|
|
362
|
+
keyValue("Status", sufficient ? "Sufficient" : warn("Low \u2014 consider purchasing more"));
|
|
363
|
+
console.log("");
|
|
364
|
+
} catch (err) {
|
|
365
|
+
spinner.fail(`Failed: ${err.message}`);
|
|
366
|
+
process.exit(1);
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
trafficCommand.command("purchase").argument("<cc-amount>", "Canton Coin amount to burn for traffic").description("Purchase additional traffic by burning CC").action(async (ccAmount) => {
|
|
370
|
+
const spinner = ora5(`Purchasing traffic with ${ccAmount} CC...`).start();
|
|
371
|
+
try {
|
|
372
|
+
const agent = await loadAgent();
|
|
373
|
+
await agent.traffic.purchaseTraffic(ccAmount);
|
|
374
|
+
spinner.succeed("Traffic purchased");
|
|
375
|
+
} catch (err) {
|
|
376
|
+
spinner.fail(`Purchase failed: ${err.message}`);
|
|
377
|
+
process.exit(1);
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
// src/commands/mcp.ts
|
|
382
|
+
import { Command as Command8 } from "commander";
|
|
383
|
+
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
384
|
+
import { join } from "path";
|
|
385
|
+
import { homedir, platform } from "os";
|
|
386
|
+
import chalk6 from "chalk";
|
|
387
|
+
var MCP_ENTRY = {
|
|
388
|
+
command: "npx",
|
|
389
|
+
args: ["@caypo/canton-mcp"],
|
|
390
|
+
env: { CANTON_AGENT_CONFIG: join(homedir(), ".caypo", "config.json") }
|
|
391
|
+
};
|
|
392
|
+
function getConfigPaths() {
|
|
393
|
+
const home = homedir();
|
|
394
|
+
const os = platform();
|
|
395
|
+
const paths = [];
|
|
396
|
+
if (os === "darwin") {
|
|
397
|
+
paths.push(
|
|
398
|
+
{ name: "Claude Desktop", path: join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json") },
|
|
399
|
+
{ name: "Cursor", path: join(home, ".cursor", "mcp.json") },
|
|
400
|
+
{ name: "Windsurf", path: join(home, ".windsurf", "mcp.json") }
|
|
401
|
+
);
|
|
402
|
+
} else if (os === "linux") {
|
|
403
|
+
paths.push(
|
|
404
|
+
{ name: "Claude Desktop", path: join(home, ".config", "Claude", "claude_desktop_config.json") },
|
|
405
|
+
{ name: "Cursor", path: join(home, ".cursor", "mcp.json") },
|
|
406
|
+
{ name: "Windsurf", path: join(home, ".windsurf", "mcp.json") }
|
|
407
|
+
);
|
|
408
|
+
} else {
|
|
409
|
+
const appData = process.env.APPDATA ?? join(home, "AppData", "Roaming");
|
|
410
|
+
paths.push(
|
|
411
|
+
{ name: "Claude Desktop", path: join(appData, "Claude", "claude_desktop_config.json") },
|
|
412
|
+
{ name: "Cursor", path: join(home, ".cursor", "mcp.json") },
|
|
413
|
+
{ name: "Windsurf", path: join(home, ".windsurf", "mcp.json") }
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
return paths;
|
|
417
|
+
}
|
|
418
|
+
async function installToConfig(configPath) {
|
|
419
|
+
let config;
|
|
420
|
+
try {
|
|
421
|
+
const raw = await readFile(configPath, "utf8");
|
|
422
|
+
config = JSON.parse(raw);
|
|
423
|
+
} catch {
|
|
424
|
+
config = { mcpServers: {} };
|
|
425
|
+
}
|
|
426
|
+
if (!config.mcpServers) {
|
|
427
|
+
config.mcpServers = {};
|
|
428
|
+
}
|
|
429
|
+
config.mcpServers["caypo"] = MCP_ENTRY;
|
|
430
|
+
await mkdir(join(configPath, ".."), { recursive: true });
|
|
431
|
+
await writeFile(configPath, JSON.stringify(config, null, 2), "utf8");
|
|
432
|
+
return true;
|
|
433
|
+
}
|
|
434
|
+
var mcpCommand = new Command8("mcp").description("MCP server management");
|
|
435
|
+
mcpCommand.command("install").description("Install MCP server config for Claude Desktop, Cursor, Windsurf").action(async () => {
|
|
436
|
+
console.log(chalk6.gray("\n Installing CAYPO MCP server configuration...\n"));
|
|
437
|
+
const configs = getConfigPaths();
|
|
438
|
+
let installed = 0;
|
|
439
|
+
for (const { name, path } of configs) {
|
|
440
|
+
try {
|
|
441
|
+
await installToConfig(path);
|
|
442
|
+
console.log(` ${chalk6.green("\u2713")} ${name} ${dim(path)}`);
|
|
443
|
+
installed++;
|
|
444
|
+
} catch (err) {
|
|
445
|
+
console.log(` ${chalk6.yellow("\u26A0")} ${name} \u2014 ${dim(err.message)}`);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
if (installed > 0) {
|
|
449
|
+
successMessage(`MCP server installed for ${installed} tool${installed > 1 ? "s" : ""}`);
|
|
450
|
+
console.log(chalk6.gray(" Restart your AI tool to activate the MCP server."));
|
|
451
|
+
console.log(chalk6.gray(" The server provides 33 tools and 20 prompts for Canton banking.\n"));
|
|
452
|
+
} else {
|
|
453
|
+
errorMessage("No AI tool configs found. Install manually.");
|
|
454
|
+
console.log(chalk6.gray(" Add this to your MCP config:\n"));
|
|
455
|
+
console.log(chalk6.gray(" " + JSON.stringify({ caypo: MCP_ENTRY }, null, 2).replace(/\n/g, "\n ")));
|
|
456
|
+
console.log("");
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
// src/index.ts
|
|
461
|
+
var CANTON_CLI_VERSION = "0.1.0";
|
|
462
|
+
var program = new Command9();
|
|
463
|
+
program.name("caypo").description("CAYPO \u2014 A bank account for AI agents on Canton Network").version(CANTON_CLI_VERSION, "-v, --version").addCommand(initCommand).addCommand(balanceCommand).addCommand(sendCommand).addCommand(payCommand).addCommand(addressCommand).addCommand(safeguardsCommand).addCommand(trafficCommand).addCommand(mcpCommand);
|
|
464
|
+
program.parse(process.argv);
|
|
465
|
+
export {
|
|
466
|
+
CANTON_CLI_VERSION
|
|
467
|
+
};
|
|
468
|
+
//# sourceMappingURL=index.js.map
|