@agentis-hq/cli 0.1.7 → 0.3.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/README.md +4 -2
- package/dist/index.js +235 -72
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,7 +43,9 @@ AGENTIS_API_URL=http://localhost:3001 agentis wallet list
|
|
|
43
43
|
|
|
44
44
|
## Authentication
|
|
45
45
|
|
|
46
|
-
Hosted wallets and hosted agents require
|
|
46
|
+
Hosted wallets and hosted agents require authentication. The CLI uses OAuth
|
|
47
|
+
authorization code flow with PKCE and stores its access and refresh credentials
|
|
48
|
+
in the OS keychain.
|
|
47
49
|
|
|
48
50
|
```bash
|
|
49
51
|
agentis login
|
|
@@ -278,7 +280,7 @@ AGENTIS_API_URL=http://localhost:3001 bun src/index.ts wallet list
|
|
|
278
280
|
## Notes
|
|
279
281
|
|
|
280
282
|
- Hosted agent keys are shown only when created or regenerated.
|
|
281
|
-
- CLI
|
|
283
|
+
- CLI OAuth credentials are stored in the OS keychain.
|
|
282
284
|
- Local wallet vaults live under `~/.agentis/wallets/`.
|
|
283
285
|
- Jupiter Earn commands require mainnet and the `--mainnet` safety flag.
|
|
284
286
|
- Umbra devnet flows are currently safest with SOL or wSOL.
|
package/dist/index.js
CHANGED
|
@@ -5,99 +5,230 @@ import { readFileSync as readFileSync2 } from "fs";
|
|
|
5
5
|
import { dirname as dirname2, join as join3 } from "path";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
7
|
|
|
8
|
+
// src/commands/auth.ts
|
|
9
|
+
import { createHash, randomBytes } from "crypto";
|
|
10
|
+
import { execFile } from "child_process";
|
|
11
|
+
|
|
12
|
+
// src/lib/config.ts
|
|
13
|
+
var API_BASE = process.env.AGENTIS_API_URL ?? "https://api.agentis.systems";
|
|
14
|
+
async function apiFetch(path, opts = {}, token) {
|
|
15
|
+
const headers = {
|
|
16
|
+
"content-type": "application/json",
|
|
17
|
+
...opts.headers ?? {}
|
|
18
|
+
};
|
|
19
|
+
if (token) headers["authorization"] = `Bearer ${token}`;
|
|
20
|
+
return fetch(`${API_BASE}${path}`, { ...opts, headers });
|
|
21
|
+
}
|
|
22
|
+
|
|
8
23
|
// src/lib/keychain.ts
|
|
9
24
|
import { Entry } from "@napi-rs/keyring";
|
|
10
25
|
var entry = new Entry("agentis-cli", "account-key");
|
|
11
|
-
|
|
12
|
-
entry.setPassword(token);
|
|
13
|
-
}
|
|
14
|
-
async function getToken() {
|
|
15
|
-
if (process.env.AGENTIS_ACCOUNT_KEY) return process.env.AGENTIS_ACCOUNT_KEY;
|
|
26
|
+
function readPassword() {
|
|
16
27
|
try {
|
|
17
28
|
return entry.getPassword();
|
|
18
29
|
} catch {
|
|
19
30
|
return null;
|
|
20
31
|
}
|
|
21
32
|
}
|
|
22
|
-
async function
|
|
33
|
+
async function saveOAuthCredentials(credentials) {
|
|
34
|
+
entry.setPassword(JSON.stringify(credentials));
|
|
35
|
+
}
|
|
36
|
+
async function getStoredCredentials() {
|
|
37
|
+
const envToken = process.env.AGENTIS_ACCOUNT_KEY;
|
|
38
|
+
if (envToken) return { type: "legacy", token: envToken };
|
|
39
|
+
const stored = readPassword();
|
|
40
|
+
if (!stored) return null;
|
|
41
|
+
if (!stored.startsWith("{")) return { type: "legacy", token: stored };
|
|
23
42
|
try {
|
|
24
|
-
|
|
43
|
+
const credentials = JSON.parse(stored);
|
|
44
|
+
if (credentials.version === 2 && credentials.accessToken?.startsWith("agt_oauth_") && credentials.refreshToken?.startsWith("agt_refresh_")) {
|
|
45
|
+
return { type: "oauth", credentials };
|
|
46
|
+
}
|
|
25
47
|
} catch {
|
|
26
48
|
}
|
|
49
|
+
return null;
|
|
27
50
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
51
|
+
async function refresh(credentials) {
|
|
52
|
+
const response = await fetch(`${API_BASE}/oauth/token`, {
|
|
53
|
+
method: "POST",
|
|
54
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
55
|
+
body: new URLSearchParams({
|
|
56
|
+
grant_type: "refresh_token",
|
|
57
|
+
refresh_token: credentials.refreshToken,
|
|
58
|
+
client_id: credentials.clientId
|
|
59
|
+
})
|
|
60
|
+
}).catch(() => null);
|
|
61
|
+
if (!response?.ok) return null;
|
|
62
|
+
const body = await response.json();
|
|
63
|
+
const updated = {
|
|
64
|
+
...credentials,
|
|
65
|
+
accessToken: body.access_token,
|
|
66
|
+
refreshToken: body.refresh_token,
|
|
67
|
+
expiresAt: Date.now() + body.expires_in * 1e3,
|
|
68
|
+
scope: body.scope.split(/\s+/).filter(Boolean)
|
|
35
69
|
};
|
|
36
|
-
|
|
37
|
-
return
|
|
70
|
+
await saveOAuthCredentials(updated);
|
|
71
|
+
return updated;
|
|
72
|
+
}
|
|
73
|
+
async function getToken() {
|
|
74
|
+
const stored = await getStoredCredentials();
|
|
75
|
+
if (!stored) return null;
|
|
76
|
+
if (stored.type === "legacy") return stored.token;
|
|
77
|
+
if (stored.credentials.expiresAt > Date.now() + 6e4) {
|
|
78
|
+
return stored.credentials.accessToken;
|
|
79
|
+
}
|
|
80
|
+
return (await refresh(stored.credentials))?.accessToken ?? null;
|
|
81
|
+
}
|
|
82
|
+
async function deleteToken() {
|
|
83
|
+
try {
|
|
84
|
+
entry.deletePassword();
|
|
85
|
+
} catch {
|
|
86
|
+
}
|
|
38
87
|
}
|
|
39
88
|
|
|
40
89
|
// src/commands/auth.ts
|
|
90
|
+
var CLIENT_ID = "agentis-cli";
|
|
91
|
+
var SCOPES = [
|
|
92
|
+
"wallets:read",
|
|
93
|
+
"wallets:write",
|
|
94
|
+
"payments:execute",
|
|
95
|
+
"policy:read",
|
|
96
|
+
"policy:write",
|
|
97
|
+
"privacy:read",
|
|
98
|
+
"privacy:write",
|
|
99
|
+
"earn:read",
|
|
100
|
+
"earn:write"
|
|
101
|
+
];
|
|
102
|
+
function base64url(bytes) {
|
|
103
|
+
return Buffer.from(bytes).toString("base64url");
|
|
104
|
+
}
|
|
105
|
+
function openBrowser(url) {
|
|
106
|
+
if (process.platform === "darwin") {
|
|
107
|
+
execFile("open", [url], () => {
|
|
108
|
+
});
|
|
109
|
+
} else if (process.platform === "win32") {
|
|
110
|
+
execFile("cmd", ["/c", "start", "", url], () => {
|
|
111
|
+
});
|
|
112
|
+
} else {
|
|
113
|
+
execFile("xdg-open", [url], () => {
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
41
117
|
async function login() {
|
|
42
|
-
const existing = await
|
|
118
|
+
const existing = await getStoredCredentials();
|
|
43
119
|
if (existing) {
|
|
44
120
|
console.log("Already logged in. Run `agentis logout` first.");
|
|
45
121
|
return;
|
|
46
122
|
}
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
123
|
+
const verifier = base64url(randomBytes(48));
|
|
124
|
+
const challenge = createHash("sha256").update(verifier).digest("base64url");
|
|
125
|
+
const state = base64url(randomBytes(24));
|
|
126
|
+
let resolveCallback;
|
|
127
|
+
const callback = new Promise((resolve2) => {
|
|
128
|
+
resolveCallback = resolve2;
|
|
129
|
+
});
|
|
130
|
+
let handled = false;
|
|
131
|
+
const server = Bun.serve({
|
|
132
|
+
hostname: "127.0.0.1",
|
|
133
|
+
port: 0,
|
|
134
|
+
fetch(request) {
|
|
135
|
+
const url = new URL(request.url);
|
|
136
|
+
if (url.pathname !== "/callback") return new Response("Not found", { status: 404 });
|
|
137
|
+
if (!handled) {
|
|
138
|
+
handled = true;
|
|
139
|
+
resolveCallback({
|
|
140
|
+
code: url.searchParams.get("code") ?? void 0,
|
|
141
|
+
error: url.searchParams.get("error") ?? void 0,
|
|
142
|
+
state: url.searchParams.get("state") ?? void 0
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return new Response(
|
|
146
|
+
'<!doctype html><html><body style="font-family:monospace;padding:40px">Agentis authorization complete. You can close this window.</body></html>',
|
|
147
|
+
{ headers: { "content-type": "text/html; charset=utf-8" } }
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
const redirectUri = `http://127.0.0.1:${server.port}/callback`;
|
|
152
|
+
const authorizeUrl = new URL(`${API_BASE}/oauth/authorize`);
|
|
153
|
+
authorizeUrl.search = new URLSearchParams({
|
|
154
|
+
response_type: "code",
|
|
155
|
+
client_id: CLIENT_ID,
|
|
156
|
+
redirect_uri: redirectUri,
|
|
157
|
+
code_challenge: challenge,
|
|
158
|
+
code_challenge_method: "S256",
|
|
159
|
+
scope: SCOPES.join(" "),
|
|
160
|
+
state,
|
|
161
|
+
resource: API_BASE
|
|
162
|
+
}).toString();
|
|
53
163
|
console.log("\nOpen this URL in your browser to authenticate:\n");
|
|
54
|
-
console.log(` ${
|
|
164
|
+
console.log(` ${authorizeUrl}
|
|
55
165
|
`);
|
|
166
|
+
openBrowser(authorizeUrl.toString());
|
|
167
|
+
console.log("Waiting for authorization...");
|
|
168
|
+
const timeout = new Promise((_, reject) => {
|
|
169
|
+
setTimeout(() => reject(new Error("Login timed out. Run `agentis login` again.")), 10 * 60 * 1e3);
|
|
170
|
+
});
|
|
56
171
|
try {
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const data = await poll.json();
|
|
75
|
-
if (data.status === "complete" && data.accountKey) {
|
|
76
|
-
await saveToken(data.accountKey);
|
|
77
|
-
console.log("\nAuthenticated! You can now use the Agentis CLI.\n");
|
|
78
|
-
return;
|
|
172
|
+
const result = await Promise.race([callback, timeout]);
|
|
173
|
+
if (result.error) throw new Error(`Authorization failed: ${result.error}`);
|
|
174
|
+
if (!result.code || result.state !== state) throw new Error("Invalid OAuth callback");
|
|
175
|
+
const response = await fetch(`${API_BASE}/oauth/token`, {
|
|
176
|
+
method: "POST",
|
|
177
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
178
|
+
body: new URLSearchParams({
|
|
179
|
+
grant_type: "authorization_code",
|
|
180
|
+
code: result.code,
|
|
181
|
+
redirect_uri: redirectUri,
|
|
182
|
+
code_verifier: verifier,
|
|
183
|
+
client_id: CLIENT_ID
|
|
184
|
+
})
|
|
185
|
+
});
|
|
186
|
+
const body = await response.json();
|
|
187
|
+
if (!response.ok || !body.access_token || !body.refresh_token || !body.expires_in) {
|
|
188
|
+
throw new Error(body.error_description ?? "OAuth token exchange failed");
|
|
79
189
|
}
|
|
190
|
+
await saveOAuthCredentials({
|
|
191
|
+
version: 2,
|
|
192
|
+
accessToken: body.access_token,
|
|
193
|
+
refreshToken: body.refresh_token,
|
|
194
|
+
expiresAt: Date.now() + body.expires_in * 1e3,
|
|
195
|
+
scope: body.scope?.split(/\s+/).filter(Boolean) ?? SCOPES,
|
|
196
|
+
clientId: CLIENT_ID
|
|
197
|
+
});
|
|
198
|
+
console.log("\nAuthenticated. You can now use the Agentis CLI.\n");
|
|
199
|
+
} catch (error) {
|
|
200
|
+
console.error(`
|
|
201
|
+
${error instanceof Error ? error.message : "Login failed"}`);
|
|
202
|
+
process.exitCode = 1;
|
|
203
|
+
} finally {
|
|
204
|
+
server.stop(true);
|
|
80
205
|
}
|
|
81
|
-
console.error("\nLogin timed out. Run `agentis login` again.");
|
|
82
|
-
process.exit(1);
|
|
83
206
|
}
|
|
84
207
|
async function logout() {
|
|
85
|
-
const
|
|
86
|
-
if (!
|
|
208
|
+
const stored = await getStoredCredentials();
|
|
209
|
+
if (!stored) {
|
|
87
210
|
console.log("Not logged in.");
|
|
88
211
|
return;
|
|
89
212
|
}
|
|
213
|
+
if (stored.type === "oauth") {
|
|
214
|
+
await fetch(`${API_BASE}/oauth/revoke`, {
|
|
215
|
+
method: "POST",
|
|
216
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
217
|
+
body: new URLSearchParams({ token: stored.credentials.refreshToken })
|
|
218
|
+
}).catch(() => null);
|
|
219
|
+
}
|
|
90
220
|
await deleteToken();
|
|
91
221
|
console.log("Logged out.");
|
|
92
222
|
}
|
|
93
223
|
async function whoami() {
|
|
224
|
+
const stored = await getStoredCredentials();
|
|
94
225
|
const token = await getToken();
|
|
95
|
-
if (!token) {
|
|
226
|
+
if (!stored || !token) {
|
|
96
227
|
console.log("Not logged in. Run `agentis login`.");
|
|
97
228
|
return;
|
|
98
229
|
}
|
|
99
230
|
const masked = token.slice(0, 13) + "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" + token.slice(-4);
|
|
100
|
-
console.log(`Logged in as ${masked}`);
|
|
231
|
+
console.log(`Logged in via ${stored.type === "oauth" ? "OAuth" : "account key"} as ${masked}`);
|
|
101
232
|
}
|
|
102
233
|
|
|
103
234
|
// src/lib/account.ts
|
|
@@ -134,7 +265,7 @@ import { wordlist as englishWordlist } from "@scure/bip39/wordlists/english.js";
|
|
|
134
265
|
import { HDKey } from "@scure/bip32";
|
|
135
266
|
import { scrypt } from "@noble/hashes/scrypt.js";
|
|
136
267
|
import { gcm } from "@noble/ciphers/aes.js";
|
|
137
|
-
import { randomBytes } from "@noble/hashes/utils.js";
|
|
268
|
+
import { randomBytes as randomBytes2 } from "@noble/hashes/utils.js";
|
|
138
269
|
import { ed25519 } from "@noble/curves/ed25519.js";
|
|
139
270
|
import { v4 as uuidv4 } from "uuid";
|
|
140
271
|
import { join } from "path";
|
|
@@ -185,8 +316,8 @@ function encodeBase58(bytes) {
|
|
|
185
316
|
return result;
|
|
186
317
|
}
|
|
187
318
|
function encryptMnemonic(mnemonic, passphrase = "") {
|
|
188
|
-
const salt =
|
|
189
|
-
const iv =
|
|
319
|
+
const salt = randomBytes2(32);
|
|
320
|
+
const iv = randomBytes2(12);
|
|
190
321
|
const key = scrypt(passphrase, salt, { N: 65536, r: 8, p: 1, dkLen: 32 });
|
|
191
322
|
const cipher = gcm(key, iv);
|
|
192
323
|
const data = new TextEncoder().encode(mnemonic);
|
|
@@ -489,6 +620,13 @@ Sent!`);
|
|
|
489
620
|
}
|
|
490
621
|
|
|
491
622
|
// src/lib/format-agent.ts
|
|
623
|
+
var blue = "\x1B[38;5;117m";
|
|
624
|
+
var purple = "\x1B[38;5;141m";
|
|
625
|
+
var green = "\x1B[38;5;114m";
|
|
626
|
+
var amber = "\x1B[38;5;179m";
|
|
627
|
+
var red = "\x1B[38;5;203m";
|
|
628
|
+
var muted = "\x1B[38;5;244m";
|
|
629
|
+
var reset = "\x1B[0m";
|
|
492
630
|
function formatPolicy(agent) {
|
|
493
631
|
const mode = agent.policyMode ?? "backend";
|
|
494
632
|
if (mode !== "onchain") return "policy=backend";
|
|
@@ -501,16 +639,41 @@ function formatPrivacy(agent) {
|
|
|
501
639
|
function formatLocalPolicy(wallet) {
|
|
502
640
|
return wallet.policy.killSwitch ? "policy=local:killed" : "policy=local";
|
|
503
641
|
}
|
|
642
|
+
function shorten(value, prefix = 6, suffix = 5) {
|
|
643
|
+
if (value.length <= prefix + suffix + 3) return value;
|
|
644
|
+
return `${value.slice(0, prefix)}...${value.slice(-suffix)}`;
|
|
645
|
+
}
|
|
646
|
+
function color(value, ansi) {
|
|
647
|
+
return `${ansi}${value}${reset}`;
|
|
648
|
+
}
|
|
649
|
+
function colorPolicy(policy) {
|
|
650
|
+
if (policy === "policy=onchain:ready") return color(policy, purple);
|
|
651
|
+
if (policy === "policy=onchain:pending") return color(policy, amber);
|
|
652
|
+
if (policy === "policy=local:killed") return color(policy, red);
|
|
653
|
+
return color(policy, muted);
|
|
654
|
+
}
|
|
655
|
+
function colorPrivacy(privacy) {
|
|
656
|
+
if (!privacy) return null;
|
|
657
|
+
if (privacy === "privacy=registered") return color(privacy, green);
|
|
658
|
+
if (privacy === "privacy=pending") return color(privacy, amber);
|
|
659
|
+
if (privacy === "privacy=failed") return color(privacy, red);
|
|
660
|
+
return color(privacy, muted);
|
|
661
|
+
}
|
|
504
662
|
function formatBadges(parts) {
|
|
505
|
-
return parts.filter(Boolean).join("
|
|
663
|
+
return parts.filter(Boolean).join(" ");
|
|
664
|
+
}
|
|
665
|
+
function formatName(name) {
|
|
666
|
+
return color(shorten(name, 17, 4).padEnd(24), blue);
|
|
506
667
|
}
|
|
507
668
|
function formatHostedAgentLine(agent) {
|
|
508
|
-
const badges = formatBadges([
|
|
509
|
-
|
|
669
|
+
const badges = formatBadges([
|
|
670
|
+
colorPolicy(formatPolicy(agent)),
|
|
671
|
+
colorPrivacy(formatPrivacy(agent))
|
|
672
|
+
]);
|
|
673
|
+
return ` ${formatName(agent.name)} ${shorten(agent.walletAddress)} ${badges}`;
|
|
510
674
|
}
|
|
511
675
|
function formatLocalWalletLine(wallet) {
|
|
512
|
-
|
|
513
|
-
return ` ${wallet.name.padEnd(20)} ${wallet.solanaAddress} [${wallet.id}] ${badges}`;
|
|
676
|
+
return ` ${formatName(wallet.name)} ${shorten(wallet.solanaAddress)} ${colorPolicy(formatLocalPolicy(wallet))}`;
|
|
514
677
|
}
|
|
515
678
|
|
|
516
679
|
// src/commands/wallet.ts
|
|
@@ -905,7 +1068,7 @@ async function privacyCommand(args2) {
|
|
|
905
1068
|
import { mkdir, readdir, readFile, stat, writeFile } from "fs/promises";
|
|
906
1069
|
import { existsSync as existsSync2 } from "fs";
|
|
907
1070
|
import { dirname, join as join2, resolve } from "path";
|
|
908
|
-
import { randomBytes as
|
|
1071
|
+
import { randomBytes as randomBytes3 } from "crypto";
|
|
909
1072
|
var DEVNET_USDC = "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU";
|
|
910
1073
|
var SOLANA_DEVNET_NETWORK = "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1";
|
|
911
1074
|
async function requireAuth2() {
|
|
@@ -1024,7 +1187,7 @@ async function facilitatorCreate(args2) {
|
|
|
1024
1187
|
}
|
|
1025
1188
|
const facilitator = await res.json();
|
|
1026
1189
|
const templateDir = facilitatorTemplateDir();
|
|
1027
|
-
const koraApiKey = "kora_" +
|
|
1190
|
+
const koraApiKey = "kora_" + randomBytes3(24).toString("hex");
|
|
1028
1191
|
await renderTemplateDir(templateDir, targetDir, {
|
|
1029
1192
|
NAME: name,
|
|
1030
1193
|
FACILITATOR_ID: facilitator.id,
|
|
@@ -1395,11 +1558,11 @@ async function earnSweep(args2) {
|
|
|
1395
1558
|
var args = process.argv.slice(2);
|
|
1396
1559
|
var cmd = args[0];
|
|
1397
1560
|
var sub = args[1];
|
|
1398
|
-
var
|
|
1399
|
-
var
|
|
1400
|
-
var
|
|
1561
|
+
var blue2 = "\x1B[38;5;117m";
|
|
1562
|
+
var green2 = "\x1B[38;5;114m";
|
|
1563
|
+
var muted2 = "\x1B[38;5;244m";
|
|
1401
1564
|
var bold = "\x1B[1m";
|
|
1402
|
-
var
|
|
1565
|
+
var reset2 = "\x1B[0m";
|
|
1403
1566
|
function readCliVersion() {
|
|
1404
1567
|
try {
|
|
1405
1568
|
const packageJsonPath = join3(dirname2(fileURLToPath(import.meta.url)), "..", "package.json");
|
|
@@ -1671,18 +1834,18 @@ var helpSpecs = {
|
|
|
1671
1834
|
}
|
|
1672
1835
|
};
|
|
1673
1836
|
function showHelp() {
|
|
1674
|
-
console.log(`${
|
|
1837
|
+
console.log(`${blue2}${bold}
|
|
1675
1838
|
\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557
|
|
1676
1839
|
\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D
|
|
1677
1840
|
\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557
|
|
1678
1841
|
\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551
|
|
1679
1842
|
\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551
|
|
1680
1843
|
\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
1681
|
-
${
|
|
1844
|
+
${reset2}${muted2}v${version}${reset2}
|
|
1682
1845
|
|
|
1683
|
-
${bold}Agentis${
|
|
1846
|
+
${bold}Agentis${reset2} \u2014 financial infrastructure for AI agents
|
|
1684
1847
|
|
|
1685
|
-
${
|
|
1848
|
+
${green2}${bold}Commands:${reset2}
|
|
1686
1849
|
login authenticate with your Agentis account
|
|
1687
1850
|
logout remove stored credentials
|
|
1688
1851
|
whoami show current account
|
|
@@ -1751,7 +1914,7 @@ function helpPath(values) {
|
|
|
1751
1914
|
}
|
|
1752
1915
|
function printRows(title, rows) {
|
|
1753
1916
|
console.log(`
|
|
1754
|
-
${
|
|
1917
|
+
${green2}${bold}${title}:${reset2}`);
|
|
1755
1918
|
for (const [left, right] of rows) {
|
|
1756
1919
|
console.log(` ${left.padEnd(38)} ${right}`);
|
|
1757
1920
|
}
|
|
@@ -1766,7 +1929,7 @@ function showCommandHelp(path) {
|
|
|
1766
1929
|
showHelp();
|
|
1767
1930
|
return;
|
|
1768
1931
|
}
|
|
1769
|
-
console.log(`${bold}Usage:${
|
|
1932
|
+
console.log(`${bold}Usage:${reset2} ${spec.usage}
|
|
1770
1933
|
`);
|
|
1771
1934
|
console.log(spec.description);
|
|
1772
1935
|
if (spec.commands) printRows("Commands", spec.commands);
|