spendos 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/.dockerignore +4 -0
- package/.env.example +30 -0
- package/AGENTS.md +212 -0
- package/BOOTSTRAP.md +55 -0
- package/Dockerfile +52 -0
- package/HEARTBEAT.md +7 -0
- package/IDENTITY.md +23 -0
- package/LICENSE +21 -0
- package/README.md +162 -0
- package/SOUL.md +202 -0
- package/SUBMISSION.md +128 -0
- package/TOOLS.md +40 -0
- package/USER.md +17 -0
- package/acp-seller/bin/acp.ts +807 -0
- package/acp-seller/config.json +34 -0
- package/acp-seller/package.json +55 -0
- package/acp-seller/src/commands/agent.ts +328 -0
- package/acp-seller/src/commands/bounty.ts +1189 -0
- package/acp-seller/src/commands/deploy.ts +414 -0
- package/acp-seller/src/commands/job.ts +217 -0
- package/acp-seller/src/commands/profile.ts +71 -0
- package/acp-seller/src/commands/resource.ts +91 -0
- package/acp-seller/src/commands/search.ts +327 -0
- package/acp-seller/src/commands/sell.ts +883 -0
- package/acp-seller/src/commands/serve.ts +258 -0
- package/acp-seller/src/commands/setup.ts +399 -0
- package/acp-seller/src/commands/token.ts +88 -0
- package/acp-seller/src/commands/wallet.ts +123 -0
- package/acp-seller/src/lib/api.ts +118 -0
- package/acp-seller/src/lib/auth.ts +291 -0
- package/acp-seller/src/lib/bounty.ts +257 -0
- package/acp-seller/src/lib/client.ts +42 -0
- package/acp-seller/src/lib/config.ts +240 -0
- package/acp-seller/src/lib/open.ts +41 -0
- package/acp-seller/src/lib/openclawCron.ts +138 -0
- package/acp-seller/src/lib/output.ts +104 -0
- package/acp-seller/src/lib/wallet.ts +81 -0
- package/acp-seller/src/seller/offerings/_shared/preTransactionScan.ts +127 -0
- package/acp-seller/src/seller/offerings/canonical-catalog.ts +221 -0
- package/acp-seller/src/seller/offerings/spendos/spendos_summarize_url/handlers.ts +20 -0
- package/acp-seller/src/seller/offerings/spendos/spendos_summarize_url/offering.json +18 -0
- package/acp-seller/src/seller/offerings/spendos/spendos_translate/handlers.ts +21 -0
- package/acp-seller/src/seller/offerings/spendos/spendos_translate/offering.json +22 -0
- package/acp-seller/src/seller/offerings/spendos/spendos_tweet_gen/handlers.ts +20 -0
- package/acp-seller/src/seller/offerings/spendos/spendos_tweet_gen/offering.json +18 -0
- package/acp-seller/src/seller/runtime/acpSocket.ts +413 -0
- package/acp-seller/src/seller/runtime/logger.ts +36 -0
- package/acp-seller/src/seller/runtime/offeringTypes.ts +52 -0
- package/acp-seller/src/seller/runtime/offerings.ts +277 -0
- package/acp-seller/src/seller/runtime/paymentVerification.test.ts +207 -0
- package/acp-seller/src/seller/runtime/paymentVerification.ts +363 -0
- package/acp-seller/src/seller/runtime/seller.onchain.test.ts +220 -0
- package/acp-seller/src/seller/runtime/seller.test.ts +823 -0
- package/acp-seller/src/seller/runtime/seller.ts +1041 -0
- package/acp-seller/src/seller/runtime/sellerApi.ts +71 -0
- package/acp-seller/src/seller/runtime/startup.ts +270 -0
- package/acp-seller/src/seller/runtime/types.ts +62 -0
- package/acp-seller/tsconfig.json +20 -0
- package/bin/spendos.js +23 -0
- package/contracts/SpendOSAudit.sol +29 -0
- package/dist/mcp-server.mjs +153 -0
- package/jobs/translate.json +7 -0
- package/jobs/tweet-gen.json +7 -0
- package/openclaw.json +41 -0
- package/package.json +49 -0
- package/plugins/spendos-events/index.ts +78 -0
- package/plugins/spendos-events/package.json +14 -0
- package/policies/enforce-bounds.mjs +71 -0
- package/public/index.html +509 -0
- package/public/landing.html +241 -0
- package/railway.json +12 -0
- package/railway.toml +12 -0
- package/scripts/deploy.ts +48 -0
- package/scripts/test-x402-mainnet.ts +30 -0
- package/scripts/xmtp-listener.ts +61 -0
- package/setup.sh +278 -0
- package/skills/spendos/skill.md +26 -0
- package/src/agent.ts +152 -0
- package/src/audit.ts +166 -0
- package/src/governance.ts +367 -0
- package/src/job-registry.ts +306 -0
- package/src/mcp-public.ts +145 -0
- package/src/mcp-server.ts +171 -0
- package/src/opportunity-scanner.ts +138 -0
- package/src/server.ts +870 -0
- package/src/venice-x402.ts +234 -0
- package/src/xmtp.ts +109 -0
- package/src/zerion.ts +58 -0
- package/start.sh +168 -0
- package/tsconfig.json +14 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"SESSION_TOKEN": {
|
|
3
|
+
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjIyMTA4NCwiaWF0IjoxNzc1MzI5NzgxLCJleHAiOjE3NzUzMzE1ODF9.EwIOdP25HzmHqXcBUaBQFT6SuD_F1cJ01iSONvgRVvQ"
|
|
4
|
+
},
|
|
5
|
+
"agents": [
|
|
6
|
+
{
|
|
7
|
+
"id": 24346,
|
|
8
|
+
"name": "sigilx",
|
|
9
|
+
"walletAddress": "0xC643569c6e08A56740aD1B3EE884dce334418737",
|
|
10
|
+
"active": false
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"id": 34005,
|
|
14
|
+
"name": "sandbox-agent-0",
|
|
15
|
+
"walletAddress": "0xCd07e40729aba5DD3336Aa4Dfd0e6eb6257EC7Ab",
|
|
16
|
+
"active": false
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"id": 41550,
|
|
20
|
+
"name": "Signal Sink",
|
|
21
|
+
"walletAddress": "0xaD2dd9E11E5B281ACb2a7b9Fb7E6c116A17FBE8f",
|
|
22
|
+
"active": false
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": 41754,
|
|
26
|
+
"name": "spendos",
|
|
27
|
+
"walletAddress": "0xAa79D5240F736E2176a925179403e25D0A94756d",
|
|
28
|
+
"apiKey": "acp-1e9eaea050d72b42d42c",
|
|
29
|
+
"active": true
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"LITE_AGENT_API_KEY": "acp-1e9eaea050d72b42d42c",
|
|
33
|
+
"SELLER_PID": 93548
|
|
34
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agent-pulse/acp-seller",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Agent Commerce Protocol (ACP) CLI — wallet, marketplace, token, and seller runtime for AI agents",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"acp": "./bin/acp.ts"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "tsx src/seller/runtime/seller.ts",
|
|
11
|
+
"acp": "tsx bin/acp.ts",
|
|
12
|
+
"setup": "tsx bin/acp.ts setup",
|
|
13
|
+
"offering:create": "tsx bin/acp.ts sell create",
|
|
14
|
+
"offering:delete": "tsx bin/acp.ts sell delete",
|
|
15
|
+
"resource:create": "tsx bin/acp.ts sell resource create",
|
|
16
|
+
"resource:delete": "tsx bin/acp.ts sell resource delete",
|
|
17
|
+
"seller:run": "tsx bin/acp.ts serve start",
|
|
18
|
+
"seller:stop": "tsx bin/acp.ts serve stop",
|
|
19
|
+
"seller:check": "tsx bin/acp.ts serve status",
|
|
20
|
+
"build": "tsc --noEmit",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"lint": "tsc --noEmit",
|
|
23
|
+
"format": "prettier --write .",
|
|
24
|
+
"format:check": "prettier --check .",
|
|
25
|
+
"prepare": "husky",
|
|
26
|
+
"test": "node ./scripts/run-node-tests.mjs",
|
|
27
|
+
"test:cert": "vitest run --config vitest.cert.config.ts",
|
|
28
|
+
"test:watch": "vitest",
|
|
29
|
+
"test:vitest": "vitest run",
|
|
30
|
+
"preflight": "tsx scripts/validate-offerings-preflight.ts",
|
|
31
|
+
"preflight:strict": "tsx scripts/validate-offerings-preflight.ts --strict"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@supabase/supabase-js": "^2.96.0",
|
|
35
|
+
"axios": "^1.13.4",
|
|
36
|
+
"dotenv": "^16.4.5",
|
|
37
|
+
"socket.io-client": "^4.8.1",
|
|
38
|
+
"tsx": "^4.19.2",
|
|
39
|
+
"viem": "^2.45.1",
|
|
40
|
+
"@agent-pulse/compute-modal": "workspace:*",
|
|
41
|
+
"@agent-pulse/training-prime": "workspace:*",
|
|
42
|
+
"@agent-pulse/telemetry-wandb": "workspace:*"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^25.5.0",
|
|
46
|
+
"husky": "^9.1.7",
|
|
47
|
+
"lint-staged": "^16.4.0",
|
|
48
|
+
"prettier": "^3.4.2",
|
|
49
|
+
"typescript": "^5.7.2",
|
|
50
|
+
"vitest": "^4.0.18"
|
|
51
|
+
},
|
|
52
|
+
"lint-staged": {
|
|
53
|
+
"*.{ts,tsx,js,jsx,json,md}": "prettier --write"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// acp agent list — Show all agents (fetches from server, auto-login if needed)
|
|
3
|
+
// acp agent switch — Switch active agent (auto-login if needed)
|
|
4
|
+
// acp agent create — Create a new agent (auto-login if needed)
|
|
5
|
+
// =============================================================================
|
|
6
|
+
|
|
7
|
+
import readline from "readline";
|
|
8
|
+
import * as output from "../lib/output.js";
|
|
9
|
+
import {
|
|
10
|
+
readConfig,
|
|
11
|
+
writeConfig,
|
|
12
|
+
getActiveAgent,
|
|
13
|
+
findAgentByName,
|
|
14
|
+
activateAgent,
|
|
15
|
+
findSellerPid,
|
|
16
|
+
isProcessRunning,
|
|
17
|
+
removePidFromConfig,
|
|
18
|
+
type AgentEntry,
|
|
19
|
+
findAgentByWalletAddress,
|
|
20
|
+
} from "../lib/config.js";
|
|
21
|
+
import {
|
|
22
|
+
ensureSession,
|
|
23
|
+
fetchAgents,
|
|
24
|
+
createAgentApi,
|
|
25
|
+
regenerateApiKey,
|
|
26
|
+
syncAgentsToConfig,
|
|
27
|
+
isAgentApiKeyValid,
|
|
28
|
+
} from "../lib/auth.js";
|
|
29
|
+
|
|
30
|
+
function redactApiKey(key: string | undefined): string {
|
|
31
|
+
if (!key || key.length < 8) return "(not available)";
|
|
32
|
+
return `${key.slice(0, 4)}...${key.slice(-4)}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function confirmPrompt(prompt: string): Promise<boolean> {
|
|
36
|
+
const rl = readline.createInterface({
|
|
37
|
+
input: process.stdin,
|
|
38
|
+
output: process.stdout,
|
|
39
|
+
});
|
|
40
|
+
return new Promise((resolve) => {
|
|
41
|
+
rl.question(prompt, (answer) => {
|
|
42
|
+
rl.close();
|
|
43
|
+
const a = answer.trim().toLowerCase();
|
|
44
|
+
resolve(a === "y" || a === "yes" || a === "");
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function sleep(ms: number): Promise<void> {
|
|
50
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function killSellerProcess(pid: number): Promise<boolean> {
|
|
54
|
+
try {
|
|
55
|
+
process.kill(pid, "SIGTERM");
|
|
56
|
+
} catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
// Wait up to 2 seconds for process to stop without blocking the event loop
|
|
60
|
+
for (let i = 0; i < 10; i++) {
|
|
61
|
+
await sleep(200);
|
|
62
|
+
if (!isProcessRunning(pid)) {
|
|
63
|
+
removePidFromConfig();
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Check if seller runtime is running. If so, warn the user and ask for
|
|
72
|
+
* confirmation to stop it. Returns true if it's safe to proceed (no seller
|
|
73
|
+
* running, or seller was stopped). Returns false if the user cancelled.
|
|
74
|
+
* Calls output.fatal (exits) if the seller could not be killed.
|
|
75
|
+
*/
|
|
76
|
+
export async function stopSellerIfRunning(): Promise<boolean> {
|
|
77
|
+
const sellerPid = findSellerPid();
|
|
78
|
+
if (sellerPid === undefined) return true;
|
|
79
|
+
|
|
80
|
+
const active = getActiveAgent();
|
|
81
|
+
const activeName = active ? `"${active.name}"` : "the current agent";
|
|
82
|
+
|
|
83
|
+
let offeringNames: string[] = [];
|
|
84
|
+
try {
|
|
85
|
+
const { getMyAgentInfo } = await import("../lib/wallet.js");
|
|
86
|
+
const info = await getMyAgentInfo();
|
|
87
|
+
offeringNames = (info.jobs ?? []).map((j: any) => j.name);
|
|
88
|
+
} catch {
|
|
89
|
+
// Non-fatal — just won't show offering names
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const offeringsLine =
|
|
93
|
+
offeringNames.length > 0
|
|
94
|
+
? `\n Active Job Offerings being served: ${offeringNames.join(", ")}\n`
|
|
95
|
+
: "";
|
|
96
|
+
output.warn(
|
|
97
|
+
`Seller runtime process is running (PID ${sellerPid}) for ${activeName}. ` +
|
|
98
|
+
`It must be stopped before switching agents, because the runtime ` +
|
|
99
|
+
`is tied to the current agent's API key.${offeringsLine}\n`,
|
|
100
|
+
);
|
|
101
|
+
const ok = await confirmPrompt(
|
|
102
|
+
" Stop the seller runtime process and continue? (Y/n): ",
|
|
103
|
+
);
|
|
104
|
+
if (!ok) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
output.log(` Stopping seller runtime (PID ${sellerPid})...`);
|
|
108
|
+
const stopped = await killSellerProcess(sellerPid);
|
|
109
|
+
if (stopped) {
|
|
110
|
+
output.log(` Seller runtime stopped.\n`);
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
output.fatal(
|
|
114
|
+
`Could not stop seller process (PID ${sellerPid}). Try: kill -9 ${sellerPid}`,
|
|
115
|
+
);
|
|
116
|
+
return false; // unreachable (fatal exits), but satisfies TS
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function displayAgents(agents: AgentEntry[]): void {
|
|
120
|
+
output.heading("Agents");
|
|
121
|
+
for (const a of agents) {
|
|
122
|
+
const marker = a.active ? output.colors.green(" (active)") : "";
|
|
123
|
+
output.log(` ${output.colors.bold(a.name)}${marker}`);
|
|
124
|
+
output.log(` ${output.colors.dim("Wallet")} ${a.walletAddress}`);
|
|
125
|
+
if (a.apiKey) {
|
|
126
|
+
output.log(
|
|
127
|
+
` ${output.colors.dim("API Key")} ${redactApiKey(a.apiKey)}`,
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
output.log("");
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export async function list(): Promise<void> {
|
|
135
|
+
const sessionToken = await ensureSession();
|
|
136
|
+
let agents: AgentEntry[];
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
const serverAgents = await fetchAgents(sessionToken);
|
|
140
|
+
agents = syncAgentsToConfig(serverAgents);
|
|
141
|
+
} catch (e) {
|
|
142
|
+
output.warn(
|
|
143
|
+
`Could not fetch agents from server: ${e instanceof Error ? e.message : String(e)}`,
|
|
144
|
+
);
|
|
145
|
+
output.log(" Showing locally saved agents.\n");
|
|
146
|
+
agents = readConfig().agents ?? [];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (agents.length === 0) {
|
|
150
|
+
output.output({ agents: [] }, () => {
|
|
151
|
+
output.log(
|
|
152
|
+
" No agents found. Run `acp agent create <name>` to create one.\n",
|
|
153
|
+
);
|
|
154
|
+
});
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
output.output(
|
|
159
|
+
agents.map((a) => ({
|
|
160
|
+
name: a.name,
|
|
161
|
+
id: a.id,
|
|
162
|
+
walletAddress: a.walletAddress,
|
|
163
|
+
active: a.active,
|
|
164
|
+
})),
|
|
165
|
+
() => displayAgents(agents),
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export async function switchAgentByName(name: string): Promise<void> {
|
|
170
|
+
const target = findAgentByName(name);
|
|
171
|
+
if (!target) {
|
|
172
|
+
output.fatal(`Agent "${name}" not found. Run \`acp agent list\` first.`);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const agents = readConfig().agents ?? [];
|
|
176
|
+
const matchingAgents = agents.filter(
|
|
177
|
+
(a) => a.name.toLowerCase() === name.toLowerCase(),
|
|
178
|
+
);
|
|
179
|
+
if (matchingAgents.length > 1) {
|
|
180
|
+
output.fatal(
|
|
181
|
+
`Multiple agents with name "${name}".\nAvailable: ${matchingAgents
|
|
182
|
+
.map((a) => `${a.name} (${a.walletAddress})`)
|
|
183
|
+
.join(
|
|
184
|
+
", ",
|
|
185
|
+
)}.\nRun \`acp agent switch --wallet <walletAddress>\` to switch to one of them.`,
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return await switchAgent(target.walletAddress);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export async function switchAgent(walletAddress: string): Promise<void> {
|
|
193
|
+
if (!walletAddress) {
|
|
194
|
+
output.fatal("Usage: acp agent switch <walletAddress>");
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const target = findAgentByWalletAddress(walletAddress);
|
|
198
|
+
if (!target) {
|
|
199
|
+
const config = readConfig();
|
|
200
|
+
const agentList = (config.agents ?? [])
|
|
201
|
+
.map((a) => `${a.name} (${a.walletAddress})`)
|
|
202
|
+
.join(", ");
|
|
203
|
+
output.fatal(
|
|
204
|
+
`Agent "${walletAddress}" not found. Run \`acp agent list\` first. Available: ${
|
|
205
|
+
agentList || "(none)"
|
|
206
|
+
}`,
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (target.active) {
|
|
211
|
+
output.log(` Agent ${target.name} is already active.\n`);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Stop seller runtime if running (API key will change)
|
|
216
|
+
const proceed = await stopSellerIfRunning();
|
|
217
|
+
if (!proceed) {
|
|
218
|
+
output.log(" Agent switch cancelled.\n");
|
|
219
|
+
throw new Error("Agent switch cancelled");
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const sessionToken = await ensureSession();
|
|
223
|
+
|
|
224
|
+
output.log(` Switching to ${target.name}...\n`);
|
|
225
|
+
try {
|
|
226
|
+
let apiKey: string = "";
|
|
227
|
+
let valid = false;
|
|
228
|
+
|
|
229
|
+
if (target.apiKey) {
|
|
230
|
+
valid = await isAgentApiKeyValid(target.apiKey);
|
|
231
|
+
if (valid) {
|
|
232
|
+
apiKey = target.apiKey;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (!valid) {
|
|
237
|
+
const result = await regenerateApiKey(sessionToken, target.walletAddress);
|
|
238
|
+
apiKey = result.apiKey;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (!apiKey) {
|
|
242
|
+
output.fatal("Failed to switch agent — no API key returned.");
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
activateAgent(target.id, apiKey);
|
|
246
|
+
|
|
247
|
+
output.output(
|
|
248
|
+
{
|
|
249
|
+
switched: true,
|
|
250
|
+
name: target.name,
|
|
251
|
+
walletAddress: target.walletAddress,
|
|
252
|
+
},
|
|
253
|
+
() => {
|
|
254
|
+
output.success(`Switched to agent: ${target.name}`);
|
|
255
|
+
output.log(` Wallet: ${target.walletAddress}`);
|
|
256
|
+
},
|
|
257
|
+
);
|
|
258
|
+
} catch (e) {
|
|
259
|
+
output.fatal(
|
|
260
|
+
`Failed to switch agent: ${e instanceof Error ? e.message : String(e)}`,
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export async function create(name: string): Promise<void> {
|
|
266
|
+
if (!name) {
|
|
267
|
+
output.fatal("Usage: acp agent create <name>");
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Stop seller runtime if running (API key will change)
|
|
271
|
+
const proceed = await stopSellerIfRunning();
|
|
272
|
+
if (!proceed) {
|
|
273
|
+
output.log(" Agent creation cancelled.\n");
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const sessionToken = await ensureSession();
|
|
278
|
+
|
|
279
|
+
try {
|
|
280
|
+
const result = await createAgentApi(sessionToken, name);
|
|
281
|
+
if (!result?.apiKey) {
|
|
282
|
+
output.fatal("Create agent failed — no API key returned.");
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Add to local config and activate
|
|
286
|
+
const config = readConfig();
|
|
287
|
+
const updatedAgents = (config.agents ?? []).map((a) => ({
|
|
288
|
+
...a,
|
|
289
|
+
active: false,
|
|
290
|
+
apiKey: undefined, // clear other agents' keys
|
|
291
|
+
})) as AgentEntry[];
|
|
292
|
+
|
|
293
|
+
const newAgent: AgentEntry = {
|
|
294
|
+
id: result.id,
|
|
295
|
+
name: result.name || name,
|
|
296
|
+
walletAddress: result.walletAddress,
|
|
297
|
+
apiKey: result.apiKey,
|
|
298
|
+
active: true,
|
|
299
|
+
};
|
|
300
|
+
updatedAgents.push(newAgent);
|
|
301
|
+
|
|
302
|
+
writeConfig({
|
|
303
|
+
...config,
|
|
304
|
+
LITE_AGENT_API_KEY: result.apiKey,
|
|
305
|
+
agents: updatedAgents,
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
output.output(
|
|
309
|
+
{
|
|
310
|
+
created: true,
|
|
311
|
+
name: newAgent.name,
|
|
312
|
+
id: newAgent.id,
|
|
313
|
+
walletAddress: newAgent.walletAddress,
|
|
314
|
+
},
|
|
315
|
+
() => {
|
|
316
|
+
output.success(`Agent created: ${newAgent.name}`);
|
|
317
|
+
output.log(` Wallet: ${newAgent.walletAddress}`);
|
|
318
|
+
output.log(
|
|
319
|
+
` API Key: ${redactApiKey(newAgent.apiKey)} (saved to config.json)\n`,
|
|
320
|
+
);
|
|
321
|
+
},
|
|
322
|
+
);
|
|
323
|
+
} catch (e) {
|
|
324
|
+
output.fatal(
|
|
325
|
+
`Create agent failed: ${e instanceof Error ? e.message : String(e)}`,
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
}
|