@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.
- package/README.md +198 -0
- package/bin/glidepool.js +311 -0
- 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
|
package/bin/glidepool.js
ADDED
|
@@ -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
|
+
}
|