@glide-pool/cli 0.1.1 → 0.1.2

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 (2) hide show
  1. package/bin/glidepool.js +98 -104
  2. package/package.json +2 -3
package/bin/glidepool.js CHANGED
@@ -1,12 +1,11 @@
1
1
  #!/usr/bin/env node
2
+ 'use strict';
2
3
 
3
- import { Command } from 'commander';
4
- import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
5
- import { homedir } from 'os';
6
- import { join } from 'path';
7
- import { createRequire } from 'module';
4
+ const { Command } = require('commander');
5
+ const { readFileSync, writeFileSync, existsSync, mkdirSync } = require('fs');
6
+ const { homedir } = require('os');
7
+ const { join } = require('path');
8
8
 
9
- const require = createRequire(import.meta.url);
10
9
  const pkg = require('../package.json');
11
10
 
12
11
  // ─────────────────────────────────────────
@@ -28,29 +27,37 @@ function saveConfig(data) {
28
27
  function getApiUrl(opts) {
29
28
  const url = opts.api || process.env.GLIDEPOOL_API_URL || loadConfig().apiUrl;
30
29
  if (!url) {
31
- console.error('Error: API URL required. Set via --api <url> or GLIDEPOOL_API_URL env or run: glidepool config set-api <url>');
30
+ console.error('Error: API URL not set.\n Run: glidepool config set-api <url>\n Or: export GLIDEPOOL_API_URL=https://your-instance.replit.app');
32
31
  process.exit(1);
33
32
  }
34
33
  return url.replace(/\/$/, '');
35
34
  }
36
35
 
37
36
  // ─────────────────────────────────────────
38
- // HTTP helper
37
+ // HTTP helper (native fetch, Node 18+)
39
38
  // ─────────────────────────────────────────
40
39
  async function apiFetch(apiUrl, path, options = {}) {
41
40
  const url = `${apiUrl}${path}`;
42
- const res = await fetch(url, {
43
- ...options,
44
- headers: { 'Content-Type': 'application/json', ...options.headers },
45
- });
41
+ let res;
42
+ try {
43
+ res = await fetch(url, {
44
+ ...options,
45
+ headers: { 'Content-Type': 'application/json', ...options.headers },
46
+ });
47
+ } catch (e) {
48
+ console.error(`Network error: ${e.message}`);
49
+ process.exit(1);
50
+ }
46
51
  const data = await res.json().catch(() => ({}));
47
52
  if (!res.ok) {
48
53
  if (res.status === 402) {
49
54
  console.error('\n[402] Payment Required');
50
- console.error(` Send ${data.amount || '0.05'} ${data.currency || 'USDC'} on Base to:`);
51
- console.error(` ${data.recipient}`);
52
- console.error(` Token: ${data.token}`);
53
- console.error(`\n Then retry with: --payment-proof <base64(JSON{txHash,from,amount})>`);
55
+ console.error(` Amount: ${data.amount || '0.05'} ${data.currency || 'USDC'}`);
56
+ console.error(` Recipient: ${data.recipient}`);
57
+ console.error(` Token: ${data.token}`);
58
+ console.error(` Network: Base Mainnet\n`);
59
+ console.error(' Send USDC to recipient on Base, then retry with:');
60
+ console.error(' --payment-proof <base64(JSON{txHash,from,amount})>');
54
61
  process.exit(2);
55
62
  }
56
63
  console.error(`API error (${res.status}): ${data.message || data.error || 'Unknown error'}`);
@@ -64,14 +71,15 @@ function printJson(data) {
64
71
  }
65
72
 
66
73
  function printTable(rows, columns) {
67
- const widths = columns.map(c => Math.max(c.label.length, ...rows.map(r => String(r[c.key] ?? '').length)));
68
- const header = columns.map((c, i) => c.label.padEnd(widths[i])).join(' ');
69
- const divider = widths.map(w => '-'.repeat(w)).join(' ');
70
- console.log(header);
71
- console.log(divider);
72
- rows.forEach(row => {
73
- console.log(columns.map((c, i) => String(row[c.key] ?? '').padEnd(widths[i])).join(' '));
74
- });
74
+ if (!rows.length) return;
75
+ const widths = columns.map(c =>
76
+ Math.max(c.label.length, ...rows.map(r => String(r[c.key] ?? '').length))
77
+ );
78
+ console.log(columns.map((c, i) => c.label.padEnd(widths[i])).join(' '));
79
+ console.log(widths.map(w => '-'.repeat(w)).join(' '));
80
+ rows.forEach(row =>
81
+ console.log(columns.map((c, i) => String(row[c.key] ?? '').padEnd(widths[i])).join(' '))
82
+ );
75
83
  }
76
84
 
77
85
  // ─────────────────────────────────────────
@@ -83,71 +91,66 @@ program
83
91
  .name('glidepool')
84
92
  .description('CLI for GlidePool — autonomous DLMM agent platform on Base Mainnet')
85
93
  .version(pkg.version)
86
- .option('--api <url>', 'GlidePool API URL (or set GLIDEPOOL_API_URL env var)')
94
+ .option('--api <url>', 'GlidePool API URL (or set GLIDEPOOL_API_URL)')
87
95
  .option('--json', 'Output raw JSON');
88
96
 
89
97
  // ── config ──────────────────────────────
90
- const config = program.command('config').description('Manage CLI configuration');
98
+ const configCmd = program.command('config').description('Manage CLI configuration');
91
99
 
92
- config
100
+ configCmd
93
101
  .command('set-api <url>')
94
- .description('Save the GlidePool API URL to ~/.glidepool/config.json')
102
+ .description('Save API URL to ~/.glidepool/config.json')
95
103
  .action((url) => {
96
104
  const cfg = loadConfig();
97
105
  cfg.apiUrl = url.replace(/\/$/, '');
98
106
  saveConfig(cfg);
99
- console.log(`Saved API URL: ${cfg.apiUrl}`);
107
+ console.log(`Saved: ${cfg.apiUrl}`);
100
108
  });
101
109
 
102
- config
110
+ configCmd
103
111
  .command('show')
104
- .description('Show current configuration')
105
- .action(() => {
106
- printJson({ configFile: CONFIG_FILE, ...loadConfig() });
107
- });
112
+ .description('Show current config (~/.glidepool/config.json)')
113
+ .action(() => { printJson({ configFile: CONFIG_FILE, ...loadConfig() }); });
108
114
 
109
115
  // ── pools ───────────────────────────────
110
- const pools = program.command('pools').description('List and inspect Maverick V2 pools');
116
+ const poolsCmd = program.command('pools').description('List and inspect Maverick V2 pools');
111
117
 
112
- pools
118
+ poolsCmd
113
119
  .command('list')
114
120
  .description('List all supported pools with live TVL, price, and fee rate')
115
- .action(async (_, cmd) => {
116
- const opts = program.opts();
117
- const api = getApiUrl(opts);
121
+ .action(async () => {
122
+ const api = getApiUrl(program.opts());
118
123
  const data = await apiFetch(api, '/api/pools');
119
- if (opts.json) { printJson(data); return; }
124
+ if (program.opts().json) { printJson(data); return; }
120
125
  printTable(data, [
121
- { key: 'tokenASymbol', label: 'TOKEN A' },
122
- { key: 'tokenBSymbol', label: 'TOKEN B' },
123
- { key: 'tvlUsd', label: 'TVL (USD)' },
126
+ { key: 'tokenASymbol', label: 'A' },
127
+ { key: 'tokenBSymbol', label: 'B' },
128
+ { key: 'tvlUsd', label: 'TVL USD' },
124
129
  { key: 'currentPrice', label: 'PRICE' },
125
130
  { key: 'feeRate', label: 'FEE' },
126
131
  { key: 'poolAddress', label: 'ADDRESS' },
127
132
  ]);
128
133
  });
129
134
 
130
- pools
135
+ poolsCmd
131
136
  .command('get <address>')
132
137
  .description('Get details for a specific pool')
133
138
  .action(async (address) => {
134
- const opts = program.opts();
135
- const api = getApiUrl(opts);
136
- const data = await apiFetch(api, `/api/pools/${address}`);
137
- printJson(data);
139
+ const api = getApiUrl(program.opts());
140
+ printJson(await apiFetch(api, `/api/pools/${address}`));
138
141
  });
139
142
 
140
143
  // ── agent ────────────────────────────────
141
- const agent = program.command('agent').description('Create and manage autonomous agents');
144
+ const agentCmd = program.command('agent').description('Create and manage autonomous agents');
142
145
 
143
- agent
146
+ agentCmd
144
147
  .command('create')
145
148
  .description('Deploy a new autonomous DLMM agent')
146
- .requiredOption('--wallet <address>', 'Your wallet address (0x...)')
147
- .requiredOption('--pool <address>', 'Maverick V2 pool address to monitor')
148
- .option('--strategy <strategy>', 'Strategy: conservative | balanced | aggressive', 'balanced')
149
- .option('--budget <usdc>', 'Max USDC budget for liquidity operations', '100')
150
- .option('--interval <seconds>', 'Analysis interval in seconds (min: 30)', '60')
149
+ .requiredOption('--wallet <address>', 'Wallet address (0x...)')
150
+ .requiredOption('--pool <address>', 'Maverick V2 pool address')
151
+ .option('--strategy <s>', 'conservative | balanced | aggressive', 'balanced')
152
+ .option('--budget <usdc>', 'Max USDC budget', '100')
153
+ .option('--interval <sec>', 'Analysis interval in seconds (min 30)', '60')
151
154
  .action(async (opts) => {
152
155
  const api = getApiUrl(program.opts());
153
156
  const data = await apiFetch(api, '/api/agents', {
@@ -161,97 +164,87 @@ agent
161
164
  }),
162
165
  });
163
166
  if (program.opts().json) { printJson(data); return; }
164
- console.log(`\nAgent deployed`);
167
+ console.log('\nAgent deployed');
165
168
  console.log(` ID: ${data.id}`);
166
169
  console.log(` Pool: ${data.poolAddress}`);
167
170
  console.log(` Strategy: ${data.strategy}`);
168
171
  console.log(` Budget: ${data.budgetUsdc} USDC`);
169
172
  console.log(` Status: ${data.status}`);
170
- console.log(`\nMonitor with: glidepool agent actions ${data.id}`);
173
+ console.log(`\nView actions: glidepool agent actions ${data.id}`);
171
174
  });
172
175
 
173
- agent
176
+ agentCmd
174
177
  .command('list')
175
- .description('List all agents for a wallet address')
178
+ .description('List all agents for a wallet')
176
179
  .requiredOption('--wallet <address>', 'Wallet address (0x...)')
177
180
  .action(async (opts) => {
178
181
  const api = getApiUrl(program.opts());
179
182
  const data = await apiFetch(api, `/api/agents?userAddress=${encodeURIComponent(opts.wallet)}`);
180
183
  if (program.opts().json) { printJson(data); return; }
181
- if (!data.length) { console.log('No agents found for this wallet.'); return; }
184
+ if (!data.length) { console.log('No agents found.'); return; }
182
185
  printTable(data, [
183
186
  { key: 'id', label: 'AGENT ID' },
184
187
  { key: 'poolAddress', label: 'POOL' },
185
188
  { key: 'strategy', label: 'STRATEGY' },
186
- { key: 'budgetUsdc', label: 'BUDGET USDC' },
189
+ { key: 'budgetUsdc', label: 'BUDGET' },
187
190
  { key: 'status', label: 'STATUS' },
188
191
  { key: 'lastAnalysisAt', label: 'LAST ANALYSIS' },
189
192
  ]);
190
193
  });
191
194
 
192
- agent
195
+ agentCmd
193
196
  .command('get <agentId>')
194
197
  .description('Get details for a specific agent')
195
198
  .action(async (agentId) => {
196
199
  const api = getApiUrl(program.opts());
197
- const data = await apiFetch(api, `/api/agents/${agentId}`);
198
- printJson(data);
200
+ printJson(await apiFetch(api, `/api/agents/${agentId}`));
199
201
  });
200
202
 
201
- agent
203
+ agentCmd
202
204
  .command('pause <agentId>')
203
205
  .description('Pause a running agent')
204
206
  .action(async (agentId) => {
205
207
  const api = getApiUrl(program.opts());
206
- await apiFetch(api, `/api/agents/${agentId}/status`, {
207
- method: 'PUT',
208
- body: JSON.stringify({ status: 'paused' }),
209
- });
208
+ await apiFetch(api, `/api/agents/${agentId}/status`, { method: 'PUT', body: JSON.stringify({ status: 'paused' }) });
210
209
  console.log(`Agent ${agentId} paused.`);
211
210
  });
212
211
 
213
- agent
212
+ agentCmd
214
213
  .command('resume <agentId>')
215
214
  .description('Resume a paused agent')
216
215
  .action(async (agentId) => {
217
216
  const api = getApiUrl(program.opts());
218
- await apiFetch(api, `/api/agents/${agentId}/status`, {
219
- method: 'PUT',
220
- body: JSON.stringify({ status: 'active' }),
221
- });
217
+ await apiFetch(api, `/api/agents/${agentId}/status`, { method: 'PUT', body: JSON.stringify({ status: 'active' }) });
222
218
  console.log(`Agent ${agentId} resumed.`);
223
219
  });
224
220
 
225
- agent
221
+ agentCmd
226
222
  .command('stop <agentId>')
227
223
  .description('Stop an agent permanently')
228
224
  .action(async (agentId) => {
229
225
  const api = getApiUrl(program.opts());
230
- await apiFetch(api, `/api/agents/${agentId}/status`, {
231
- method: 'PUT',
232
- body: JSON.stringify({ status: 'stopped' }),
233
- });
226
+ await apiFetch(api, `/api/agents/${agentId}/status`, { method: 'PUT', body: JSON.stringify({ status: 'stopped' }) });
234
227
  console.log(`Agent ${agentId} stopped.`);
235
228
  });
236
229
 
237
- agent
230
+ agentCmd
238
231
  .command('actions <agentId>')
239
- .description('Show LLM decisions (actions) for an agent')
240
- .option('--limit <n>', 'Number of actions to show', '10')
232
+ .description('Show LLM decisions stored in the database')
233
+ .option('--limit <n>', 'Number of actions', '10')
241
234
  .action(async (agentId, opts) => {
242
235
  const api = getApiUrl(program.opts());
243
236
  const data = await apiFetch(api, `/api/agents/${agentId}/actions?limit=${opts.limit}`);
244
237
  if (program.opts().json) { printJson(data); return; }
245
- if (!data.length) { console.log('No actions yet. Agent will analyze on its next cycle.'); return; }
238
+ if (!data.length) { console.log('No actions yet. Agent analyzes on its next cycle.'); return; }
246
239
  data.forEach((a) => {
247
240
  const ts = new Date(a.createdAt).toLocaleTimeString();
248
241
  const rec = a.llmRecommendation;
249
- console.log(`\n[${ts}] ${a.actionType.toUpperCase()} — ${a.status}`);
250
- if (rec?.riskLevel) console.log(` Risk: ${rec.riskLevel}`);
251
- if (a.llmReasoning) console.log(` Reason: ${a.llmReasoning.slice(0, 200)}...`);
252
- if (rec?.recommendation?.suggestedBinRange) {
242
+ console.log(`\n[${ts}] ${a.actionType.toUpperCase()} status=${a.status}`);
243
+ if (rec && rec.riskLevel) console.log(` Risk: ${rec.riskLevel}`);
244
+ if (a.llmReasoning) console.log(` Reason: ${String(a.llmReasoning).slice(0, 180)}...`);
245
+ if (rec && rec.recommendation && rec.recommendation.suggestedBinRange) {
253
246
  const r = rec.recommendation.suggestedBinRange;
254
- console.log(` Bins: lower=${r.lowerTick} upper=${r.upperTick}`);
247
+ console.log(` Bins: lower=${r.lowerTick} upper=${r.upperTick}`);
255
248
  }
256
249
  if (a.txHash) console.log(` TX: ${a.txHash}`);
257
250
  });
@@ -265,7 +258,7 @@ program
265
258
  const api = getApiUrl(program.opts());
266
259
  const data = await apiFetch(api, `/api/positions/${walletAddress}`);
267
260
  if (program.opts().json) { printJson(data); return; }
268
- if (!data.length) { console.log('No Maverick V2 positions found for this wallet.'); return; }
261
+ if (!data.length) { console.log('No Maverick V2 positions found.'); return; }
269
262
  printTable(data, [
270
263
  { key: 'nftId', label: 'NFT ID' },
271
264
  { key: 'tokenASymbol', label: 'TOKEN A' },
@@ -280,11 +273,11 @@ program
280
273
  // ── advisor ──────────────────────────────
281
274
  program
282
275
  .command('advisor')
283
- .description('Get a Claude Opus 4 AI recommendation for a pool position')
284
- .requiredOption('--pool <address>', 'Pool address to analyze')
285
- .requiredOption('--goal <text>', 'Your liquidity goal (e.g. "maximize fee income with low IL")')
286
- .option('--nft <id>', 'NFT position ID if analyzing an existing position')
287
- .option('--payment-proof <base64>', 'x402 payment proof header (if server requires payment)')
276
+ .description('Get Claude Opus 4 AI recommendation for a pool position')
277
+ .requiredOption('--pool <address>', 'Pool address')
278
+ .requiredOption('--goal <text>', 'Your liquidity goal')
279
+ .option('--nft <id>', 'NFT ID for existing position analysis')
280
+ .option('--payment-proof <base64>', 'x402 payment proof (if server requires payment)')
288
281
  .action(async (opts) => {
289
282
  const api = getApiUrl(program.opts());
290
283
  const qs = new URLSearchParams({ poolAddress: opts.pool, userGoal: opts.goal });
@@ -293,19 +286,20 @@ program
293
286
  if (opts.paymentProof) headers['x-payment-proof'] = opts.paymentProof;
294
287
  const data = await apiFetch(api, `/api/advisor?${qs}`, { headers });
295
288
  if (program.opts().json) { printJson(data); return; }
296
- console.log(`\n── AI Advisor ──────────────────────────`);
297
- console.log(` Action: ${data.recommendation?.action?.toUpperCase()}`);
289
+ const rec = data.recommendation || {};
290
+ console.log('\n── AI Advisor ──────────────────────────');
291
+ console.log(` Action: ${(rec.action || '').toUpperCase()}`);
298
292
  console.log(` Risk: ${data.riskLevel}`);
299
293
  console.log(` Summary: ${data.summary}`);
300
- if (data.recommendation?.suggestedBinRange) {
301
- const r = data.recommendation.suggestedBinRange;
302
- console.log(` Bins: lower=${r.lowerTick} upper=${r.upperTick}`);
294
+ if (rec.suggestedBinRange) {
295
+ console.log(` Bins: lower=${rec.suggestedBinRange.lowerTick} upper=${rec.suggestedBinRange.upperTick}`);
296
+ }
297
+ if (rec.suggestedWithdrawPercent) {
298
+ console.log(` Withdraw: ${rec.suggestedWithdrawPercent}%`);
303
299
  }
304
- if (data.recommendation?.suggestedWithdrawPercent) {
305
- console.log(` Withdraw: ${data.recommendation.suggestedWithdrawPercent}%`);
300
+ if (rec.reasoning) {
301
+ console.log(`\n Reasoning:\n ${rec.reasoning}`);
306
302
  }
307
- console.log(`\n Reasoning:`);
308
- console.log(` ${data.recommendation?.reasoning}`);
309
303
  });
310
304
 
311
- program.parse();
305
+ program.parse(process.argv);
package/package.json CHANGED
@@ -1,10 +1,9 @@
1
1
  {
2
2
  "name": "@glide-pool/cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "CLI for managing GlidePool autonomous DLMM agents on Base Mainnet",
5
- "type": "module",
6
5
  "bin": {
7
- "glidepool": "./bin/glidepool"
6
+ "glidepool": "./bin/glidepool.js"
8
7
  },
9
8
  "files": [
10
9
  "bin",