@exagent/agent 0.3.0 → 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/dist/cli.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  readConfigFile,
9
9
  writeConfigFile,
10
10
  writeSampleConfig
11
- } from "./chunk-UAP5CTHB.js";
11
+ } from "./chunk-VDK4XPAC.js";
12
12
 
13
13
  // src/cli.ts
14
14
  import { Command } from "commander";
@@ -17,97 +17,82 @@ import { Command } from "commander";
17
17
  import { chmodSync, existsSync, mkdirSync, writeFileSync } from "fs";
18
18
  import { homedir } from "os";
19
19
  import { dirname, resolve } from "path";
20
- import { createInterface } from "readline/promises";
21
- import { stdin as input, stdout as output } from "process";
22
20
  import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
23
- function expandHomeDir(path) {
24
- if (!path.startsWith("~/")) return path;
25
- return resolve(homedir(), path.slice(2));
26
- }
27
- async function prompt(question) {
28
- const rl = createInterface({ input, output });
21
+ import * as clack from "@clack/prompts";
22
+
23
+ // src/ui.ts
24
+ import figlet from "figlet";
25
+ import gradient from "gradient-string";
26
+ import boxen from "boxen";
27
+ import pc from "picocolors";
28
+ import { createRequire } from "module";
29
+ var brandGradient = gradient(["#3B82F6", "#6366F1", "#7C3AED"]);
30
+ var accentGradient = gradient(["#22D3EE", "#3B82F6"]);
31
+ function getVersion() {
29
32
  try {
30
- return (await rl.question(question)).trim();
31
- } finally {
32
- rl.close();
33
+ const require2 = createRequire(import.meta.url);
34
+ const pkg = require2("../package.json");
35
+ return pkg.version || "0.0.0";
36
+ } catch {
37
+ return "0.0.0";
33
38
  }
34
39
  }
35
- async function promptSecret(question) {
36
- const rl = createInterface({ input, output, terminal: true });
37
- rl.stdoutMuted = true;
38
- const originalWrite = rl._writeToOutput?.bind(rl);
39
- rl._writeToOutput = (text) => {
40
- if (!rl.stdoutMuted) {
41
- originalWrite?.(text);
42
- }
43
- };
44
- try {
45
- const answer = (await rl.question(question)).trim();
46
- output.write("\n");
47
- return answer;
48
- } finally {
49
- rl.close();
50
- }
40
+ function printBanner() {
41
+ const art = figlet.textSync("EXAGENT", {
42
+ font: "Small",
43
+ horizontalLayout: "default"
44
+ });
45
+ console.log();
46
+ console.log(brandGradient(art));
47
+ console.log(pc.dim(` v${getVersion()}`));
48
+ console.log();
51
49
  }
52
- async function promptSecretPassword(question = "Device password: ") {
53
- return promptSecret(question);
50
+ function printSuccess(title, lines) {
51
+ const body = [
52
+ "",
53
+ pc.bold(pc.white(title)),
54
+ "",
55
+ ...lines.map((l) => ` ${l}`),
56
+ ""
57
+ ].join("\n");
58
+ console.log();
59
+ console.log(boxen(body, {
60
+ padding: { top: 0, bottom: 0, left: 2, right: 2 },
61
+ borderColor: "#3B82F6",
62
+ borderStyle: "round",
63
+ dimBorder: false
64
+ }));
65
+ console.log();
54
66
  }
55
- async function promptPasswordWithConfirmation() {
56
- output.write("\n");
57
- output.write("Important: this password encrypts the local wallet key, relay token, and agent LLM key for this device.\n");
58
- output.write("If you lose this password and the agent wallet holds funds, those funds cannot be recovered.\n\n");
59
- const ack = await prompt('Type "I UNDERSTAND" to continue: ');
60
- if (ack !== "I UNDERSTAND") {
61
- throw new Error("Secure setup aborted");
62
- }
63
- while (true) {
64
- const password = await promptSecret("Create a device password (min 12 chars): ");
65
- if (password.length < 12) {
66
- output.write("Password must be at least 12 characters.\n");
67
- continue;
68
- }
69
- const confirm = await promptSecret("Confirm device password: ");
70
- if (password !== confirm) {
71
- output.write("Passwords did not match. Try again.\n");
72
- continue;
73
- }
74
- return password;
75
- }
67
+ function printStep(step, total, label) {
68
+ console.log();
69
+ console.log(accentGradient(` Step ${step} of ${total}`) + pc.dim(` \u2014 ${label}`));
76
70
  }
77
- async function promptWalletPrivateKey() {
78
- while (true) {
79
- const choice = (await prompt("Wallet setup \u2014 [1] generate new wallet locally, [2] use existing private key: ")).trim();
80
- if (choice === "1") {
81
- const privateKey = generatePrivateKey();
82
- const address = privateKeyToAccount(privateKey).address;
83
- output.write(`Generated wallet address: ${address}
84
- `);
85
- return privateKey;
86
- }
87
- if (choice === "2") {
88
- const privateKey = await promptSecret("Wallet private key (0x...): ");
89
- if (/^0x[a-fA-F0-9]{64}$/.test(privateKey)) {
90
- return privateKey;
91
- }
92
- output.write("Invalid private key. Expected a 32-byte hex string prefixed with 0x.\n");
93
- continue;
94
- }
95
- output.write("Enter 1 or 2.\n");
96
- }
71
+ function printDone(message) {
72
+ console.log(` ${pc.green("\u2713")} ${message}`);
97
73
  }
98
- async function promptLlmProvider() {
99
- while (true) {
100
- const provider = (await prompt("Agent LLM provider (openai/anthropic/google/deepseek/mistral/groq/together/ollama): ")).toLowerCase();
101
- if (["openai", "anthropic", "google", "deepseek", "mistral", "groq", "together", "ollama"].includes(provider)) {
102
- return provider;
103
- }
104
- output.write("Unsupported provider.\n");
105
- }
74
+ function printInfo(message) {
75
+ console.log(` ${pc.dim("\u2502")} ${message}`);
76
+ }
77
+ function printError(message) {
78
+ console.log(` ${pc.red("\u2717")} ${message}`);
79
+ }
80
+
81
+ // src/setup.ts
82
+ function expandHomeDir(path) {
83
+ if (!path.startsWith("~/")) return path;
84
+ return resolve(homedir(), path.slice(2));
85
+ }
86
+ function cancelled() {
87
+ clack.cancel("Setup cancelled.");
88
+ process.exit(0);
106
89
  }
107
90
  async function consumeBootstrapPackage(config) {
108
91
  if (!config.secrets?.bootstrapToken) {
109
92
  return { apiToken: "" };
110
93
  }
94
+ const apiHost = new URL(config.apiUrl).host;
95
+ printInfo(`Connecting to ${pc.cyan(apiHost)}...`);
111
96
  const res = await fetch(`${config.apiUrl}/v1/agents/bootstrap/consume`, {
112
97
  method: "POST",
113
98
  headers: { "Content-Type": "application/json" },
@@ -118,46 +103,121 @@ async function consumeBootstrapPackage(config) {
118
103
  });
119
104
  if (!res.ok) {
120
105
  const body = await res.text();
121
- throw new Error(`Failed to consume secure setup package: ${body}`);
106
+ throw new Error(`Failed to consume bootstrap package: ${body}`);
122
107
  }
123
108
  const data = await res.json();
124
109
  return data.payload;
125
110
  }
126
- async function buildLocalSecrets(config, bootstrapPayload) {
127
- const nextConfig = structuredClone(config);
128
- const llm = { ...nextConfig.llm || {} };
129
- if (bootstrapPayload.llm?.provider && !llm.provider) {
130
- llm.provider = bootstrapPayload.llm.provider;
111
+ async function setupWallet(config) {
112
+ if (config.wallet?.privateKey) {
113
+ const account = privateKeyToAccount(config.wallet.privateKey);
114
+ printDone(`Using existing wallet: ${pc.dim(account.address)}`);
115
+ return config.wallet.privateKey;
116
+ }
117
+ const method = await clack.select({
118
+ message: "How would you like to set up your wallet?",
119
+ options: [
120
+ { value: "generate", label: "Generate new wallet locally", hint: "recommended" },
121
+ { value: "import", label: "Import existing private key" }
122
+ ]
123
+ });
124
+ if (clack.isCancel(method)) cancelled();
125
+ if (method === "generate") {
126
+ const privateKey2 = generatePrivateKey();
127
+ const address2 = privateKeyToAccount(privateKey2).address;
128
+ printDone(`Wallet created: ${pc.dim(address2)}`);
129
+ return privateKey2;
131
130
  }
132
- if (bootstrapPayload.llm?.model && !llm.model) {
133
- llm.model = bootstrapPayload.llm.model;
131
+ const privateKey = await clack.password({
132
+ message: "Wallet private key (0x...):",
133
+ validate: (val) => {
134
+ if (!/^0x[a-fA-F0-9]{64}$/.test(val)) {
135
+ return "Invalid private key. Expected a 32-byte hex string prefixed with 0x.";
136
+ }
137
+ }
138
+ });
139
+ if (clack.isCancel(privateKey)) cancelled();
140
+ const address = privateKeyToAccount(privateKey).address;
141
+ printDone(`Wallet imported: ${pc.dim(address)}`);
142
+ return privateKey;
143
+ }
144
+ var LLM_PROVIDERS = ["openai", "anthropic", "google", "deepseek", "mistral", "groq", "together", "ollama"];
145
+ async function setupLlm(config, bootstrapPayload) {
146
+ let provider = config.llm?.provider || bootstrapPayload.llm?.provider;
147
+ if (provider) {
148
+ printInfo(`Provider: ${pc.cyan(provider)} ${pc.dim("(from dashboard)")}`);
149
+ } else {
150
+ const selected = await clack.select({
151
+ message: "LLM provider:",
152
+ options: LLM_PROVIDERS.map((p) => ({ value: p, label: p }))
153
+ });
154
+ if (clack.isCancel(selected)) cancelled();
155
+ provider = selected;
134
156
  }
135
- if (!llm.provider) {
136
- llm.provider = await promptLlmProvider();
157
+ let model = config.llm?.model || bootstrapPayload.llm?.model;
158
+ if (model) {
159
+ printInfo(`Model: ${pc.cyan(model)} ${pc.dim("(from dashboard)")}`);
160
+ } else {
161
+ const entered = await clack.text({
162
+ message: "LLM model:",
163
+ placeholder: "gpt-4o",
164
+ validate: (val) => {
165
+ if (!val.trim()) return "Model name is required.";
166
+ }
167
+ });
168
+ if (clack.isCancel(entered)) cancelled();
169
+ model = entered;
137
170
  }
138
- if (!llm.model) {
139
- llm.model = await prompt("Agent LLM model: ");
140
- if (!llm.model) {
141
- throw new Error("Agent LLM model is required");
171
+ let apiKey;
172
+ if (bootstrapPayload.llm?.apiKey) {
173
+ const useBootstrap = await clack.confirm({
174
+ message: "LLM API key received from dashboard. Use it?",
175
+ initialValue: true
176
+ });
177
+ if (clack.isCancel(useBootstrap)) cancelled();
178
+ if (useBootstrap) {
179
+ apiKey = bootstrapPayload.llm.apiKey;
142
180
  }
143
181
  }
144
- const secrets = {
145
- apiToken: bootstrapPayload.apiToken || nextConfig.apiToken || await promptSecret("Agent relay token: "),
146
- walletPrivateKey: bootstrapPayload.walletPrivateKey || nextConfig.wallet?.privateKey || await promptWalletPrivateKey(),
147
- llmApiKey: bootstrapPayload.llm?.apiKey || nextConfig.llm.apiKey || await promptSecret("Agent LLM API key: ")
148
- };
149
- if (!secrets.apiToken) {
150
- throw new Error("Agent relay token is required");
182
+ if (!apiKey) {
183
+ apiKey = config.llm?.apiKey;
151
184
  }
152
- nextConfig.llm = llm;
153
- delete nextConfig.apiToken;
154
- delete nextConfig.wallet;
155
- delete nextConfig.llm.apiKey;
156
- return { config: nextConfig, secrets };
185
+ if (!apiKey) {
186
+ const entered = await clack.password({
187
+ message: "LLM API key:",
188
+ validate: (val) => {
189
+ if (!val.trim()) return "API key is required.";
190
+ }
191
+ });
192
+ if (clack.isCancel(entered)) cancelled();
193
+ apiKey = entered;
194
+ }
195
+ printDone("LLM configured");
196
+ return { provider, model, apiKey };
157
197
  }
158
- function writeSecureStore(path, secrets, password) {
198
+ async function setupEncryption() {
199
+ printInfo(`Secrets encrypted with ${pc.cyan("AES-256-GCM")} (${pc.cyan("scrypt")} KDF)`);
200
+ printInfo("The password never leaves this machine.");
201
+ console.log();
202
+ const password2 = await clack.password({
203
+ message: "Choose a device password (12+ characters):",
204
+ validate: (val) => {
205
+ if (val.length < 12) return "Password must be at least 12 characters.";
206
+ }
207
+ });
208
+ if (clack.isCancel(password2)) cancelled();
209
+ const confirm2 = await clack.password({
210
+ message: "Confirm password:",
211
+ validate: (val) => {
212
+ if (val !== password2) return "Passwords do not match.";
213
+ }
214
+ });
215
+ if (clack.isCancel(confirm2)) cancelled();
216
+ return password2;
217
+ }
218
+ function writeSecureStore(path, secrets, password2) {
159
219
  const secureStorePath = expandHomeDir(path);
160
- const encrypted = encryptSecretPayload(secrets, password);
220
+ const encrypted = encryptSecretPayload(secrets, password2);
161
221
  const dir = dirname(secureStorePath);
162
222
  if (!existsSync(dir)) {
163
223
  mkdirSync(dir, { recursive: true, mode: 448 });
@@ -169,74 +229,130 @@ function writeSecureStore(path, secrets, password) {
169
229
  }
170
230
  return secureStorePath;
171
231
  }
232
+ async function promptSecretPassword(question = "Device password:") {
233
+ const password2 = await clack.password({ message: question });
234
+ if (clack.isCancel(password2)) cancelled();
235
+ return password2;
236
+ }
172
237
  async function ensureLocalSetup(configPath) {
173
238
  const config = readConfigFile(configPath);
174
239
  const existingSecureStorePath = config.secrets?.secureStorePath ? expandHomeDir(config.secrets.secureStorePath) : null;
175
240
  if (existingSecureStorePath && !config.secrets?.bootstrapToken && existsSync(existingSecureStorePath) && !config.apiToken && !config.wallet?.privateKey && !config.llm.apiKey) {
176
241
  return;
177
242
  }
243
+ printBanner();
244
+ clack.intro(pc.bold("Agent Setup"));
245
+ printStep(1, 4, "Bootstrap package");
178
246
  const bootstrapPayload = await consumeBootstrapPackage(config);
179
- const { config: nextConfig, secrets } = await buildLocalSecrets(config, bootstrapPayload);
180
- const password = await promptPasswordWithConfirmation();
247
+ if (config.secrets?.bootstrapToken) {
248
+ printDone("Bootstrap package consumed");
249
+ if (bootstrapPayload.llm?.provider) {
250
+ printInfo(`LLM config received: ${pc.cyan(bootstrapPayload.llm.provider)}${bootstrapPayload.llm.model ? ` / ${pc.cyan(bootstrapPayload.llm.model)}` : ""}`);
251
+ }
252
+ } else {
253
+ printInfo("No bootstrap token \u2014 manual configuration");
254
+ }
255
+ printStep(2, 4, "Wallet setup");
256
+ const walletPrivateKey = await setupWallet(config);
257
+ printStep(3, 4, "LLM configuration");
258
+ const llm = await setupLlm(config, bootstrapPayload);
259
+ printStep(4, 4, "Device encryption");
260
+ const password2 = await setupEncryption();
261
+ const secrets = {
262
+ apiToken: bootstrapPayload.apiToken || config.apiToken || "",
263
+ walletPrivateKey,
264
+ llmApiKey: llm.apiKey
265
+ };
266
+ if (!secrets.apiToken) {
267
+ const token = await clack.password({
268
+ message: "Agent relay token:",
269
+ validate: (val) => {
270
+ if (!val.trim()) return "Relay token is required.";
271
+ }
272
+ });
273
+ if (clack.isCancel(token)) cancelled();
274
+ secrets.apiToken = token;
275
+ }
276
+ const nextConfig = structuredClone(config);
277
+ nextConfig.llm = {
278
+ ...nextConfig.llm,
279
+ provider: llm.provider,
280
+ model: llm.model
281
+ };
282
+ delete nextConfig.apiToken;
283
+ delete nextConfig.wallet;
284
+ delete nextConfig.llm.apiKey;
181
285
  const secureStorePath = writeSecureStore(
182
286
  nextConfig.secrets?.secureStorePath || getDefaultSecureStorePath(nextConfig.agentId),
183
287
  secrets,
184
- password
288
+ password2
185
289
  );
186
- nextConfig.secrets = {
187
- secureStorePath
188
- };
290
+ nextConfig.secrets = { secureStorePath };
189
291
  writeConfigFile(configPath, nextConfig);
190
- output.write(`Encrypted local secret store created at ${secureStorePath}
191
- `);
292
+ printDone(`Encrypted store: ${pc.dim(secureStorePath)}`);
293
+ clack.outro(pc.green("Setup complete"));
294
+ printSuccess("Ready", [
295
+ `${pc.cyan("npx exagent run")} Start trading`,
296
+ `${pc.cyan("npx exagent status")} Check connection`,
297
+ "",
298
+ `${pc.dim("Dashboard:")} ${pc.cyan("https://exagent.io")}`
299
+ ]);
192
300
  }
193
301
 
194
302
  // src/cli.ts
195
303
  var program = new Command();
196
- program.name("exagent").description("Exagent \u2014 LLM trading agent runtime").version("0.1.0");
304
+ program.name("exagent").description("Exagent \u2014 LLM trading agent runtime").version("0.3.0");
197
305
  program.command("init").description("Create a sample agent configuration file").option("--agent-id <id>", "Agent ID (from dashboard)", "my-agent").option("--api-url <url>", "API server URL", "http://localhost:3002").option("--config <path>", "Config file path", "agent-config.json").action((opts) => {
306
+ printBanner();
198
307
  writeSampleConfig(opts.agentId, opts.apiUrl, opts.config);
199
- console.log(`Created ${opts.config}`);
200
- console.log("Edit only the public strategy/venue/risk settings in the file.");
201
- console.log(`Then run: exagent setup --config ${opts.config}`);
308
+ printDone(`Created ${pc.cyan(opts.config)}`);
309
+ console.log();
310
+ console.log(` Edit only the public strategy/venue/risk settings.`);
311
+ console.log(` Then run: ${pc.cyan(`exagent setup --config ${opts.config}`)}`);
312
+ console.log();
202
313
  });
203
314
  program.command("setup").description("Run first-time secure local setup for agent secrets").option("--config <path>", "Config file path", "agent-config.json").action(async (opts) => {
204
315
  try {
205
316
  await ensureLocalSetup(opts.config);
206
- console.log("Secure local setup complete.");
207
317
  } catch (err) {
208
- console.error("Failed to complete secure local setup:", err.message);
318
+ printError(err.message);
209
319
  process.exit(1);
210
320
  }
211
321
  });
212
322
  program.command("run").description("Start the agent").option("--config <path>", "Config file path", "agent-config.json").action(async (opts) => {
213
323
  try {
214
324
  await ensureLocalSetup(opts.config);
325
+ printBanner();
215
326
  const config = await loadConfig(opts.config, {
216
327
  getSecretPassword: async () => promptSecretPassword()
217
328
  });
329
+ printDone(`Agent ${pc.cyan(config.agentId)} starting...`);
330
+ console.log();
218
331
  const runtime = new AgentRuntime(config);
219
332
  await runtime.start();
220
333
  await new Promise(() => {
221
334
  });
222
335
  } catch (err) {
223
- console.error("Failed to start agent:", err.message);
336
+ printError(err.message);
224
337
  process.exit(1);
225
338
  }
226
339
  });
227
340
  program.command("templates").description("List available strategy templates").action(() => {
341
+ printBanner();
228
342
  const templates = listTemplates();
229
- console.log("\nAvailable strategy templates:\n");
343
+ console.log(pc.bold(" Strategy Templates"));
344
+ console.log();
230
345
  for (const t of templates) {
231
- console.log(` ${t.id}`);
232
- console.log(` ${t.name} \u2014 ${t.description}`);
233
- console.log(` Risk: ${t.riskLevel} | Venues: ${t.venues.join(", ") || "any"}`);
346
+ console.log(` ${pc.cyan(t.id)}`);
347
+ console.log(` ${t.name} \u2014 ${pc.dim(t.description)}`);
348
+ console.log(` ${pc.dim(`Risk: ${t.riskLevel} | Venues: ${t.venues.join(", ") || "any"}`)}`);
234
349
  console.log();
235
350
  }
236
351
  });
237
352
  program.command("status").description("Check agent status").option("--config <path>", "Config file path", "agent-config.json").action(async (opts) => {
238
353
  try {
239
354
  await ensureLocalSetup(opts.config);
355
+ printBanner();
240
356
  const config = await loadConfig(opts.config, {
241
357
  getSecretPassword: async () => promptSecretPassword()
242
358
  });
@@ -244,13 +360,20 @@ program.command("status").description("Check agent status").option("--config <pa
244
360
  headers: { Authorization: `Bearer ${config.apiToken}` }
245
361
  });
246
362
  if (!res.ok) {
247
- console.error(`API error: ${res.status}`);
363
+ printError(`API error: ${res.status}`);
248
364
  process.exit(1);
249
365
  }
250
366
  const agent = await res.json();
251
- console.log(JSON.stringify(agent, null, 2));
367
+ const name = agent.name || config.agentId;
368
+ const status = agent.status || "unknown";
369
+ const statusColor = status === "online" ? pc.green : status === "error" ? pc.red : pc.yellow;
370
+ printSuccess(name, [
371
+ `${pc.dim("Status:")} ${statusColor(status)}`,
372
+ `${pc.dim("Agent:")} ${pc.cyan(config.agentId)}`,
373
+ `${pc.dim("API:")} ${pc.dim(config.apiUrl)}`
374
+ ]);
252
375
  } catch (err) {
253
- console.error("Failed to check status:", err.message);
376
+ printError(err.message);
254
377
  process.exit(1);
255
378
  }
256
379
  });
package/dist/index.d.ts CHANGED
@@ -19,7 +19,9 @@ interface RuntimeConfig {
19
19
  };
20
20
  strategy: {
21
21
  file?: string;
22
+ code?: string;
22
23
  template?: string;
24
+ venues?: string[];
23
25
  prompt?: {
24
26
  name?: string;
25
27
  systemPrompt: string;
@@ -124,6 +126,18 @@ declare class AgentRuntime {
124
126
  constructor(config: RuntimeConfig);
125
127
  start(): Promise<void>;
126
128
  stop(): Promise<void>;
129
+ private configureLLMAdapter;
130
+ private teardownVenues;
131
+ private waitForCycleCompletion;
132
+ private getConfiguredSpotVenue;
133
+ private normalizeVenueForExecution;
134
+ private isVenueConfigured;
135
+ private canExecuteVenue;
136
+ private getPreferredExecutionVenues;
137
+ private buildRuntimeVenuesFromSelection;
138
+ private buildStrategyFallbackPrompt;
139
+ private extractStrategyConfigFromAgentConfig;
140
+ private applyExecutionMode;
127
141
  private initializeVenues;
128
142
  private startTrading;
129
143
  private stopTrading;
@@ -415,6 +429,7 @@ declare function createLLMAdapter(config: LLMConfig): LLMAdapter;
415
429
 
416
430
  declare function loadStrategy(config: {
417
431
  file?: string;
432
+ code?: string;
418
433
  template?: string;
419
434
  prompt?: {
420
435
  name?: string;
package/dist/index.js CHANGED
@@ -43,7 +43,7 @@ import {
43
43
  loadConfig,
44
44
  loadStrategy,
45
45
  writeSampleConfig
46
- } from "./chunk-UAP5CTHB.js";
46
+ } from "./chunk-VDK4XPAC.js";
47
47
  export {
48
48
  AcrossAdapter,
49
49
  AerodromeAdapter,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exagent/agent",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -18,15 +18,22 @@
18
18
  "dev": "tsup src/index.ts src/cli.ts --format esm --dts --watch"
19
19
  },
20
20
  "dependencies": {
21
+ "@clack/prompts": "^1.1.0",
21
22
  "@exagent/sdk": "workspace:*",
22
23
  "@polymarket/clob-client": "^4.0.0",
24
+ "boxen": "^8.0.1",
23
25
  "commander": "^12.0.0",
24
26
  "ethers": "^5.7.2",
27
+ "figlet": "^1.10.0",
28
+ "gradient-string": "^3.0.0",
29
+ "picocolors": "^1.1.1",
25
30
  "viem": "^2.21.0",
26
31
  "ws": "^8.16.0",
27
32
  "zod": "^3.22.0"
28
33
  },
29
34
  "devDependencies": {
35
+ "@types/figlet": "^1.7.0",
36
+ "@types/gradient-string": "^1.1.6",
30
37
  "@types/node": "^20.0.0",
31
38
  "@types/ws": "^8.5.0",
32
39
  "tsup": "^8.0.0",