@glide-pool/cli 0.1.1 → 0.1.3
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 +5 -5
- package/bin/glidepool.js +98 -104
- package/package.json +4 -5
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @glide-pool/cli
|
|
2
2
|
|
|
3
|
-
CLI for [GlidePool](https://github.com/
|
|
3
|
+
CLI for [GlidePool](https://github.com/GlidePool/glidepool) — autonomous DLMM agent platform on Base Mainnet.
|
|
4
4
|
|
|
5
5
|
Manage agents, browse pools, inspect positions, and get Claude Opus 4 AI advice directly from your terminal.
|
|
6
6
|
|
|
@@ -16,13 +16,13 @@ Point the CLI at your GlidePool API server:
|
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
18
|
# Save API URL to ~/.glidepool/config.json
|
|
19
|
-
glidepool config set-api https://
|
|
19
|
+
glidepool config set-api https://api.glidepool.xyz
|
|
20
20
|
|
|
21
21
|
# Or use the --api flag on every command
|
|
22
|
-
glidepool --api https://
|
|
22
|
+
glidepool --api https://api.glidepool.xyz pools list
|
|
23
23
|
|
|
24
|
-
# Or set the
|
|
25
|
-
export GLIDEPOOL_API_URL=https://
|
|
24
|
+
# Or set the environment variable
|
|
25
|
+
export GLIDEPOOL_API_URL=https://api.glidepool.xyz
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
## Commands
|
package/bin/glidepool.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
|
30
|
+
console.error('Error: API URL not set.\n Run: glidepool config set-api <url>\n Or: export GLIDEPOOL_API_URL=https://api.glidepool.xyz');
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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(`
|
|
51
|
-
console.error(` ${data.recipient}`);
|
|
52
|
-
console.error(` Token:
|
|
53
|
-
console.error(
|
|
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
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
console.log(
|
|
72
|
-
|
|
73
|
-
|
|
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
|
|
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
|
|
98
|
+
const configCmd = program.command('config').description('Manage CLI configuration');
|
|
91
99
|
|
|
92
|
-
|
|
100
|
+
configCmd
|
|
93
101
|
.command('set-api <url>')
|
|
94
|
-
.description('Save
|
|
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
|
|
107
|
+
console.log(`Saved: ${cfg.apiUrl}`);
|
|
100
108
|
});
|
|
101
109
|
|
|
102
|
-
|
|
110
|
+
configCmd
|
|
103
111
|
.command('show')
|
|
104
|
-
.description('Show current
|
|
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
|
|
116
|
+
const poolsCmd = program.command('pools').description('List and inspect Maverick V2 pools');
|
|
111
117
|
|
|
112
|
-
|
|
118
|
+
poolsCmd
|
|
113
119
|
.command('list')
|
|
114
120
|
.description('List all supported pools with live TVL, price, and fee rate')
|
|
115
|
-
.action(async (
|
|
116
|
-
const
|
|
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: '
|
|
122
|
-
{ key: 'tokenBSymbol', label: '
|
|
123
|
-
{ key: 'tvlUsd', label: 'TVL
|
|
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
|
-
|
|
135
|
+
poolsCmd
|
|
131
136
|
.command('get <address>')
|
|
132
137
|
.description('Get details for a specific pool')
|
|
133
138
|
.action(async (address) => {
|
|
134
|
-
const
|
|
135
|
-
|
|
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
|
|
144
|
+
const agentCmd = program.command('agent').description('Create and manage autonomous agents');
|
|
142
145
|
|
|
143
|
-
|
|
146
|
+
agentCmd
|
|
144
147
|
.command('create')
|
|
145
148
|
.description('Deploy a new autonomous DLMM agent')
|
|
146
|
-
.requiredOption('--wallet <address>', '
|
|
147
|
-
.requiredOption('--pool <address>', 'Maverick V2 pool address
|
|
148
|
-
.option('--strategy <
|
|
149
|
-
.option('--budget <usdc>', 'Max USDC budget
|
|
150
|
-
.option('--interval <
|
|
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(
|
|
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(`\
|
|
173
|
+
console.log(`\nView actions: glidepool agent actions ${data.id}`);
|
|
171
174
|
});
|
|
172
175
|
|
|
173
|
-
|
|
176
|
+
agentCmd
|
|
174
177
|
.command('list')
|
|
175
|
-
.description('List all agents for a wallet
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
198
|
-
printJson(data);
|
|
200
|
+
printJson(await apiFetch(api, `/api/agents/${agentId}`));
|
|
199
201
|
});
|
|
200
202
|
|
|
201
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
230
|
+
agentCmd
|
|
238
231
|
.command('actions <agentId>')
|
|
239
|
-
.description('Show LLM decisions
|
|
240
|
-
.option('--limit <n>', 'Number of actions
|
|
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
|
|
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()}
|
|
250
|
-
if (rec
|
|
251
|
-
if (a.llmReasoning) console.log(` Reason: ${a.llmReasoning.slice(0,
|
|
252
|
-
if (rec
|
|
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}
|
|
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
|
|
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
|
|
284
|
-
.requiredOption('--pool <address>', 'Pool address
|
|
285
|
-
.requiredOption('--goal <text>', 'Your liquidity goal
|
|
286
|
-
.option('--nft <id>', 'NFT
|
|
287
|
-
.option('--payment-proof <base64>', 'x402 payment proof
|
|
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
|
-
|
|
297
|
-
console.log(
|
|
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 (
|
|
301
|
-
|
|
302
|
-
|
|
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 (
|
|
305
|
-
console.log(
|
|
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.
|
|
3
|
+
"version": "0.1.3",
|
|
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",
|
|
@@ -30,9 +29,9 @@
|
|
|
30
29
|
},
|
|
31
30
|
"repository": {
|
|
32
31
|
"type": "git",
|
|
33
|
-
"url": "https://github.com/
|
|
32
|
+
"url": "https://github.com/GlidePool/cli"
|
|
34
33
|
},
|
|
35
34
|
"publishConfig": {
|
|
36
35
|
"access": "public"
|
|
37
36
|
}
|
|
38
|
-
}
|
|
37
|
+
}
|