@exagent/agent 0.3.5 → 0.3.7

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.
Files changed (78) hide show
  1. package/dist/chunk-7UGLJO6W.js +6392 -0
  2. package/dist/chunk-EHAOPCTJ.js +6406 -0
  3. package/dist/chunk-FGMXTW5I.js +6540 -0
  4. package/dist/chunk-IVA2SCSN.js +6756 -0
  5. package/dist/chunk-JHXCSGPC.js +6352 -0
  6. package/dist/chunk-V6O4UXVN.js +6345 -0
  7. package/dist/chunk-ZRAOPQQW.js +6406 -0
  8. package/dist/cli.js +40 -98
  9. package/dist/index.d.ts +24 -2
  10. package/dist/index.js +1 -1
  11. package/package.json +17 -14
  12. package/.turbo/turbo-build.log +0 -17
  13. package/src/bridge/across.ts +0 -240
  14. package/src/bridge/bridge-manager.ts +0 -87
  15. package/src/bridge/index.ts +0 -9
  16. package/src/bridge/types.ts +0 -77
  17. package/src/chains.ts +0 -105
  18. package/src/cli.ts +0 -244
  19. package/src/config.ts +0 -499
  20. package/src/diagnostics.ts +0 -335
  21. package/src/index.ts +0 -98
  22. package/src/llm/anthropic.ts +0 -63
  23. package/src/llm/base.ts +0 -264
  24. package/src/llm/deepseek.ts +0 -48
  25. package/src/llm/google.ts +0 -63
  26. package/src/llm/groq.ts +0 -48
  27. package/src/llm/index.ts +0 -42
  28. package/src/llm/mistral.ts +0 -48
  29. package/src/llm/ollama.ts +0 -52
  30. package/src/llm/openai.ts +0 -51
  31. package/src/llm/together.ts +0 -48
  32. package/src/llm-providers.ts +0 -100
  33. package/src/logger.ts +0 -137
  34. package/src/paper/executor.ts +0 -201
  35. package/src/paper/index.ts +0 -1
  36. package/src/perp/client.ts +0 -200
  37. package/src/perp/index.ts +0 -12
  38. package/src/perp/msgpack.ts +0 -272
  39. package/src/perp/orders.ts +0 -234
  40. package/src/perp/positions.ts +0 -126
  41. package/src/perp/signer.ts +0 -277
  42. package/src/perp/types.ts +0 -192
  43. package/src/perp/websocket.ts +0 -274
  44. package/src/position-tracker.ts +0 -243
  45. package/src/prediction/client.ts +0 -281
  46. package/src/prediction/index.ts +0 -3
  47. package/src/prediction/order-manager.ts +0 -297
  48. package/src/prediction/types.ts +0 -151
  49. package/src/relay.ts +0 -254
  50. package/src/runtime.ts +0 -1755
  51. package/src/scrub-secrets.ts +0 -39
  52. package/src/setup.ts +0 -384
  53. package/src/signal.ts +0 -212
  54. package/src/spot/aerodrome.ts +0 -158
  55. package/src/spot/client.ts +0 -138
  56. package/src/spot/index.ts +0 -11
  57. package/src/spot/swap-manager.ts +0 -219
  58. package/src/spot/types.ts +0 -203
  59. package/src/spot/uniswap.ts +0 -150
  60. package/src/store.ts +0 -50
  61. package/src/strategy/index.ts +0 -2
  62. package/src/strategy/loader.ts +0 -191
  63. package/src/strategy/templates.ts +0 -125
  64. package/src/trading/index.ts +0 -2
  65. package/src/trading/market.ts +0 -120
  66. package/src/trading/risk.ts +0 -107
  67. package/src/ui.ts +0 -75
  68. package/test-bridge-arb-to-base.mjs +0 -223
  69. package/test-funded-check.mjs +0 -79
  70. package/test-funded-phase19.mjs +0 -933
  71. package/test-hl-deposit-recover.mjs +0 -281
  72. package/test-hl-withdraw.mjs +0 -372
  73. package/test-live-signing.mjs +0 -374
  74. package/test-phase7.mjs +0 -416
  75. package/test-recover-arb.mjs +0 -206
  76. package/test-spot-bridge.mjs +0 -248
  77. package/test-wallet-setup.mjs +0 -126
  78. package/tsconfig.json +0 -8
