@general-liquidity/gordon-cli 0.8.19 → 0.8.22
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 +64 -393
- package/bin/gordon.cjs +15 -2
- package/lib/platform.cjs +2 -2
- package/lib/self-install.cjs +343 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,455 +1,126 @@
|
|
|
1
|
-
<
|
|
2
|
-
<img src="gordon_ascii.png" alt="Gordon" width="400">
|
|
3
|
-
</p>
|
|
4
|
-
|
|
5
|
-
<h1 align="center">The Frontier Trading Agent</h1>
|
|
6
|
-
|
|
7
|
-
<p align="center">
|
|
8
|
-
<em>Talk naturally. Trade confidently. Sleep peacefully.</em>
|
|
9
|
-
</p>
|
|
1
|
+
<h1 align="center">Gordon CLI</h1>
|
|
10
2
|
|
|
11
3
|
<p align="center">
|
|
12
|
-
|
|
13
|
-
<a href="https://github.com/general-liquidity/gordon-cli/actions"><img src="https://img.shields.io/github/actions/workflow/status/general-liquidity/gordon-cli/release.yml?style=flat-square&label=build" alt="build status"></a>
|
|
14
|
-
<a href="https://github.com/general-liquidity/gordon-cli/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@general-liquidity/gordon-cli.svg?style=flat-square" alt="license"></a>
|
|
15
|
-
<a href="https://discord.gg/general-liquidity"><img src="https://img.shields.io/discord/XXXXXXXXX?style=flat-square&logo=discord&logoColor=white&label=discord" alt="Discord"></a>
|
|
4
|
+
The Frontier Trading Agent
|
|
16
5
|
</p>
|
|
17
6
|
|
|
18
7
|
<p align="center">
|
|
19
|
-
<a href="
|
|
20
|
-
<a href="
|
|
21
|
-
<a href="
|
|
22
|
-
<a href="
|
|
23
|
-
<a href="https://docs.gordon.trade">Docs</a>
|
|
8
|
+
<a href="https://www.npmjs.com/package/@general-liquidity/gordon-cli">npm</a> •
|
|
9
|
+
<a href="https://gordoncli.com">Website</a> •
|
|
10
|
+
<a href="https://docs.gordon.trade">Docs</a> •
|
|
11
|
+
<a href="https://github.com/general-liquidity/gordon-cli-dist/releases">Downloads</a>
|
|
24
12
|
</p>
|
|
25
13
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
## What is Gordon?
|
|
14
|
+
## Install
|
|
29
15
|
|
|
30
|
-
|
|
16
|
+
`npm`:
|
|
31
17
|
|
|
18
|
+
```bash
|
|
19
|
+
npm install -g @general-liquidity/gordon-cli
|
|
32
20
|
```
|
|
33
|
-
You: I think ETH is gonna bounce here
|
|
34
21
|
|
|
35
|
-
|
|
36
|
-
$3,380 support (tested 4x). Looks like a textbook bounce setup.
|
|
22
|
+
If global npm install fails with `EACCES` / permission errors on Linux or macOS, use the user-local npm path instead:
|
|
37
23
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
TP1: $3,580 (50% position, +5.3%)
|
|
41
|
-
TP2: $3,720 (50% position, +9.4%)
|
|
42
|
-
|
|
43
|
-
Risk/Reward: 1:2.8 — Want me to create this plan?
|
|
24
|
+
```bash
|
|
25
|
+
npx @general-liquidity/gordon-cli@latest install
|
|
44
26
|
```
|
|
45
27
|
|
|
46
|
-
|
|
28
|
+
That installs Gordon into a user-writable bin directory without `sudo`.
|
|
47
29
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
## Installation
|
|
51
|
-
|
|
52
|
-
**npm** (recommended)
|
|
53
|
-
```bash
|
|
54
|
-
npm install -g @general-liquidity/gordon-cli
|
|
55
|
-
```
|
|
56
|
-
Downloads the matching prebuilt binary for your platform during install.
|
|
30
|
+
`bun`:
|
|
57
31
|
|
|
58
|
-
**bun**
|
|
59
32
|
```bash
|
|
60
33
|
bun add -g @general-liquidity/gordon-cli
|
|
61
34
|
```
|
|
62
35
|
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
curl -fsSL https://raw.githubusercontent.com/general-liquidity/gordon-cli/main/scripts/install.sh | sh
|
|
66
|
-
```
|
|
36
|
+
`Homebrew`:
|
|
67
37
|
|
|
68
|
-
**from source**
|
|
69
38
|
```bash
|
|
70
|
-
|
|
71
|
-
|
|
39
|
+
brew tap general-liquidity/gordon-cli-dist https://github.com/general-liquidity/gordon-cli-dist
|
|
40
|
+
brew install general-liquidity/gordon-cli-dist/gordon
|
|
72
41
|
```
|
|
73
42
|
|
|
74
|
-
|
|
75
|
-
```bash
|
|
76
|
-
gordon
|
|
77
|
-
```
|
|
43
|
+
`Scoop`:
|
|
78
44
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
### 1. First Run
|
|
84
|
-
|
|
85
|
-
Gordon walks you through setup on first launch—API keys, preferences, safety modes.
|
|
45
|
+
```powershell
|
|
46
|
+
scoop bucket add gordon https://github.com/general-liquidity/gordon-cli-dist
|
|
47
|
+
scoop install gordon/gordon
|
|
48
|
+
```
|
|
86
49
|
|
|
87
|
-
|
|
50
|
+
Standalone install script:
|
|
88
51
|
|
|
89
52
|
```bash
|
|
90
|
-
|
|
91
|
-
export OPENAI_API_KEY="sk-..."
|
|
92
|
-
export DEDALUS_API_KEY="dd-..."
|
|
93
|
-
|
|
94
|
-
# Exchange (Binance for now)
|
|
95
|
-
export BINANCE_API_KEY="..."
|
|
96
|
-
export BINANCE_API_SECRET="..."
|
|
53
|
+
curl -fsSL https://raw.githubusercontent.com/general-liquidity/gordon-cli-dist/main/install.sh | sh
|
|
97
54
|
```
|
|
98
55
|
|
|
99
|
-
|
|
56
|
+
Windows PowerShell:
|
|
100
57
|
|
|
101
|
-
```
|
|
102
|
-
gordon
|
|
58
|
+
```powershell
|
|
59
|
+
irm https://raw.githubusercontent.com/general-liquidity/gordon-cli-dist/main/install.ps1 | iex
|
|
103
60
|
```
|
|
104
61
|
|
|
105
|
-
|
|
62
|
+
The npm package is a thin wrapper. It downloads the matching prebuilt binary for your platform during install.
|
|
106
63
|
|
|
107
|
-
|
|
64
|
+
## npm Permission Fallback
|
|
108
65
|
|
|
109
|
-
|
|
66
|
+
Global `npm install -g` can fail on Unix machines when the npm global prefix is root-owned. Gordon now supports a universal npm fallback:
|
|
110
67
|
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
│ YOU │
|
|
114
|
-
│ "buy BTC near support" │
|
|
115
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
116
|
-
│
|
|
117
|
-
▼
|
|
118
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
119
|
-
│ 🛡️ MIDDLEWARE LAYER
|
|
120
|
-
│ Input Guardrails │ Access Control │ Rate Limiting │
|
|
121
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
122
|
-
│
|
|
123
|
-
▼
|
|
124
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
125
|
-
│ 📈 GORDON (Mastra Agent Network)
|
|
126
|
-
│ │
|
|
127
|
-
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
|
128
|
-
│ │ Scanner │ │ Analyst │ │ Planner │ │ Executor │ │
|
|
129
|
-
│ │ ──────── │ │ ──────── │ │ ──────── │ │ ──────── │ │
|
|
130
|
-
│ │ Find │ │ Deep │ │ Create │ │ Execute │ │
|
|
131
|
-
│ │ setups │ │ analysis │ │ plans │ │ orders │ │
|
|
132
|
-
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
|
|
133
|
-
│ │
|
|
134
|
-
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
|
135
|
-
│ │ Monitor │ │ Teacher │ │Backtester│ │ Gordon │ │
|
|
136
|
-
│ │ ──────── │ │ ──────── │ │ ──────── │ │ ──────── │ │
|
|
137
|
-
│ │ Track │ │ Explain │ │ Test │ │ Route & │ │
|
|
138
|
-
│ │ positions│ │ concepts │ │ strategy │ │ orchestrate│ │
|
|
139
|
-
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
|
|
140
|
-
│ │
|
|
141
|
-
│ Handoff Validation │ Fallback Chains │ Error Recovery │
|
|
142
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
143
|
-
│
|
|
144
|
-
▼
|
|
145
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
146
|
-
│ 🔧 TOOLS LAYER (29 modules)
|
|
147
|
-
│ │
|
|
148
|
-
│ Trading: create_plan, execute_plan, close_trade, grid_plan │
|
|
149
|
-
│ Analysis: indicators, orderbook, market_analysis, charts │
|
|
150
|
-
│ Discovery: scan_market, trending, new_listings, top_movers │
|
|
151
|
-
│ Risk: kelly_size, volatility_size, exit_conditions, drawdown │
|
|
152
|
-
│ Portfolio: positions, wallet, earn, history, account │
|
|
153
|
-
│ Backtest: run_backtest, optimize, monte_carlo, walk_forward │
|
|
154
|
-
│ System: arm/disarm, scheduler, explain, shared_context │
|
|
155
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
156
|
-
│
|
|
157
|
-
▼
|
|
158
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
159
|
-
│ 💾 INFRASTRUCTURE LAYER
|
|
160
|
-
│ │
|
|
161
|
-
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
|
|
162
|
-
│ │ Binance │ │ LLM │ │ SQLite │ │ LibSQL │ │
|
|
163
|
-
│ │ REST+WS │ │ Providers │ │ Storage │ │ Vector │ │
|
|
164
|
-
│ └───────────┘ └───────────┘ └───────────┘ └───────────┘ │
|
|
165
|
-
│ │ │ │ │ │
|
|
166
|
-
│ Orders & OpenAI Plans & Semantic │
|
|
167
|
-
│ Market Data Anthropic Trades Memory │
|
|
168
|
-
│ Real-time Google Events RAG │
|
|
169
|
-
│ WebSocket Dedalus Audit Recall │
|
|
170
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
171
|
-
│
|
|
172
|
-
▼
|
|
173
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
174
|
-
│ TRADE PLAN │
|
|
175
|
-
│ ┌────────────────────────────────────────────────────────────┐ │
|
|
176
|
-
│ │ + BUY 0.15 ETH @ $3,400 (limit) │ │
|
|
177
|
-
│ │ + STOP 0.15 ETH @ $3,290 (stop-limit) │ │
|
|
178
|
-
│ │ + SELL 0.075 ETH @ $3,580 (TP1) │ │
|
|
179
|
-
│ │ + SELL 0.075 ETH @ $3,720 (TP2) │ │
|
|
180
|
-
│ └────────────────────────────────────────────────────────────┘ │
|
|
181
|
-
│ │
|
|
182
|
-
│ [ APPROVE ] [ MODIFY ] [ REJECT ] │
|
|
183
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
184
|
-
│
|
|
185
|
-
▼ (only if you approve + ARM)
|
|
186
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
187
|
-
│ EXECUTION │
|
|
188
|
-
│ Orders placed on Binance. Gordon monitors. │
|
|
189
|
-
│ Auto-disarms after 24h. You stay in control. │
|
|
190
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
68
|
+
```bash
|
|
69
|
+
npx @general-liquidity/gordon-cli@latest install
|
|
191
70
|
```
|
|
192
71
|
|
|
193
|
-
|
|
72
|
+
If the chosen install directory is not already on `PATH`, Gordon prints the exact command to add it.
|
|
194
73
|
|
|
195
|
-
##
|
|
74
|
+
## Upgrades
|
|
196
75
|
|
|
197
|
-
|
|
76
|
+
Once installed, Gordon can upgrade itself with:
|
|
198
77
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
| 🔒 **SAFE Mode Default** | Gordon starts in SAFE mode. Can analyze, cannot trade. |
|
|
202
|
-
| ⏰ **24h Auto-Disarm** | ARMED mode expires automatically. No forgotten bots. |
|
|
203
|
-
| ✋ **Human Approval** | Every order requires explicit "yes". No exceptions. |
|
|
204
|
-
| 📊 **Risk Disclosure** | See exact $ at risk before every trade. |
|
|
205
|
-
| 🛡️ **Position Limits** | Configurable max allocation per trade (default 10%). |
|
|
206
|
-
| 💰 **Cash Reserve** | Always keeps 20% cash. Never goes all-in. |
|
|
207
|
-
|
|
208
|
-
```
|
|
209
|
-
SAFE MODE (default) ARMED MODE (you enable)
|
|
210
|
-
───────────────────── ─────────────────────────
|
|
211
|
-
✓ Scan markets ✓ Everything in SAFE, plus:
|
|
212
|
-
✓ Analyze coins ✓ Execute approved plans
|
|
213
|
-
✓ Create plans ✓ Place real orders
|
|
214
|
-
✓ Explain concepts ✓ Monitor positions
|
|
215
|
-
✗ Execute trades ⏰ Auto-expires in 24h
|
|
78
|
+
```bash
|
|
79
|
+
gordon --upgrade
|
|
216
80
|
```
|
|
217
81
|
|
|
218
|
-
|
|
82
|
+
That now resolves through the active install channel for npm, the user-local `npx` installer, Homebrew, Scoop, and the standalone install scripts.
|
|
219
83
|
|
|
220
|
-
##
|
|
221
|
-
|
|
222
|
-
~200 TypeScript files implementing a production-grade trading platform.
|
|
223
|
-
|
|
224
|
-
### Core Platform
|
|
225
|
-
|
|
226
|
-
- **8-Agent Network** — Mastra-based orchestration: Scanner, Analyst, Planner, Executor, Monitor, Teacher, Backtester, Gordon (coordinator)
|
|
227
|
-
- **Agent Handoffs** — Validated transitions between agents with fallback chains and error recovery
|
|
228
|
-
- **Cross-Agent Memory** — Shared context allowing agents to pass analysis, plans, and backtest results
|
|
229
|
-
- **Semantic Memory** — LibSQL Vector for RAG-based recall of past trades and analyses
|
|
230
|
-
- **LLM Client** — Multi-provider support (OpenAI, Anthropic Claude, Google Gemini, Dedalus Labs)
|
|
231
|
-
|
|
232
|
-
### Security & Middleware
|
|
233
|
-
|
|
234
|
-
- **Input Guardrails** — Prompt injection detection, dangerous command blocking
|
|
235
|
-
- **Output Sanitization** — Sensitive data filtering in responses
|
|
236
|
-
- **Access Control** — ARMED mode enforcement for trading tools
|
|
237
|
-
- **Rate Limiting** — Per-agent, per-tool rate limits to prevent abuse
|
|
238
|
-
- **Audit Logging** — Comprehensive trail of all sensitive operations
|
|
239
|
-
|
|
240
|
-
### Observability
|
|
241
|
-
|
|
242
|
-
- **OpenTelemetry Tracing** — Distributed tracing for agent calls and tool execution
|
|
243
|
-
- **Metrics Collection** — Tool invocation counts, success/failure rates, latency tracking
|
|
244
|
-
- **Request Monitoring** — Per-request performance metrics and error classification
|
|
245
|
-
|
|
246
|
-
### Trading Engine
|
|
247
|
-
|
|
248
|
-
- **Scanner** — Market-wide opportunity detection across top 50 cryptos
|
|
249
|
-
- **Analyzer** — Deep technical analysis per coin with multiple timeframes
|
|
250
|
-
- **Planner** — AI-powered trade plan generation with entry/SL/TP levels
|
|
251
|
-
- **Validator** — Risk checks, position limits, allocation validation
|
|
252
|
-
- **Executor** — Order placement with OCO orders and rollback on failure
|
|
253
|
-
- **Monitor** — Real-time position tracking via WebSocket, fill detection, alerts
|
|
254
|
-
- **Trailing Stops** — Automatic trailing stop-loss management
|
|
255
|
-
- **Order Recovery** — Automatic recovery mechanism for failed/interrupted orders
|
|
256
|
-
- **Grid Calculator** — DCA and grid entry calculations
|
|
257
|
-
|
|
258
|
-
### Trading Strategies
|
|
259
|
-
|
|
260
|
-
- **Tier 1 (Beginner):** Support Bounce, Bollinger Bounce, SMA Crossover, Volume Surge, VWAP Bounce
|
|
261
|
-
- **Tier 2 (Intermediate):** Consolidation Pop, ADX Trend, EMA-RSI Crossover, Relative Strength, Engulfing Pattern
|
|
262
|
-
- **Strategy Ensemble** — Combine multiple strategies with configurable weights
|
|
263
|
-
|
|
264
|
-
### Backtesting Engine
|
|
265
|
-
|
|
266
|
-
- **Historical Simulation** — Full backtesting against historical data
|
|
267
|
-
- **Monte Carlo Analysis** — Statistical confidence intervals
|
|
268
|
-
- **Walk-Forward Validation** — Out-of-sample testing
|
|
269
|
-
- **Grid Search Optimization** — Hyperparameter tuning
|
|
270
|
-
- **Alpha Decay Analysis** — Strategy degradation detection
|
|
271
|
-
- **Performance Metrics** — Sharpe ratio, max drawdown, profit factor, win rate
|
|
272
|
-
|
|
273
|
-
### Technical Analysis
|
|
274
|
-
|
|
275
|
-
- **RSI** — Relative Strength Index (oversold/overbought)
|
|
276
|
-
- **MACD** — Momentum and trend direction
|
|
277
|
-
- **Bollinger Bands** — Volatility and mean reversion
|
|
278
|
-
- **ATR** — Average True Range for stop placement
|
|
279
|
-
- **VWAP** — Volume Weighted Average Price
|
|
280
|
-
- **Stochastic RSI** — Momentum oscillator
|
|
281
|
-
- **EMA/SMA** — Trend following indicators
|
|
282
|
-
- **Volume Analysis** — Confirmation signals and whale detection
|
|
283
|
-
- **Support/Resistance** — Automatic level detection
|
|
284
|
-
|
|
285
|
-
### Infrastructure
|
|
286
|
-
|
|
287
|
-
- **Binance Client** — Full REST API with HMAC signing, rate limiting, circuit breaker
|
|
288
|
-
- **Binance WebSocket** — Real-time price feeds and order updates
|
|
289
|
-
- **SQLite Storage** — Plans, trades, events, audit logs with WAL mode
|
|
290
|
-
- **LibSQL Vector** — Semantic memory and RAG for conversation recall
|
|
291
|
-
- **Service Container** — Dependency injection for clean architecture
|
|
292
|
-
- **Repository Pattern** — Data access layer for trades and plans
|
|
293
|
-
- **Event Bus** — Event-driven architecture for system coordination
|
|
294
|
-
- **Caching Layer** — Price and result caching with TTL
|
|
295
|
-
- **Resilience** — Retry logic, exponential backoff, circuit breakers, fallback chains
|
|
296
|
-
|
|
297
|
-
### User Experience
|
|
298
|
-
|
|
299
|
-
- **Ink CLI** — React-based terminal UI with theme support
|
|
300
|
-
- **Real-time Chat** — Streaming responses with agent attribution
|
|
301
|
-
- **Onboarding Flow** — First-run setup wizard
|
|
302
|
-
- **Model Selector** — Choose your preferred LLM
|
|
303
|
-
- **Keyboard Shortcuts** — Power user navigation
|
|
304
|
-
- **Command Autocomplete** — Slash command suggestions
|
|
305
|
-
- **Status Bar** — Mode, portfolio value, BTC price, connection status
|
|
306
|
-
|
|
307
|
-
---
|
|
308
|
-
|
|
309
|
-
## Configuration
|
|
310
|
-
|
|
311
|
-
Gordon stores config at `~/.gordon/config.json`:
|
|
312
|
-
|
|
313
|
-
```json
|
|
314
|
-
{
|
|
315
|
-
"version": "1.0.0",
|
|
316
|
-
"mode": "SAFE",
|
|
317
|
-
"preferences": {
|
|
318
|
-
"cashReservePercent": 0.2,
|
|
319
|
-
"maxAllocationPerTrade": 0.1,
|
|
320
|
-
"defaultTimeframes": ["1h", "4h"],
|
|
321
|
-
"topNCoins": 50
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
```
|
|
84
|
+
## Supported binaries
|
|
325
85
|
|
|
326
|
-
|
|
86
|
+
- macOS arm64
|
|
87
|
+
- macOS x64
|
|
88
|
+
- Linux arm64
|
|
89
|
+
- Linux x64
|
|
90
|
+
- Windows x64
|
|
327
91
|
|
|
328
|
-
|
|
329
|
-
|----------|----------|-------------|
|
|
330
|
-
| `OPENAI_API_KEY` | One LLM | OpenAI API key |
|
|
331
|
-
| `ANTHROPIC_API_KEY` | provider | Anthropic Claude API key |
|
|
332
|
-
| `GOOGLE_GENERATIVE_AI_API_KEY` | required | Google Gemini API key |
|
|
333
|
-
| `DEDALUS_API_KEY` | | Dedalus Labs API key (20+ models) |
|
|
334
|
-
| `BINANCE_API_KEY` | For trading | Binance API key |
|
|
335
|
-
| `BINANCE_API_SECRET` | For trading | Binance secret |
|
|
92
|
+
Release binaries and package manager manifests are published at:
|
|
336
93
|
|
|
337
|
-
|
|
94
|
+
- `https://github.com/general-liquidity/gordon-cli-dist/releases`
|
|
338
95
|
|
|
339
|
-
##
|
|
96
|
+
## Setup
|
|
97
|
+
|
|
98
|
+
Set one LLM provider key before first launch:
|
|
340
99
|
|
|
341
100
|
```bash
|
|
342
|
-
|
|
343
|
-
bun run dev # Development mode (hot reload)
|
|
344
|
-
bun test # Run tests
|
|
345
|
-
bun run typecheck # Type check
|
|
346
|
-
bun run build # Build for npm
|
|
347
|
-
bun run build:binary # Build standalone executable
|
|
101
|
+
export OPENAI_API_KEY="sk-..."
|
|
348
102
|
```
|
|
349
103
|
|
|
350
|
-
|
|
104
|
+
or
|
|
351
105
|
|
|
106
|
+
```bash
|
|
107
|
+
export DEDALUS_API_KEY="dd-..."
|
|
352
108
|
```
|
|
353
|
-
gordon/
|
|
354
|
-
├── src/
|
|
355
|
-
│ ├── app/ # Terminal UI (React + Ink)
|
|
356
|
-
│ │ ├── App.tsx
|
|
357
|
-
│ │ ├── ChatView.tsx
|
|
358
|
-
│ │ ├── ChatInput.tsx
|
|
359
|
-
│ │ ├── components/ # Reusable UI components
|
|
360
|
-
│ │ └── ...
|
|
361
|
-
│ ├── core/ # Trading logic
|
|
362
|
-
│ │ ├── scanner.ts
|
|
363
|
-
│ │ ├── analyzer.ts
|
|
364
|
-
│ │ ├── planner.ts
|
|
365
|
-
│ │ ├── executor.ts
|
|
366
|
-
│ │ ├── monitor.ts
|
|
367
|
-
│ │ ├── trailing-stop.ts
|
|
368
|
-
│ │ ├── indicators/ # Technical indicators
|
|
369
|
-
│ │ └── risk-management/
|
|
370
|
-
│ ├── backtest/ # Backtesting engine
|
|
371
|
-
│ │ ├── engine.ts
|
|
372
|
-
│ │ ├── monte-carlo.ts
|
|
373
|
-
│ │ ├── walk-forward.ts
|
|
374
|
-
│ │ └── optimization/
|
|
375
|
-
│ ├── strategies/ # Trading strategies
|
|
376
|
-
│ │ ├── tier-1/ # Beginner strategies
|
|
377
|
-
│ │ ├── tier-2/ # Intermediate strategies
|
|
378
|
-
│ │ └── ensemble.ts
|
|
379
|
-
│ ├── services/ # Business services
|
|
380
|
-
│ │ ├── trading.service.ts
|
|
381
|
-
│ │ ├── portfolio.service.ts
|
|
382
|
-
│ │ └── container.ts # Dependency injection
|
|
383
|
-
│ ├── repositories/ # Data access layer
|
|
384
|
-
│ ├── infra/ # Infrastructure
|
|
385
|
-
│ │ ├── agents/ # Mastra multi-agent system
|
|
386
|
-
│ │ │ ├── tools/ # 29 tool modules
|
|
387
|
-
│ │ │ └── middleware/ # Guardrails, access control
|
|
388
|
-
│ │ ├── binance/ # Exchange client + WebSocket
|
|
389
|
-
│ │ ├── llm/ # LLM providers
|
|
390
|
-
│ │ ├── storage/ # SQLite + config
|
|
391
|
-
│ │ ├── observability/ # OpenTelemetry tracing + metrics
|
|
392
|
-
│ │ ├── audit/ # Audit logging
|
|
393
|
-
│ │ └── cache/ # Caching layer
|
|
394
|
-
│ ├── events/ # Event-driven architecture
|
|
395
|
-
│ └── types/ # TypeScript definitions
|
|
396
|
-
├── prompts/ # LLM prompt templates
|
|
397
|
-
├── scripts/ # Install scripts
|
|
398
|
-
└── .github/ # CI/CD workflows
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
---
|
|
402
|
-
|
|
403
|
-
## Roadmap
|
|
404
109
|
|
|
405
|
-
|
|
406
|
-
- [x] Binance spot trading
|
|
407
|
-
- [x] Multi-provider LLM (OpenAI, Anthropic, Google, Dedalus)
|
|
408
|
-
- [x] Plan-as-diff approval UI
|
|
409
|
-
- [x] SAFE/ARMED modes with 24h auto-expiry
|
|
410
|
-
- [x] Trailing stops
|
|
411
|
-
- [x] 10+ trading strategies (tier 1 & tier 2)
|
|
412
|
-
- [x] Backtesting engine with Monte Carlo & walk-forward
|
|
413
|
-
- [x] Real-time WebSocket monitoring
|
|
414
|
-
- [x] Order recovery mechanism
|
|
415
|
-
- [x] Audit logging & security guardrails
|
|
416
|
-
- [ ] More exchanges (Coinbase, Kraken)
|
|
417
|
-
- [ ] Portfolio rebalancing
|
|
418
|
-
- [ ] Mobile notifications
|
|
419
|
-
- [ ] Paper trading mode
|
|
420
|
-
|
|
421
|
-
---
|
|
422
|
-
|
|
423
|
-
## Contributing
|
|
424
|
-
|
|
425
|
-
We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
110
|
+
or
|
|
426
111
|
|
|
427
112
|
```bash
|
|
428
|
-
|
|
429
|
-
bun install
|
|
430
|
-
bun test
|
|
431
|
-
# Make changes, add tests, submit PR
|
|
113
|
+
export INCEPTION_API_KEY="..."
|
|
432
114
|
```
|
|
433
115
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
## License
|
|
437
|
-
|
|
438
|
-
MIT © [General Liquidity, Inc.](https://generalliquidity.com)
|
|
116
|
+
Then run:
|
|
439
117
|
|
|
440
|
-
|
|
118
|
+
```bash
|
|
119
|
+
gordon
|
|
120
|
+
```
|
|
441
121
|
|
|
442
|
-
|
|
443
|
-
<sub>
|
|
444
|
-
<em>"The most valuable commodity I know of is information."</em>
|
|
445
|
-
<br>
|
|
446
|
-
— Gordon Gekko (the other one)
|
|
447
|
-
</sub>
|
|
448
|
-
</p>
|
|
122
|
+
## Docs
|
|
449
123
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
<a href="https://discord.gg/general-liquidity">Discord</a> •
|
|
454
|
-
<a href="https://docs.gordon.trade">Docs</a>
|
|
455
|
-
</p>
|
|
124
|
+
- Website: `https://gordoncli.com`
|
|
125
|
+
- Docs: `https://docs.gordon.trade`
|
|
126
|
+
- Public distribution repo: `https://github.com/general-liquidity/gordon-cli-dist`
|
package/bin/gordon.cjs
CHANGED
|
@@ -4,8 +4,21 @@ const fs = require("fs");
|
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const { spawn } = require("child_process");
|
|
6
6
|
const { getInstalledBinaryPath } = require("../lib/platform.cjs");
|
|
7
|
+
const { runSelfInstall } = require("../lib/self-install.cjs");
|
|
7
8
|
|
|
8
9
|
const packageRoot = path.resolve(__dirname, "..");
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
|
|
12
|
+
if (args[0] === "install") {
|
|
13
|
+
runSelfInstall(args.slice(1), { packageRoot }).then(
|
|
14
|
+
(code) => process.exit(code || 0),
|
|
15
|
+
(error) => {
|
|
16
|
+
console.error(`[gordon] ${error.message}`);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
9
22
|
|
|
10
23
|
let binaryPath;
|
|
11
24
|
try {
|
|
@@ -17,12 +30,12 @@ try {
|
|
|
17
30
|
|
|
18
31
|
if (!fs.existsSync(binaryPath)) {
|
|
19
32
|
console.error(
|
|
20
|
-
"[gordon] The Gordon binary is missing. Reinstall with `npm install -g @general-liquidity/gordon-cli
|
|
33
|
+
"[gordon] The Gordon binary is missing. Reinstall with `npm install -g @general-liquidity/gordon-cli` or run `npx @general-liquidity/gordon-cli@latest install` for a user-local install."
|
|
21
34
|
);
|
|
22
35
|
process.exit(1);
|
|
23
36
|
}
|
|
24
37
|
|
|
25
|
-
const child = spawn(binaryPath,
|
|
38
|
+
const child = spawn(binaryPath, args, { stdio: "inherit" });
|
|
26
39
|
|
|
27
40
|
child.on("error", (error) => {
|
|
28
41
|
console.error(`[gordon] Failed to launch ${path.basename(binaryPath)}: ${error.message}`);
|
package/lib/platform.cjs
CHANGED
|
@@ -38,9 +38,9 @@ function getInstalledBinaryPath(packageRoot = path.resolve(__dirname, ".."), pla
|
|
|
38
38
|
function getDownloadUrl(version, platform = process.platform, arch = process.arch) {
|
|
39
39
|
const { assetName } = getTarget(platform, arch);
|
|
40
40
|
const cleanVersion = String(version).replace(/^v/, "");
|
|
41
|
+
const distRepo = process.env.GORDON_BINARY_DIST_REPO || "general-liquidity/gordon-cli-dist";
|
|
41
42
|
const baseUrl =
|
|
42
|
-
process.env.GORDON_BINARY_BASE_URL ||
|
|
43
|
-
`https://github.com/general-liquidity/gordon-cli/releases/download/v${cleanVersion}`;
|
|
43
|
+
process.env.GORDON_BINARY_BASE_URL || `https://github.com/${distRepo}/releases/download/v${cleanVersion}`;
|
|
44
44
|
return `${baseUrl.replace(/\/$/, "")}/${assetName}`;
|
|
45
45
|
}
|
|
46
46
|
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const os = require("os");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const https = require("https");
|
|
5
|
+
const { pipeline } = require("stream/promises");
|
|
6
|
+
const { getDownloadUrl, getInstalledBinaryPath, getTarget } = require("./platform.cjs");
|
|
7
|
+
const pkg = require("../package.json");
|
|
8
|
+
const INSTALL_METADATA_FILENAME = "gordon-install.json";
|
|
9
|
+
|
|
10
|
+
function log(message) {
|
|
11
|
+
console.log(`[gordon] ${message}`);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function parseArgs(args) {
|
|
15
|
+
const options = {
|
|
16
|
+
help: false,
|
|
17
|
+
targetDir: null
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
21
|
+
const arg = args[index];
|
|
22
|
+
if (arg === "--help" || arg === "-h") {
|
|
23
|
+
options.help = true;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if ((arg === "--target-dir" || arg === "--dir") && args[index + 1]) {
|
|
28
|
+
options.targetDir = path.resolve(args[index + 1]);
|
|
29
|
+
index += 1;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
throw new Error(`Unknown install option: ${arg}`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return options;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function printHelp() {
|
|
40
|
+
console.log(`gordon install
|
|
41
|
+
|
|
42
|
+
Install Gordon into a user-writable bin directory without requiring \`npm install -g\`.
|
|
43
|
+
|
|
44
|
+
Usage:
|
|
45
|
+
npx @general-liquidity/gordon-cli@latest install
|
|
46
|
+
gordon install --target-dir <directory>
|
|
47
|
+
|
|
48
|
+
Options:
|
|
49
|
+
--target-dir <dir> Override the install directory
|
|
50
|
+
-h, --help Show this help
|
|
51
|
+
`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function normalizeForCompare(value) {
|
|
55
|
+
const resolved = path.resolve(value);
|
|
56
|
+
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function splitPathEntries(envPath = process.env.PATH || "") {
|
|
60
|
+
return envPath.split(path.delimiter).filter(Boolean);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function pathContainsDirectory(directory, env = process.env) {
|
|
64
|
+
const target = normalizeForCompare(directory);
|
|
65
|
+
return splitPathEntries(env.PATH).some((entry) => {
|
|
66
|
+
try {
|
|
67
|
+
return normalizeForCompare(entry) === target;
|
|
68
|
+
} catch {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function uniqueDirectories(values) {
|
|
75
|
+
const seen = new Set();
|
|
76
|
+
const result = [];
|
|
77
|
+
for (const value of values) {
|
|
78
|
+
if (!value) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const normalized = normalizeForCompare(value);
|
|
83
|
+
if (seen.has(normalized)) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
seen.add(normalized);
|
|
88
|
+
result.push(path.resolve(value));
|
|
89
|
+
}
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function isWritableDirectory(directory, { create } = { create: false }) {
|
|
94
|
+
try {
|
|
95
|
+
if (create) {
|
|
96
|
+
await fs.promises.mkdir(directory, { recursive: true });
|
|
97
|
+
} else {
|
|
98
|
+
const stats = await fs.promises.stat(directory);
|
|
99
|
+
if (!stats.isDirectory()) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const probePath = path.join(directory, `.gordon-write-test-${process.pid}-${Date.now()}`);
|
|
105
|
+
await fs.promises.writeFile(probePath, "");
|
|
106
|
+
await fs.promises.rm(probePath, { force: true });
|
|
107
|
+
return true;
|
|
108
|
+
} catch {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function resolveInstallDirectory(explicitTargetDir = null, env = process.env) {
|
|
114
|
+
if (explicitTargetDir) {
|
|
115
|
+
return {
|
|
116
|
+
directory: explicitTargetDir,
|
|
117
|
+
inPath: pathContainsDirectory(explicitTargetDir, env)
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const homeDirectory = os.homedir();
|
|
122
|
+
const pathEntries = splitPathEntries(env.PATH);
|
|
123
|
+
const standardCandidates = [];
|
|
124
|
+
const pathCandidates = [];
|
|
125
|
+
|
|
126
|
+
if (process.platform === "win32") {
|
|
127
|
+
if (env.APPDATA) {
|
|
128
|
+
standardCandidates.push(path.join(env.APPDATA, "npm"));
|
|
129
|
+
}
|
|
130
|
+
if (env.LOCALAPPDATA) {
|
|
131
|
+
standardCandidates.push(path.join(env.LOCALAPPDATA, "Microsoft", "WinGet", "Links"));
|
|
132
|
+
standardCandidates.push(path.join(env.LOCALAPPDATA, "gordon"));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
for (const entry of pathEntries) {
|
|
136
|
+
const resolvedEntry = path.resolve(entry);
|
|
137
|
+
const normalizedEntry = normalizeForCompare(resolvedEntry);
|
|
138
|
+
const userRoots = uniqueDirectories([
|
|
139
|
+
env.USERPROFILE,
|
|
140
|
+
env.LOCALAPPDATA,
|
|
141
|
+
env.APPDATA,
|
|
142
|
+
homeDirectory
|
|
143
|
+
]);
|
|
144
|
+
const withinUserRoot = userRoots.some((root) => {
|
|
145
|
+
const normalizedRoot = normalizeForCompare(root);
|
|
146
|
+
return normalizedEntry === normalizedRoot || normalizedEntry.startsWith(`${normalizedRoot}${path.sep}`);
|
|
147
|
+
});
|
|
148
|
+
if (
|
|
149
|
+
withinUserRoot
|
|
150
|
+
&& !normalizedEntry.includes(`${path.sep}node_modules${path.sep}`)
|
|
151
|
+
) {
|
|
152
|
+
pathCandidates.push(resolvedEntry);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
standardCandidates.push(path.join(homeDirectory, ".local", "bin"));
|
|
157
|
+
standardCandidates.push(path.join(homeDirectory, "bin"));
|
|
158
|
+
|
|
159
|
+
for (const entry of pathEntries) {
|
|
160
|
+
const resolvedEntry = path.resolve(entry);
|
|
161
|
+
const normalizedEntry = normalizeForCompare(resolvedEntry);
|
|
162
|
+
const normalizedHome = `${normalizeForCompare(homeDirectory)}${path.sep}`;
|
|
163
|
+
if (
|
|
164
|
+
normalizedEntry.startsWith(normalizedHome)
|
|
165
|
+
&& !normalizedEntry.includes(`${path.sep}node_modules${path.sep}`)
|
|
166
|
+
) {
|
|
167
|
+
pathCandidates.push(resolvedEntry);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const orderedCandidates = uniqueDirectories([
|
|
173
|
+
...standardCandidates.filter((candidate) => pathContainsDirectory(candidate, env)),
|
|
174
|
+
...pathCandidates,
|
|
175
|
+
...standardCandidates
|
|
176
|
+
]);
|
|
177
|
+
|
|
178
|
+
for (const candidate of orderedCandidates) {
|
|
179
|
+
const create = standardCandidates.some((standardCandidate) => normalizeForCompare(standardCandidate) === normalizeForCompare(candidate));
|
|
180
|
+
if (await isWritableDirectory(candidate, { create })) {
|
|
181
|
+
return {
|
|
182
|
+
directory: candidate,
|
|
183
|
+
inPath: pathContainsDirectory(candidate, env)
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
throw new Error("Could not find a writable user install directory.");
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async function downloadBinary(url, destinationPath, redirectCount = 0) {
|
|
192
|
+
if (redirectCount > 5) {
|
|
193
|
+
throw new Error(`Too many redirects while downloading ${url}`);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
await new Promise((resolve, reject) => {
|
|
197
|
+
const request = https.get(
|
|
198
|
+
url,
|
|
199
|
+
{ headers: { "User-Agent": "gordon-npm-installer" } },
|
|
200
|
+
async (response) => {
|
|
201
|
+
if (
|
|
202
|
+
response.statusCode &&
|
|
203
|
+
response.statusCode >= 300 &&
|
|
204
|
+
response.statusCode < 400 &&
|
|
205
|
+
response.headers.location
|
|
206
|
+
) {
|
|
207
|
+
response.resume();
|
|
208
|
+
try {
|
|
209
|
+
await downloadBinary(response.headers.location, destinationPath, redirectCount + 1);
|
|
210
|
+
resolve();
|
|
211
|
+
} catch (error) {
|
|
212
|
+
reject(error);
|
|
213
|
+
}
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (response.statusCode !== 200) {
|
|
218
|
+
response.resume();
|
|
219
|
+
reject(new Error(`Download failed with status ${response.statusCode} for ${url}`));
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const fileStream = fs.createWriteStream(destinationPath);
|
|
224
|
+
pipeline(response, fileStream).then(resolve, reject);
|
|
225
|
+
}
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
request.on("error", reject);
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async function finalizeBinary(tempPath, targetPath) {
|
|
233
|
+
if (process.platform !== "win32") {
|
|
234
|
+
await fs.promises.chmod(tempPath, 0o755);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
await fs.promises.rm(targetPath, { force: true });
|
|
238
|
+
await fs.promises.rename(tempPath, targetPath);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
async function writeInstallMetadata(targetDirectory, version, channel) {
|
|
242
|
+
const metadataPath = path.join(targetDirectory, INSTALL_METADATA_FILENAME);
|
|
243
|
+
const payload = {
|
|
244
|
+
channel,
|
|
245
|
+
installDir: targetDirectory,
|
|
246
|
+
version,
|
|
247
|
+
installedAt: new Date().toISOString()
|
|
248
|
+
};
|
|
249
|
+
await fs.promises.writeFile(metadataPath, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function getUnixPathHint(directory, env = process.env) {
|
|
253
|
+
const shell = env.SHELL || "";
|
|
254
|
+
if (shell.includes("fish")) {
|
|
255
|
+
return {
|
|
256
|
+
profile: "~/.config/fish/config.fish",
|
|
257
|
+
command: `fish_add_path ${directory.replace(os.homedir(), "$HOME")}`
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (shell.includes("zsh")) {
|
|
262
|
+
return {
|
|
263
|
+
profile: "~/.zshrc",
|
|
264
|
+
command: `echo 'export PATH=\"${directory.replace(os.homedir(), "$HOME")}:$PATH\"' >> ~/.zshrc`
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return {
|
|
269
|
+
profile: "~/.bashrc",
|
|
270
|
+
command: `echo 'export PATH=\"${directory.replace(os.homedir(), "$HOME")}:$PATH\"' >> ~/.bashrc`
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function printPathGuidance(directory) {
|
|
275
|
+
if (process.platform === "win32") {
|
|
276
|
+
log(`Add ${directory} to your user PATH, then open a new terminal.`);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const hint = getUnixPathHint(directory);
|
|
281
|
+
log(`Add ${directory} to PATH if your shell cannot find \`gordon\` yet.`);
|
|
282
|
+
console.log(` ${hint.command}`);
|
|
283
|
+
console.log(` # then restart your shell or source ${hint.profile}`);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
async function installBinary({ targetDirectory, sourceBinaryPath, version }) {
|
|
287
|
+
const { binaryName, assetName } = getTarget();
|
|
288
|
+
await fs.promises.mkdir(targetDirectory, { recursive: true });
|
|
289
|
+
|
|
290
|
+
const installPath = path.join(targetDirectory, binaryName);
|
|
291
|
+
const tempPath = `${installPath}.tmp`;
|
|
292
|
+
await fs.promises.rm(tempPath, { force: true });
|
|
293
|
+
|
|
294
|
+
if (sourceBinaryPath && fs.existsSync(sourceBinaryPath)) {
|
|
295
|
+
log(`Copying ${path.basename(sourceBinaryPath)} to ${installPath}`);
|
|
296
|
+
await fs.promises.copyFile(sourceBinaryPath, tempPath);
|
|
297
|
+
} else {
|
|
298
|
+
const downloadUrl = getDownloadUrl(version);
|
|
299
|
+
log(`Downloading ${assetName} from ${downloadUrl}`);
|
|
300
|
+
await downloadBinary(downloadUrl, tempPath);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
await finalizeBinary(tempPath, installPath);
|
|
304
|
+
return installPath;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
async function runSelfInstall(args, options = {}) {
|
|
308
|
+
const parsed = parseArgs(args);
|
|
309
|
+
if (parsed.help) {
|
|
310
|
+
printHelp();
|
|
311
|
+
return 0;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const packageRoot = options.packageRoot || path.resolve(__dirname, "..");
|
|
315
|
+
const version = String(options.version || pkg.version).replace(/^v/, "");
|
|
316
|
+
const bundledBinaryPath = options.sourceBinaryPath || getInstalledBinaryPath(packageRoot);
|
|
317
|
+
const sourceBinaryPath = fs.existsSync(bundledBinaryPath) ? bundledBinaryPath : null;
|
|
318
|
+
const { directory, inPath } = await resolveInstallDirectory(parsed.targetDir);
|
|
319
|
+
const installPath = await installBinary({
|
|
320
|
+
targetDirectory: directory,
|
|
321
|
+
sourceBinaryPath,
|
|
322
|
+
version
|
|
323
|
+
});
|
|
324
|
+
await writeInstallMetadata(directory, version, options.channel || "npx");
|
|
325
|
+
|
|
326
|
+
console.log("");
|
|
327
|
+
log(`Installed Gordon v${version} to ${installPath}`);
|
|
328
|
+
if (!inPath) {
|
|
329
|
+
printPathGuidance(directory);
|
|
330
|
+
}
|
|
331
|
+
console.log("");
|
|
332
|
+
console.log("Next steps:");
|
|
333
|
+
console.log(" gordon --help");
|
|
334
|
+
console.log(" gordon");
|
|
335
|
+
|
|
336
|
+
return 0;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
module.exports = {
|
|
340
|
+
parseArgs,
|
|
341
|
+
resolveInstallDirectory,
|
|
342
|
+
runSelfInstall
|
|
343
|
+
};
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@general-liquidity/gordon-cli",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.22",
|
|
4
4
|
"description": "The Frontier Trading Agent",
|
|
5
5
|
"author": "General Liquidity, Inc.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "https://github.com/general-liquidity/gordon-cli.git"
|
|
9
|
+
"url": "https://github.com/general-liquidity/gordon-cli-dist.git"
|
|
10
10
|
},
|
|
11
|
-
"homepage": "https://
|
|
12
|
-
"bugs": "https://github.com/general-liquidity/gordon-cli/issues",
|
|
11
|
+
"homepage": "https://gordoncli.com",
|
|
12
|
+
"bugs": "https://github.com/general-liquidity/gordon-cli-dist/issues",
|
|
13
13
|
"keywords": [
|
|
14
14
|
"trading",
|
|
15
15
|
"crypto",
|