@glide-pool/cli 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.
Files changed (3) hide show
  1. package/README.md +198 -0
  2. package/bin/glidepool.js +311 -0
  3. package/package.json +39 -0
package/README.md ADDED
@@ -0,0 +1,198 @@
1
+ # @glide-pool/cli
2
+
3
+ CLI for [GlidePool](https://github.com/glide-pool/glidepool) — autonomous DLMM agent platform on Base Mainnet.
4
+
5
+ Manage agents, browse pools, inspect positions, and get Claude Opus 4 AI advice directly from your terminal.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install -g @glide-pool/cli
11
+ ```
12
+
13
+ ## Setup
14
+
15
+ Point the CLI at your GlidePool API server:
16
+
17
+ ```bash
18
+ # Save API URL to ~/.glidepool/config.json
19
+ glidepool config set-api https://your-glidepool-instance.replit.app
20
+
21
+ # Or use the --api flag on every command
22
+ glidepool --api https://your-instance.replit.app pools list
23
+
24
+ # Or set the env var
25
+ export GLIDEPOOL_API_URL=https://your-glidepool-instance.replit.app
26
+ ```
27
+
28
+ ## Commands
29
+
30
+ ### `glidepool config`
31
+
32
+ ```bash
33
+ glidepool config set-api <url> # Save API URL
34
+ glidepool config show # Show current config
35
+ ```
36
+
37
+ ---
38
+
39
+ ### `glidepool pools`
40
+
41
+ ```bash
42
+ # List all supported Maverick V2 pools (live TVL, price, fee)
43
+ glidepool pools list
44
+
45
+ # Output:
46
+ # TOKEN A TOKEN B TVL (USD) PRICE FEE ADDRESS
47
+ # ------- ------- --------- ------ ----- ----------
48
+ # WETH USDC 21311 0.0004 0.0015 0x3d70...
49
+ # DAI USDC 64203 0.9998 0.00002 0x1a2b...
50
+
51
+ # Get details for a specific pool
52
+ glidepool pools get 0x3d70b2f31f75dc84acdd5e1588695221959b2d37
53
+
54
+ # Raw JSON output (all commands support --json)
55
+ glidepool pools list --json
56
+ ```
57
+
58
+ ---
59
+
60
+ ### `glidepool agent`
61
+
62
+ ```bash
63
+ # Deploy a new autonomous agent
64
+ glidepool agent create \
65
+ --wallet 0xYourWallet \
66
+ --pool 0x3d70b2f31f75dc84acdd5e1588695221959b2d37 \
67
+ --strategy balanced \
68
+ --budget 100 \
69
+ --interval 60
70
+
71
+ # Output:
72
+ # Agent deployed
73
+ # ID: 4df9a63d-30eb-4885-87fc-f44f98baadbe
74
+ # Pool: 0x3d70b2f31f75dc84acdd5e1588695221959b2d37
75
+ # Strategy: balanced
76
+ # Budget: 100 USDC
77
+ # Status: active
78
+
79
+ # List all agents for a wallet
80
+ glidepool agent list --wallet 0xYourWallet
81
+
82
+ # Get a single agent
83
+ glidepool agent get <agentId>
84
+
85
+ # Pause / resume / stop
86
+ glidepool agent pause <agentId>
87
+ glidepool agent resume <agentId>
88
+ glidepool agent stop <agentId>
89
+
90
+ # View LLM decisions (last 10 by default)
91
+ glidepool agent actions <agentId>
92
+ glidepool agent actions <agentId> --limit 20
93
+
94
+ # Output:
95
+ # [03:31:28] HOLD — completed
96
+ # Risk: high
97
+ # Reason: Pool reserves are low, price is volatile. Holding current position...
98
+ #
99
+ # [03:32:00] REBALANCE — pending_signature
100
+ # Risk: medium
101
+ # Bins: lower=-5 upper=5
102
+ ```
103
+
104
+ ---
105
+
106
+ ### `glidepool positions`
107
+
108
+ ```bash
109
+ # List Maverick V2 LP positions for a wallet
110
+ glidepool positions 0xYourWallet
111
+
112
+ # Output:
113
+ # NFT ID TOKEN A TOKEN B VALUE USD AMOUNT A AMOUNT B BINS
114
+ # ------ ------- ------- --------- -------- -------- ----
115
+ # 1234 WETH USDC 523.40 0.150000 285.2200 3
116
+ ```
117
+
118
+ ---
119
+
120
+ ### `glidepool advisor`
121
+
122
+ ```bash
123
+ # Get Claude Opus 4 analysis for a pool
124
+ glidepool advisor \
125
+ --pool 0x3d70b2f31f75dc84acdd5e1588695221959b2d37 \
126
+ --goal "maximize fee income with minimal impermanent loss"
127
+
128
+ # Analyze an existing position
129
+ glidepool advisor \
130
+ --pool 0x3d70b2f31f75dc84acdd5e1588695221959b2d37 \
131
+ --goal "should I rebalance or hold?" \
132
+ --nft 1234
133
+
134
+ # Output:
135
+ # ── AI Advisor ──────────────────────────
136
+ # Action: HOLD
137
+ # Risk: low
138
+ # Summary: Pool is in a healthy state. Current price is centered in your bin range.
139
+ #
140
+ # Reasoning:
141
+ # The active tick is within the optimal range. Fee generation is consistent.
142
+ # No rebalance needed at this time. Monitor for price drift above tick 150.
143
+ ```
144
+
145
+ **x402 payments:** If the server requires payment (`X402_ENABLED=true`), the CLI shows:
146
+ ```
147
+ [402] Payment Required
148
+ Send 0.05 USDC on Base to:
149
+ 0xTreasuryAddress...
150
+ Token: 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
151
+
152
+ Then retry with: --payment-proof <base64(JSON{txHash,from,amount})>
153
+ ```
154
+
155
+ Once you've sent the USDC:
156
+ ```bash
157
+ PROOF=$(echo '{"txHash":"0x...","from":"0xYour...","amount":"0.05"}' | base64)
158
+ glidepool advisor --pool 0x3d70... --goal "..." --payment-proof "$PROOF"
159
+ ```
160
+
161
+ ---
162
+
163
+ ## Global Options
164
+
165
+ | Flag | Description |
166
+ |---|---|
167
+ | `--api <url>` | Override API URL for this command |
168
+ | `--json` | Output raw JSON (useful for scripting) |
169
+ | `--version` | Show CLI version |
170
+ | `--help` | Show help |
171
+
172
+ ---
173
+
174
+ ## Agent Strategies
175
+
176
+ | Strategy | Mode | Description |
177
+ |---|---|---|
178
+ | `conservative` | Static bins | Tight fixed range, low risk |
179
+ | `balanced` | Both (follows price) | Medium risk, adapts to price movement |
180
+ | `aggressive` | Right/Left (trend) | Higher exposure, follows price direction |
181
+
182
+ The agent server runs Claude Opus 4 on each cycle. It analyzes pool state (activeTick, TVL, reserves, price) against your goal and produces one of:
183
+ - **hold** — current position is optimal, no action needed
184
+ - **rebalance** — shift bin range, requires wallet signature
185
+ - **withdraw** — remove liquidity, requires wallet signature
186
+ - **add_liquidity** — add more liquidity, requires wallet signature
187
+ - **switch_mode** — change bin mode, requires wallet signature
188
+
189
+ All on-chain actions require your explicit wallet signature — the GlidePool server never holds your private keys.
190
+
191
+ ## Requirements
192
+
193
+ - Node.js >= 18
194
+ - A running GlidePool API server
195
+
196
+ ## License
197
+
198
+ MIT
@@ -0,0 +1,311 @@
1
+ #!/usr/bin/env node
2
+
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';
8
+
9
+ const require = createRequire(import.meta.url);
10
+ const pkg = require('../package.json');
11
+
12
+ // ─────────────────────────────────────────
13
+ // Config
14
+ // ─────────────────────────────────────────
15
+ const CONFIG_DIR = join(homedir(), '.glidepool');
16
+ const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
17
+
18
+ function loadConfig() {
19
+ if (!existsSync(CONFIG_FILE)) return {};
20
+ try { return JSON.parse(readFileSync(CONFIG_FILE, 'utf8')); } catch { return {}; }
21
+ }
22
+
23
+ function saveConfig(data) {
24
+ mkdirSync(CONFIG_DIR, { recursive: true });
25
+ writeFileSync(CONFIG_FILE, JSON.stringify(data, null, 2));
26
+ }
27
+
28
+ function getApiUrl(opts) {
29
+ const url = opts.api || process.env.GLIDEPOOL_API_URL || loadConfig().apiUrl;
30
+ 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>');
32
+ process.exit(1);
33
+ }
34
+ return url.replace(/\/$/, '');
35
+ }
36
+
37
+ // ─────────────────────────────────────────
38
+ // HTTP helper
39
+ // ─────────────────────────────────────────
40
+ async function apiFetch(apiUrl, path, options = {}) {
41
+ const url = `${apiUrl}${path}`;
42
+ const res = await fetch(url, {
43
+ ...options,
44
+ headers: { 'Content-Type': 'application/json', ...options.headers },
45
+ });
46
+ const data = await res.json().catch(() => ({}));
47
+ if (!res.ok) {
48
+ if (res.status === 402) {
49
+ 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})>`);
54
+ process.exit(2);
55
+ }
56
+ console.error(`API error (${res.status}): ${data.message || data.error || 'Unknown error'}`);
57
+ process.exit(1);
58
+ }
59
+ return data;
60
+ }
61
+
62
+ function printJson(data) {
63
+ console.log(JSON.stringify(data, null, 2));
64
+ }
65
+
66
+ 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
+ });
75
+ }
76
+
77
+ // ─────────────────────────────────────────
78
+ // CLI
79
+ // ─────────────────────────────────────────
80
+ const program = new Command();
81
+
82
+ program
83
+ .name('glidepool')
84
+ .description('CLI for GlidePool — autonomous DLMM agent platform on Base Mainnet')
85
+ .version(pkg.version)
86
+ .option('--api <url>', 'GlidePool API URL (or set GLIDEPOOL_API_URL env var)')
87
+ .option('--json', 'Output raw JSON');
88
+
89
+ // ── config ──────────────────────────────
90
+ const config = program.command('config').description('Manage CLI configuration');
91
+
92
+ config
93
+ .command('set-api <url>')
94
+ .description('Save the GlidePool API URL to ~/.glidepool/config.json')
95
+ .action((url) => {
96
+ const cfg = loadConfig();
97
+ cfg.apiUrl = url.replace(/\/$/, '');
98
+ saveConfig(cfg);
99
+ console.log(`Saved API URL: ${cfg.apiUrl}`);
100
+ });
101
+
102
+ config
103
+ .command('show')
104
+ .description('Show current configuration')
105
+ .action(() => {
106
+ printJson({ configFile: CONFIG_FILE, ...loadConfig() });
107
+ });
108
+
109
+ // ── pools ───────────────────────────────
110
+ const pools = program.command('pools').description('List and inspect Maverick V2 pools');
111
+
112
+ pools
113
+ .command('list')
114
+ .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);
118
+ const data = await apiFetch(api, '/api/pools');
119
+ if (opts.json) { printJson(data); return; }
120
+ printTable(data, [
121
+ { key: 'tokenASymbol', label: 'TOKEN A' },
122
+ { key: 'tokenBSymbol', label: 'TOKEN B' },
123
+ { key: 'tvlUsd', label: 'TVL (USD)' },
124
+ { key: 'currentPrice', label: 'PRICE' },
125
+ { key: 'feeRate', label: 'FEE' },
126
+ { key: 'poolAddress', label: 'ADDRESS' },
127
+ ]);
128
+ });
129
+
130
+ pools
131
+ .command('get <address>')
132
+ .description('Get details for a specific pool')
133
+ .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);
138
+ });
139
+
140
+ // ── agent ────────────────────────────────
141
+ const agent = program.command('agent').description('Create and manage autonomous agents');
142
+
143
+ agent
144
+ .command('create')
145
+ .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')
151
+ .action(async (opts) => {
152
+ const api = getApiUrl(program.opts());
153
+ const data = await apiFetch(api, '/api/agents', {
154
+ method: 'POST',
155
+ body: JSON.stringify({
156
+ userAddress: opts.wallet,
157
+ poolAddress: opts.pool,
158
+ strategy: opts.strategy,
159
+ budgetUsdc: Number(opts.budget),
160
+ analysisIntervalSec: Number(opts.interval),
161
+ }),
162
+ });
163
+ if (program.opts().json) { printJson(data); return; }
164
+ console.log(`\nAgent deployed`);
165
+ console.log(` ID: ${data.id}`);
166
+ console.log(` Pool: ${data.poolAddress}`);
167
+ console.log(` Strategy: ${data.strategy}`);
168
+ console.log(` Budget: ${data.budgetUsdc} USDC`);
169
+ console.log(` Status: ${data.status}`);
170
+ console.log(`\nMonitor with: glidepool agent actions ${data.id}`);
171
+ });
172
+
173
+ agent
174
+ .command('list')
175
+ .description('List all agents for a wallet address')
176
+ .requiredOption('--wallet <address>', 'Wallet address (0x...)')
177
+ .action(async (opts) => {
178
+ const api = getApiUrl(program.opts());
179
+ const data = await apiFetch(api, `/api/agents?userAddress=${encodeURIComponent(opts.wallet)}`);
180
+ if (program.opts().json) { printJson(data); return; }
181
+ if (!data.length) { console.log('No agents found for this wallet.'); return; }
182
+ printTable(data, [
183
+ { key: 'id', label: 'AGENT ID' },
184
+ { key: 'poolAddress', label: 'POOL' },
185
+ { key: 'strategy', label: 'STRATEGY' },
186
+ { key: 'budgetUsdc', label: 'BUDGET USDC' },
187
+ { key: 'status', label: 'STATUS' },
188
+ { key: 'lastAnalysisAt', label: 'LAST ANALYSIS' },
189
+ ]);
190
+ });
191
+
192
+ agent
193
+ .command('get <agentId>')
194
+ .description('Get details for a specific agent')
195
+ .action(async (agentId) => {
196
+ const api = getApiUrl(program.opts());
197
+ const data = await apiFetch(api, `/api/agents/${agentId}`);
198
+ printJson(data);
199
+ });
200
+
201
+ agent
202
+ .command('pause <agentId>')
203
+ .description('Pause a running agent')
204
+ .action(async (agentId) => {
205
+ const api = getApiUrl(program.opts());
206
+ await apiFetch(api, `/api/agents/${agentId}/status`, {
207
+ method: 'PUT',
208
+ body: JSON.stringify({ status: 'paused' }),
209
+ });
210
+ console.log(`Agent ${agentId} paused.`);
211
+ });
212
+
213
+ agent
214
+ .command('resume <agentId>')
215
+ .description('Resume a paused agent')
216
+ .action(async (agentId) => {
217
+ const api = getApiUrl(program.opts());
218
+ await apiFetch(api, `/api/agents/${agentId}/status`, {
219
+ method: 'PUT',
220
+ body: JSON.stringify({ status: 'active' }),
221
+ });
222
+ console.log(`Agent ${agentId} resumed.`);
223
+ });
224
+
225
+ agent
226
+ .command('stop <agentId>')
227
+ .description('Stop an agent permanently')
228
+ .action(async (agentId) => {
229
+ const api = getApiUrl(program.opts());
230
+ await apiFetch(api, `/api/agents/${agentId}/status`, {
231
+ method: 'PUT',
232
+ body: JSON.stringify({ status: 'stopped' }),
233
+ });
234
+ console.log(`Agent ${agentId} stopped.`);
235
+ });
236
+
237
+ agent
238
+ .command('actions <agentId>')
239
+ .description('Show LLM decisions (actions) for an agent')
240
+ .option('--limit <n>', 'Number of actions to show', '10')
241
+ .action(async (agentId, opts) => {
242
+ const api = getApiUrl(program.opts());
243
+ const data = await apiFetch(api, `/api/agents/${agentId}/actions?limit=${opts.limit}`);
244
+ if (program.opts().json) { printJson(data); return; }
245
+ if (!data.length) { console.log('No actions yet. Agent will analyze on its next cycle.'); return; }
246
+ data.forEach((a) => {
247
+ const ts = new Date(a.createdAt).toLocaleTimeString();
248
+ 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) {
253
+ const r = rec.recommendation.suggestedBinRange;
254
+ console.log(` Bins: lower=${r.lowerTick} upper=${r.upperTick}`);
255
+ }
256
+ if (a.txHash) console.log(` TX: ${a.txHash}`);
257
+ });
258
+ });
259
+
260
+ // ── positions ────────────────────────────
261
+ program
262
+ .command('positions <walletAddress>')
263
+ .description('List Maverick V2 LP positions for a wallet on Base Mainnet')
264
+ .action(async (walletAddress) => {
265
+ const api = getApiUrl(program.opts());
266
+ const data = await apiFetch(api, `/api/positions/${walletAddress}`);
267
+ if (program.opts().json) { printJson(data); return; }
268
+ if (!data.length) { console.log('No Maverick V2 positions found for this wallet.'); return; }
269
+ printTable(data, [
270
+ { key: 'nftId', label: 'NFT ID' },
271
+ { key: 'tokenASymbol', label: 'TOKEN A' },
272
+ { key: 'tokenBSymbol', label: 'TOKEN B' },
273
+ { key: 'valueUsd', label: 'VALUE USD' },
274
+ { key: 'amountA', label: 'AMOUNT A' },
275
+ { key: 'amountB', label: 'AMOUNT B' },
276
+ { key: 'binCount', label: 'BINS' },
277
+ ]);
278
+ });
279
+
280
+ // ── advisor ──────────────────────────────
281
+ program
282
+ .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)')
288
+ .action(async (opts) => {
289
+ const api = getApiUrl(program.opts());
290
+ const qs = new URLSearchParams({ poolAddress: opts.pool, userGoal: opts.goal });
291
+ if (opts.nft) qs.set('nftId', opts.nft);
292
+ const headers = {};
293
+ if (opts.paymentProof) headers['x-payment-proof'] = opts.paymentProof;
294
+ const data = await apiFetch(api, `/api/advisor?${qs}`, { headers });
295
+ if (program.opts().json) { printJson(data); return; }
296
+ console.log(`\n── AI Advisor ──────────────────────────`);
297
+ console.log(` Action: ${data.recommendation?.action?.toUpperCase()}`);
298
+ console.log(` Risk: ${data.riskLevel}`);
299
+ 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}`);
303
+ }
304
+ if (data.recommendation?.suggestedWithdrawPercent) {
305
+ console.log(` Withdraw: ${data.recommendation.suggestedWithdrawPercent}%`);
306
+ }
307
+ console.log(`\n Reasoning:`);
308
+ console.log(` ${data.recommendation?.reasoning}`);
309
+ });
310
+
311
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@glide-pool/cli",
3
+ "version": "0.1.0",
4
+ "description": "CLI for managing GlidePool autonomous DLMM agents on Base Mainnet",
5
+ "type": "module",
6
+ "bin": {
7
+ "glidepool": "./bin/glidepool.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "src",
12
+ "README.md"
13
+ ],
14
+ "keywords": [
15
+ "glidepool",
16
+ "dlmm",
17
+ "maverick",
18
+ "base",
19
+ "defi",
20
+ "liquidity",
21
+ "agent",
22
+ "cli"
23
+ ],
24
+ "author": "glide-pool",
25
+ "license": "MIT",
26
+ "engines": {
27
+ "node": ">=18"
28
+ },
29
+ "dependencies": {
30
+ "commander": "^12.1.0"
31
+ },
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/glide-pool/glidepool"
35
+ },
36
+ "publishConfig": {
37
+ "access": "public"
38
+ }
39
+ }