@@ -1,87 +0,0 @@
1
- import { getChainConfig } from '../chains.js';
2
- import type { SpotDEXClient } from '../spot/client.js';
3
- import { AcrossAdapter } from './across.js';
4
- import type { BridgeConfig, BridgeRequest, BridgeFeeEstimate, BridgeResult } from './types.js';
5
-
6
- const MIN_GAS_WEI = 100_000_000_000_000n; // 0.0001 ETH/POL
7
-
8
- export class BridgeManager {
9
- private across: AcrossAdapter;
10
- private client: SpotDEXClient;
11
- private config: BridgeConfig;
12
-
13
- constructor(client: SpotDEXClient, config: BridgeConfig) {
14
- this.config = config;
15
- this.client = client;
16
- this.across = new AcrossAdapter(client, config);
17
- }
18
-
19
- async estimateFee(request: BridgeRequest): Promise<BridgeFeeEstimate> {
20
- const bridge = request.bridge ?? this.config.defaultBridge;
21
- if (bridge !== 'across') {
22
- throw new Error(`Unsupported bridge: ${bridge}. Only "across" is currently supported.`);
23
- }
24
- return this.across.estimateFee(request);
25
- }
26
-
27
- async bridge(request: BridgeRequest): Promise<BridgeResult> {
28
- const bridge = request.bridge ?? this.config.defaultBridge;
29
- if (bridge !== 'across') {
30
- return {
31
- success: false,
32
- depositTxHash: '0x0' as `0x${string}`,
33
- fromChain: request.fromChain,
34
- toChain: request.toChain,
35
- token: request.token,
36
- amount: request.amount,
37
- fee: 0n,
38
- error: `Unsupported bridge: ${bridge}. Only "across" is currently supported.`,
39
- };
40
- }
41
-
42
- // Enforce max bridge value cap
43
- // Bridge amounts are in token decimals — estimate USD for common tokens (USDC = 6 decimals)
44
- try {
45
- const decimals = await this.client.getDecimals(request.token, request.fromChain);
46
- const amountFloat = Number(request.amount) / 10 ** decimals;
47
- if (amountFloat > this.config.maxBridgeValueUSD) {
48
- return {
49
- success: false,
50
- depositTxHash: '0x0' as `0x${string}`,
51
- fromChain: request.fromChain,
52
- toChain: request.toChain,
53
- token: request.token,
54
- amount: request.amount,
55
- fee: 0n,
56
- error: `Bridge value ${amountFloat.toFixed(2)} exceeds max $${this.config.maxBridgeValueUSD}. Reduce amount or increase maxBridgeValueUSD.`,
57
- };
58
- }
59
- } catch {
60
- // If decimals lookup fails, proceed — let the bridge itself validate
61
- }
62
-
63
- // Pre-check native gas balance on origin chain
64
- try {
65
- const nativeBalance = await this.client.getNativeBalance(request.fromChain);
66
- if (nativeBalance < MIN_GAS_WEI) {
67
- const chainConfig = getChainConfig(request.fromChain);
68
- const nativeName = chainConfig?.nativeCurrency ?? 'ETH';
69
- return {
70
- success: false,
71
- depositTxHash: '0x0' as `0x${string}`,
72
- fromChain: request.fromChain,
73
- toChain: request.toChain,
74
- token: request.token,
75
- amount: request.amount,
76
- fee: 0n,
77
- error: `Insufficient ${nativeName} for gas on ${request.fromChain}. Balance: ${nativeBalance} wei. Need at least 0.0001 ${nativeName}.`,
78
- };
79
- }
80
- } catch {
81
- // Non-critical — proceed and let the bridge itself surface the error
82
- }
83
-
84
- console.log(`[bridge] Bridging via Across: ${request.fromChain} → ${request.toChain} (${request.amount})`);
85
- return this.across.deposit(request);
86
- }
87
- }
@@ -1,9 +0,0 @@
1
- export { AcrossAdapter } from './across.js';
2
- export { BridgeManager } from './bridge-manager.js';
3
- export type {
4
- BridgeConfig,
5
- BridgeRequest,
6
- BridgeFeeEstimate,
7
- BridgeResult,
8
- } from './types.js';
9
- export { DEFAULT_BRIDGE_CONFIG } from './types.js';
@@ -1,77 +0,0 @@
1
- // ─── Bridge Config ──────────────────────────────────────────────
2
-
3
- export interface BridgeConfig {
4
- enabled: boolean;
5
- defaultBridge: string;
6
- maxBridgeValueUSD: number;
7
- fillTimeoutMs: number;
8
- pollIntervalMs: number;
9
- }
10
-
11
- export const DEFAULT_BRIDGE_CONFIG: BridgeConfig = {
12
- enabled: false,
13
- defaultBridge: 'across',
14
- maxBridgeValueUSD: 10_000,
15
- fillTimeoutMs: 300_000, // 5 minutes
16
- pollIntervalMs: 2_000, // 2 seconds
17
- };
18
-
19
- // ─── Bridge Request & Results ───────────────────────────────────
20
-
21
- export interface BridgeRequest {
22
- token: `0x${string}`;
23
- amount: bigint;
24
- fromChain: string;
25
- toChain: string;
26
- recipient?: `0x${string}`;
27
- bridge?: string;
28
- }
29
-
30
- export interface BridgeFeeEstimate {
31
- totalRelayFeePct: number;
32
- capitalFeePct: number;
33
- lpFeePct: number;
34
- relayGasFeePct: number;
35
- timestamp: number;
36
- estimatedFillTimeSec: number;
37
- isAmountTooLow: boolean;
38
- outputAmount: bigint;
39
- }
40
-
41
- export interface BridgeResult {
42
- success: boolean;
43
- depositTxHash: `0x${string}`;
44
- fromChain: string;
45
- toChain: string;
46
- token: `0x${string}`;
47
- amount: bigint;
48
- fee: bigint;
49
- fillTxHash?: `0x${string}`;
50
- fillTimestamp?: number;
51
- error?: string;
52
- }
53
-
54
- // ─── Across SpokePool ABI Fragment ──────────────────────────────
55
-
56
- export const ACROSS_SPOKE_POOL_ABI = [
57
- {
58
- type: 'function' as const,
59
- name: 'depositV3' as const,
60
- inputs: [
61
- { name: 'depositor', type: 'address' as const },
62
- { name: 'recipient', type: 'address' as const },
63
- { name: 'inputToken', type: 'address' as const },
64
- { name: 'outputToken', type: 'address' as const },
65
- { name: 'inputAmount', type: 'uint256' as const },
66
- { name: 'outputAmount', type: 'uint256' as const },
67
- { name: 'destinationChainId', type: 'uint256' as const },
68
- { name: 'exclusiveRelayer', type: 'address' as const },
69
- { name: 'quoteTimestamp', type: 'uint32' as const },
70
- { name: 'fillDeadline', type: 'uint32' as const },
71
- { name: 'exclusivityDeadline', type: 'uint32' as const },
72
- { name: 'message', type: 'bytes' as const },
73
- ],
74
- outputs: [],
75
- stateMutability: 'payable' as const,
76
- },
77
- ] as const;
package/src/chains.ts DELETED
@@ -1,105 +0,0 @@
1
- import { type Chain, base, arbitrum, polygon, mainnet } from 'viem/chains';
2
-
3
- export interface ChainConfig {
4
- chainId: number;
5
- name: string;
6
- viemChain: Chain;
7
- rpcUrl: string;
8
- nativeCurrency: string;
9
- blockExplorer: string;
10
- wethAddress: `0x${string}`;
11
- usdcAddress: `0x${string}`;
12
- dexRouters: Record<string, `0x${string}`>;
13
- uniswapQuoter?: `0x${string}`;
14
- acrossSpokePool?: `0x${string}`;
15
- }
16
-
17
- export const CHAIN_CONFIGS: Record<string, ChainConfig> = {
18
- base: {
19
- chainId: 8453,
20
- name: 'base',
21
- viemChain: base,
22
- rpcUrl: 'https://mainnet.base.org',
23
- nativeCurrency: 'ETH',
24
- blockExplorer: 'https://basescan.org',
25
- wethAddress: '0x4200000000000000000000000000000000000006',
26
- usdcAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
27
- dexRouters: {
28
- uniswap: '0x2626664c2603336E57B271c5C0b26F421741e481',
29
- aerodrome: '0xcF77a3Ba9A5CA399B7c97c74d54e5b1Beb874E43',
30
- },
31
- uniswapQuoter: '0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a',
32
- acrossSpokePool: '0x09aea4b2242abC8bb4BB78D537A67a245A7bEC64',
33
- },
34
- ethereum: {
35
- chainId: 1,
36
- name: 'ethereum',
37
- viemChain: mainnet,
38
- rpcUrl: 'https://eth.llamarpc.com',
39
- nativeCurrency: 'ETH',
40
- blockExplorer: 'https://etherscan.io',
41
- wethAddress: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
42
- usdcAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
43
- dexRouters: {
44
- uniswap: '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45',
45
- },
46
- uniswapQuoter: '0x61fFE014bA17989E743c5F6cB21bF9697530B21e',
47
- acrossSpokePool: '0x5c7BCd6E7De5423a257D81B442095A1a6ced35C5',
48
- },
49
- arbitrum: {
50
- chainId: 42161,
51
- name: 'arbitrum',
52
- viemChain: arbitrum,
53
- rpcUrl: 'https://arb1.arbitrum.io/rpc',
54
- nativeCurrency: 'ETH',
55
- blockExplorer: 'https://arbiscan.io',
56
- wethAddress: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',
57
- usdcAddress: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
58
- dexRouters: {
59
- uniswap: '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45',
60
- },
61
- uniswapQuoter: '0x61fFE014bA17989E743c5F6cB21bF9697530B21e',
62
- acrossSpokePool: '0xe35e9842fceaCA96570B734083f4a58e8F7C5f2A',
63
- },
64
- polygon: {
65
- chainId: 137,
66
- name: 'polygon',
67
- viemChain: polygon,
68
- rpcUrl: 'https://polygon-bor-rpc.publicnode.com',
69
- nativeCurrency: 'POL',
70
- blockExplorer: 'https://polygonscan.com',
71
- wethAddress: '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270',
72
- usdcAddress: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',
73
- dexRouters: {
74
- uniswap: '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45',
75
- },
76
- uniswapQuoter: '0x61fFE014bA17989E743c5F6cB21bF9697530B21e',
77
- acrossSpokePool: '0x9295ee1d8C5b022Be115A2AD3c30C72E34e7F096',
78
- },
79
- };
80
-
81
- /**
82
- * Apply custom RPC endpoint overrides. Call once at startup.
83
- * Accepts a map of chain name (or chain ID string) → RPC URL.
84
- */
85
- export function applyRpcOverrides(overrides: Record<string, string>): void {
86
- for (const [key, url] of Object.entries(overrides)) {
87
- // Support both chain name ("base") and chain ID ("8453")
88
- const chain = CHAIN_CONFIGS[key.toLowerCase()]
89
- ?? Object.values(CHAIN_CONFIGS).find(c => c.chainId.toString() === key);
90
-
91
- if (chain) {
92
- chain.rpcUrl = url;
93
- console.log(`[chains] RPC override: ${chain.name} → ${url}`);
94
- } else {
95
- console.warn(`[chains] Unknown chain for RPC override: ${key}`);
96
- }
97
- }
98
- }
99
-
100
- export function getChainConfig(nameOrId: string | number): ChainConfig | undefined {
101
- if (typeof nameOrId === 'number') {
102
- return Object.values(CHAIN_CONFIGS).find(c => c.chainId === nameOrId);
103
- }
104
- return CHAIN_CONFIGS[nameOrId.toLowerCase()];
105
- }
package/src/cli.ts DELETED
@@ -1,244 +0,0 @@
1
- #!/usr/bin/env node
2
- import { Command } from 'commander';
3
- import { loadConfig, readConfigFile, writeConfigFile, updateSecureStore, writeSampleConfig } from './config.js';
4
- import { AgentRuntime } from './runtime.js';
5
- import { listTemplates } from './strategy/index.js';
6
- import { ensureLocalSetup, promptSecretPassword } from './setup.js';
7
- import { printBanner, printDone, printError, printInfo, printSuccess, pc } from './ui.js';
8
- import * as clack from '@clack/prompts';
9
-
10
- const program = new Command();
11
-
12
- program
13
- .name('exagent')
14
- .description('Exagent — LLM trading agent runtime')
15
- .version('0.3.5');
16
-
17
- program
18
- .command('init')
19
- .description('Create a sample agent configuration file')
20
- .option('--agent-id <id>', 'Agent ID (from dashboard)', 'my-agent')
21
- .option('--api-url <url>', 'API server URL', 'http://localhost:3002')
22
- .option('--config <path>', 'Config file path', 'agent-config.json')
23
- .action((opts) => {
24
- printBanner();
25
- writeSampleConfig(opts.agentId, opts.apiUrl, opts.config);
26
- printDone(`Created ${pc.cyan(opts.config)}`);
27
- console.log();
28
- console.log(` Edit only the public strategy/venue/risk settings.`);
29
- console.log(` Then run: ${pc.cyan(`exagent setup --config ${opts.config}`)}`);
30
- console.log();
31
- });
32
-
33
- program
34
- .command('setup')
35
- .description('Run first-time secure local setup for agent secrets')
36
- .option('--config <path>', 'Config file path', 'agent-config.json')
37
- .action(async (opts) => {
38
- try {
39
- await ensureLocalSetup(opts.config);
40
- } catch (err) {
41
- printError((err as Error).message);
42
- process.exit(1);
43
- }
44
- });
45
-
46
- program
47
- .command('run')
48
- .description('Start the agent')
49
- .option('--config <path>', 'Config file path', 'agent-config.json')
50
- .action(async (opts) => {
51
- try {
52
- await ensureLocalSetup(opts.config);
53
- printBanner();
54
- const config = await loadConfig(opts.config, {
55
- getSecretPassword: async () => promptSecretPassword(),
56
- });
57
- printDone(`Agent ${pc.cyan(config.agentId)} starting...`);
58
- console.log();
59
- const runtime = new AgentRuntime(config);
60
- await runtime.start();
61
-
62
- // Keep the process running
63
- await new Promise(() => {});
64
- } catch (err) {
65
- printError((err as Error).message);
66
- process.exit(1);
67
- }
68
- });
69
-
70
- program
71
- .command('templates')
72
- .description('List available strategy templates')
73
- .action(() => {
74
- printBanner();
75
- const templates = listTemplates();
76
- console.log(pc.bold(' Strategy Templates'));
77
- console.log();
78
- for (const t of templates) {
79
- console.log(` ${pc.cyan(t.id)}`);
80
- console.log(` ${t.name} — ${pc.dim(t.description)}`);
81
- console.log(` ${pc.dim(`Risk: ${t.riskLevel} | Venues: ${t.venues.join(', ') || 'any'}`)}`);
82
- console.log();
83
- }
84
- });
85
-
86
- program
87
- .command('status')
88
- .description('Check agent status')
89
- .option('--config <path>', 'Config file path', 'agent-config.json')
90
- .action(async (opts) => {
91
- try {
92
- await ensureLocalSetup(opts.config);
93
- printBanner();
94
- const config = await loadConfig(opts.config, {
95
- getSecretPassword: async () => promptSecretPassword(),
96
- });
97
- const res = await fetch(`${config.apiUrl}/v1/agents/${config.agentId}`, {
98
- headers: { Authorization: `Bearer ${config.apiToken}` },
99
- });
100
-
101
- if (!res.ok) {
102
- printError(`API error: ${res.status}`);
103
- process.exit(1);
104
- }
105
-
106
- const agent = await res.json() as Record<string, unknown>;
107
- const name = (agent.name as string) || config.agentId;
108
- const status = (agent.status as string) || 'unknown';
109
-
110
- const statusColor = status === 'online' ? pc.green : status === 'error' ? pc.red : pc.yellow;
111
-
112
- printSuccess(name, [
113
- `${pc.dim('Status:')} ${statusColor(status)}`,
114
- `${pc.dim('Agent:')} ${pc.cyan(config.agentId)}`,
115
- `${pc.dim('API:')} ${pc.dim(config.apiUrl)}`,
116
- ]);
117
- } catch (err) {
118
- printError((err as Error).message);
119
- process.exit(1);
120
- }
121
- });
122
-
123
- import { LLM_PROVIDERS, getProvider } from './llm-providers.js';
124
-
125
- program
126
- .command('config')
127
- .description('Change LLM provider, model, or API key')
128
- .option('--config <path>', 'Config file path', 'agent-config.json')
129
- .action(async (opts) => {
130
- try {
131
- printBanner();
132
- const config = readConfigFile(opts.config);
133
- const secureStorePath = config.secrets?.secureStorePath;
134
-
135
- if (!secureStorePath) {
136
- printError('No secure store found. Run setup first: npx exagent setup');
137
- process.exit(1);
138
- }
139
-
140
- clack.intro(pc.bold('Agent Configuration'));
141
-
142
- // Decrypt current secrets
143
- const password = await promptSecretPassword();
144
- const currentConfig = await loadConfig(opts.config, {
145
- getSecretPassword: async () => password,
146
- });
147
-
148
- // Show current LLM settings
149
- const currentProvider = currentConfig.llm.provider;
150
- const currentModel = currentConfig.llm.model || 'not set';
151
- const currentKey = currentConfig.llm.apiKey;
152
- const maskedKey = currentKey
153
- ? `${currentKey.slice(0, 7)}...${currentKey.slice(-4)}`
154
- : 'not set';
155
-
156
- printInfo(`Provider: ${pc.cyan(currentProvider)}`);
157
- printInfo(`Model: ${pc.cyan(currentModel)}`);
158
- printInfo(`API key: ${pc.dim(maskedKey)}`);
159
- console.log();
160
-
161
- const action = await clack.select({
162
- message: 'What would you like to change?',
163
- options: [
164
- { value: 'key', label: 'LLM API key' },
165
- { value: 'all', label: 'Provider, model, and API key' },
166
- ],
167
- });
168
- if (clack.isCancel(action)) {
169
- clack.cancel('Cancelled.');
170
- process.exit(0);
171
- }
172
-
173
- let newProvider: string = currentProvider;
174
- let newModel: string = currentModel;
175
-
176
- if (action === 'all') {
177
- const selectedProvider = await clack.select({
178
- message: 'LLM provider:',
179
- options: LLM_PROVIDERS.map(p => ({ value: p.id, label: p.label })),
180
- initialValue: currentProvider || undefined,
181
- });
182
- if (clack.isCancel(selectedProvider)) {
183
- clack.cancel('Cancelled.');
184
- process.exit(0);
185
- }
186
- newProvider = selectedProvider;
187
-
188
- const provider = getProvider(newProvider);
189
- const modelOptions = provider
190
- ? provider.models.map(m => ({ value: m.id, label: m.label }))
191
- : [{ value: currentModel, label: currentModel }];
192
-
193
- const selectedModel = await clack.select({
194
- message: 'LLM model:',
195
- options: modelOptions,
196
- initialValue: currentModel || undefined,
197
- });
198
- if (clack.isCancel(selectedModel)) {
199
- clack.cancel('Cancelled.');
200
- process.exit(0);
201
- }
202
- newModel = selectedModel;
203
- }
204
-
205
- const newKey = await clack.password({
206
- message: 'New LLM API key:',
207
- validate: (val) => {
208
- if (!val?.trim()) return 'API key is required.';
209
- if (val.length < 10) return 'API key seems too short.';
210
- },
211
- });
212
- if (clack.isCancel(newKey)) {
213
- clack.cancel('Cancelled.');
214
- process.exit(0);
215
- }
216
-
217
- // Update secure store with new API key
218
- updateSecureStore(secureStorePath, password, { llmApiKey: newKey });
219
-
220
- // Update config file with new provider/model
221
- const updatedConfig = readConfigFile(opts.config);
222
- updatedConfig.llm = {
223
- ...updatedConfig.llm,
224
- provider: newProvider as typeof updatedConfig.llm.provider,
225
- model: newModel,
226
- };
227
- writeConfigFile(opts.config, updatedConfig);
228
-
229
- clack.outro(pc.green('Configuration updated'));
230
-
231
- printSuccess('Updated', [
232
- `${pc.dim('Provider:')} ${pc.cyan(newProvider)}`,
233
- `${pc.dim('Model:')} ${pc.cyan(newModel)}`,
234
- `${pc.dim('API key:')} ${pc.dim(`${newKey.slice(0, 7)}...${newKey.slice(-4)}`)}`,
235
- '',
236
- `Run ${pc.cyan('npx exagent run')} to start with the new configuration.`,
237
- ]);
238
- } catch (err) {
239
- printError((err as Error).message);
240
- process.exit(1);
241
- }
242
- });
243
-
244
- program.parse();