@cryptocom/cdcx-cli 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,394 @@
1
+ # cdcx
2
+
3
+ A CLI, MCP server, and terminal dashboard for the [Crypto.com Exchange API](https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html). Single binary, zero runtime dependencies.
4
+
5
+ 86 REST endpoints across 10 API groups, dynamically generated from the Crypto.com Exchange OpenAPI spec. Real-time WebSocket streaming. Full-screen TUI dashboard. Paper trading. Works as a standalone CLI, an MCP tool server for AI agents, or an interactive terminal.
6
+
7
+ > **Caution:** This software interacts with the live Crypto.com Exchange and can execute real financial transactions. Test with `cdcx paper` before using real funds.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ curl -sSfL https://raw.githubusercontent.com/crypto-com/cdcx-cli/main/install.sh | sh
13
+ ```
14
+
15
+ **From source:**
16
+
17
+ ```bash
18
+ cargo install --git https://github.com/crypto-com/cdcx-cli.git --bin cdcx
19
+ ```
20
+
21
+ ---
22
+
23
+ ## Why cdcx?
24
+
25
+ ### For AI Agents
26
+
27
+ Every response is structured JSON. 86 MCP tools with typed parameters, enum validation, safety enforcement, and schema discovery — all generated from the OpenAPI spec at runtime. Your LLM can trade, analyze markets, and manage positions without custom tooling.
28
+
29
+ ```bash
30
+ cdcx mcp --services market,account,trade
31
+ ```
32
+
33
+ ```json
34
+ {
35
+ "mcpServers": {
36
+ "cdcx": {
37
+ "command": "npx",
38
+ "args": ["-y", "@cryptocom/cdcx-cli@latest", "mcp", "--services", "market,account,trade"]
39
+ }
40
+ }
41
+ }
42
+ ```
43
+
44
+ Compatible with Claude Code, Cursor, Claude Desktop, Codex, Github Copilot, Gemini CLI, and other MCP clients. Includes 13 agent skill files in `skills/` for guided workflows.
45
+
46
+ Things you can ask your AI agent:
47
+
48
+ > *"What's the current BTC price and 24h volume?"*
49
+
50
+ > *"Paper trade BTC for a few rounds and show me the P&L"*
51
+
52
+ > *"Place an OTOCO bracket on BTC_USDT: entry at 70000, stop-loss at 65000, take-profit at 75000"*
53
+
54
+ ### For the Command Line
55
+
56
+ Every endpoint is a command. `--help` on everything. `--dry-run` to preview. `--output json` for scripting. Tab completion. Profiles for multi-account.
57
+
58
+ ```bash
59
+ cdcx market ticker BTC_USDT -o table
60
+ cdcx trade order BUY BTC_USDT 0.001 --dry-run
61
+ cdcx stream ticker BTC_USDT ETH_USDT
62
+ cdcx paper buy BTC_USDT --quantity 0.01
63
+ ```
64
+
65
+ ### For the Dashboard
66
+
67
+ Full-screen terminal trading interface. 6 tabs, real-time streaming, candlestick charts, heatmap mode, split screen, order workflows. Zero flicker.
68
+
69
+ ```bash
70
+ cdcx tui
71
+ ```
72
+
73
+ Press `p` to toggle paper mode. Press `O` for OTOCO bracket orders. Press `?` for all shortcuts.
74
+
75
+ ---
76
+
77
+ ## Quick Start
78
+
79
+ Public market data works without credentials:
80
+
81
+ ```bash
82
+ cdcx market ticker BTC_USDT -o table
83
+ cdcx market book BTC_USDT --depth 10 -o table
84
+ cdcx market candlestick BTC_USDT --timeframe 1h -o table
85
+ ```
86
+
87
+ Paper trading works without credentials:
88
+
89
+ ```bash
90
+ cdcx paper init --balance 50000
91
+ cdcx paper buy BTC_USDT --quantity 0.01
92
+ cdcx paper positions
93
+ cdcx paper balance
94
+ ```
95
+
96
+ For trading, set credentials:
97
+
98
+ ```bash
99
+ export CDCX_API_KEY="your-key"
100
+ export CDCX_API_SECRET="your-secret"
101
+ cdcx account summary
102
+ ```
103
+
104
+ ---
105
+
106
+ ## MCP Server
107
+
108
+ Expose the Exchange API as MCP tools for AI agents:
109
+
110
+ ```bash
111
+ cdcx mcp --services market,account,trade
112
+ cdcx mcp --services all --allow-dangerous
113
+ ```
114
+
115
+ Service groups (MCP): `market`, `account`, `trade`, `advanced`, `margin`, `staking`, `funding`, `fiat`, `otc`, `stream`, `all`
116
+
117
+ > **Note:** `account` also exposes historical endpoints (orders, trades, transactions). `funding` covers wallet deposit/withdrawal endpoints. Paper trading is a CLI-only feature and has no MCP tools.
118
+
119
+ ### Safety Model
120
+
121
+ | Tier | Behavior | Examples |
122
+ |------|----------|---------|
123
+ | **read** | No confirmation | `market ticker`, `market book` |
124
+ | **sensitive_read** | No confirmation | `account summary`, `trade open-orders` |
125
+ | **mutate** | Requires `acknowledged: true` | `trade order`, `trade cancel` |
126
+ | **dangerous** | Requires `--allow-dangerous` | `trade cancel-all`, `wallet withdraw` |
127
+
128
+ ### Agent Skills
129
+
130
+ 13 skill files in `skills/` covering:
131
+
132
+ | Skill | Purpose |
133
+ |-------|---------|
134
+ | `cdcx-market-intel` | Market analysis and price discovery |
135
+ | `cdcx-portfolio-intel` | Portfolio analysis and risk assessment |
136
+ | `cdcx-execution` | Order placement with safety checks |
137
+ | `cdcx-advanced` | OCO, OTO, OTOCO contingency orders |
138
+ | `cdcx-paper-strategy` | Paper trading strategy testing |
139
+ | `cdcx-wallet-ops` | Deposits, withdrawals, network management |
140
+ | `cdcx-auth-setup` | Credential configuration |
141
+ | `cdcx-autonomy-levels` | Safety tier configuration |
142
+ | `cdcx-check-balance` | Balance and credential verification |
143
+ | `cdcx-place-limit-order` | Limit order workflow with preflight checks |
144
+ | `cdcx-isolated-margin` | Isolated margin trading (equity/RWA perpetuals) |
145
+ | `recipe-morning-brief` | Daily market briefing workflow |
146
+ | `recipe-emergency-flatten` | Emergency position flattening |
147
+
148
+ ### Plugin Installation
149
+
150
+ Install cdcx as a one-click plugin from your AI coding tool's marketplace.
151
+
152
+ **Claude Code:**
153
+
154
+ ```bash
155
+ claude plugin marketplace add crypto-com/cdcx-cli
156
+ claude plugin install cdcx-cli@cdcx-cli
157
+ ```
158
+
159
+ **Codex CLI:**
160
+
161
+ ```bash
162
+ codex plugin marketplace add crypto-com/cdcx-cli
163
+ ```
164
+
165
+ **Other:** Open Settings > MCP Servers, add:
166
+
167
+ ```json
168
+ {
169
+ "cdcx": {
170
+ "command": "npx",
171
+ "args": ["-y", "@cryptocom/cdcx-cli@latest", "mcp", "--services", "market"]
172
+ }
173
+ }
174
+ ```
175
+
176
+ To expand services beyond market data, update the `--services` flag:
177
+
178
+ ```
179
+ market,trade,account # Trading agent
180
+ market,trade,account,advanced # With OCO/OTOCO
181
+ all --allow-dangerous # Full access (withdrawals enabled)
182
+ ```
183
+
184
+ ---
185
+
186
+ ## CLI Reference
187
+
188
+ ### Market Data (public)
189
+
190
+ ```bash
191
+ cdcx market ticker # All tickers
192
+ cdcx market ticker BTC_USDT # Single instrument
193
+ cdcx market book BTC_USDT --depth 20 # Order book
194
+ cdcx market trades BTC_USDT # Recent trades
195
+ cdcx market candlestick BTC_USDT --timeframe 1h
196
+ cdcx market instruments # All instruments
197
+ ```
198
+
199
+ ### Trading (requires auth)
200
+
201
+ ```bash
202
+ cdcx trade order BUY BTC_USDT 0.001 --type LIMIT --price 50000
203
+ cdcx trade open-orders
204
+ cdcx trade cancel --order-id ORDER_ID
205
+ cdcx trade cancel-all
206
+ ```
207
+
208
+ ### Advanced Orders
209
+
210
+ ```bash
211
+ cdcx advanced create-oto --instrument-name BTC_USDT ...
212
+ cdcx advanced create-otoco --instrument-name BTC_USDT ...
213
+ cdcx advanced open-orders
214
+ ```
215
+
216
+ ### Paper Trading
217
+
218
+ Local paper trading engine with live market prices. No auth required.
219
+
220
+ ```bash
221
+ cdcx paper init --balance 50000 # Create account
222
+ cdcx paper buy BTC_USDT --quantity 0.01 # Market buy
223
+ cdcx paper sell BTC_USDT --quantity 0.01 # Market sell
224
+ cdcx paper buy BTC_USDT --quantity 0.01 --price 65000 # Limit buy
225
+ cdcx paper positions # Portfolio + P&L
226
+ cdcx paper history # Trade history
227
+ cdcx paper balance # Account balance
228
+ cdcx paper reset --balance 100000 # Reset account
229
+ ```
230
+
231
+ ### Streaming (WebSocket)
232
+
233
+ ```bash
234
+ cdcx stream ticker BTC_USDT ETH_USDT # Real-time tickers
235
+ cdcx stream book BTC_USDT # Order book updates
236
+ cdcx stream trades BTC_USDT # Trade executions
237
+ cdcx stream orders # Your order updates (auth)
238
+ cdcx stream positions # Position changes (auth)
239
+ ```
240
+
241
+ ### Account
242
+
243
+ ```bash
244
+ cdcx account summary # Balances
245
+ cdcx account positions # Open positions
246
+ cdcx trade fee-rate # Fee rates
247
+ ```
248
+
249
+ ### History / Wallet / Staking / Fiat / Margin
250
+
251
+ ```bash
252
+ cdcx history orders cdcx wallet deposit-address --currency BTC
253
+ cdcx history trades cdcx wallet deposit-history
254
+ cdcx history transactions cdcx wallet withdrawal-history
255
+ cdcx staking instruments cdcx fiat accounts
256
+ cdcx staking positions cdcx margin transfer --dry-run
257
+ ```
258
+
259
+ ---
260
+
261
+ ## Interactive Dashboard
262
+
263
+ ```bash
264
+ cdcx tui # Launch
265
+ cdcx tui --theme amber # With theme
266
+ cdcx tui --setup # Setup wizard
267
+ ```
268
+
269
+ ### Features
270
+
271
+ - **6 tabs:** Market, Portfolio, Orders, History, Watchlist, Positions
272
+ - **Real-time streaming:** WebSocket ticker, order book, candlestick, trade channels
273
+ - **Sparklines:** 24h Braille-dot price charts inline per instrument
274
+ - **Heatmap mode:** rows glow red/green by 24h performance
275
+ - **Candlestick charts:** volume bars, 9 timeframes, streaming updates, time axis
276
+ - **Multi-chart compare:** up to 4 instruments side by side
277
+ - **Split screen:** table + chart, auto-updates on selection
278
+ - **Order book detail:** cumulative depth bars, buy/sell pressure bar
279
+ - **Order workflows:** place order, OCO, OTOCO, cancel
280
+ - **Live portfolio P&L:** session P&L in status bar, cash vs position breakdown in Portfolio tab
281
+ - **Paper mode:** toggle `p` to trade against local paper engine with unrealized/realized P&L
282
+ - **Instrument picker:** search-as-you-type overlay
283
+ - **Price alerts:** set thresholds with terminal bell notification
284
+ - **Ticker tape:** scrolling top movers banner
285
+ - **6 themes:** terminal-pro, cyber-midnight, monochrome, neon, micky-d, amber + custom TOML
286
+ - **Mouse support:** click to select, scroll, double-click to detail
287
+ - **Export:** `y` copies table as CSV to clipboard
288
+
289
+ ### Keyboard Shortcuts
290
+
291
+ | Key | Action |
292
+ |-----|--------|
293
+ | `1`-`6` / `Tab` | Switch tabs |
294
+ | `Enter` | Instrument detail (book + trades) |
295
+ | `k` | Candlestick chart |
296
+ | `m` | Compare charts (up to 4) |
297
+ | `h` | Toggle heatmap |
298
+ | `i` | Instrument spotlight |
299
+ | `\` | Split screen (table + chart) |
300
+ | `[ / ]` | Cycle chart timeframe |
301
+ | `s / S` | Sort / reverse sort |
302
+ | `/` | Search instruments |
303
+ | `t` | Place order |
304
+ | `o` | OCO order (stop-loss + take-profit) |
305
+ | `O` | OTOCO order (entry + SL + TP) |
306
+ | `c` | Cancel orders |
307
+ | `p` | Toggle LIVE / PAPER mode |
308
+ | `!` | Set price alert |
309
+ | `y` | Copy to clipboard (CSV) |
310
+ | `?` | Help overlay |
311
+ | `q` | Quit |
312
+
313
+ ---
314
+
315
+ ## Configuration
316
+
317
+ ### Credentials
318
+
319
+ Resolved in order: flags > `CDCX_API_KEY`/`CDCX_API_SECRET` env > `CDC_API_KEY`/`CDC_API_SECRET` env > `~/.config/cdcx/config.toml` profile.
320
+
321
+ ```bash
322
+ cdcx setup # Interactive credential setup
323
+ cdcx --profile uat account summary # Use named profile
324
+ ```
325
+
326
+ ### TUI Config
327
+
328
+ `~/.config/cdcx/tui.toml`:
329
+
330
+ ```toml
331
+ theme = "terminal-pro"
332
+ tick_rate_ms = 250
333
+ watchlist = ["BTC_USDT", "ETH_USDT", "SOL_USDT", "CRO_USDT"]
334
+
335
+ [themes.my-theme]
336
+ bg = "#1a1a2e"
337
+ accent = "#00d4ff"
338
+ positive = "#00ff88"
339
+ negative = "#ff4444"
340
+ ```
341
+
342
+ ### Global Flags
343
+
344
+ | Flag | Description |
345
+ |------|-------------|
346
+ | `-o, --output` | Output format: `json` (default), `table`, `ndjson` |
347
+ | `--dry-run` | Preview request without executing |
348
+ | `--env` | Environment: `production` (default), `uat` |
349
+ | `--profile` | Config profile name |
350
+ | `--yes` | Skip confirmation prompts |
351
+ | `-v, --verbose` | Verbose output |
352
+
353
+ ---
354
+
355
+ ## Architecture
356
+
357
+ ```
358
+ crates/cdcx-core/ # API client, auth, signing, schema, OpenAPI parser, paper engine
359
+ crates/cdcx-cli/ # CLI binary, dispatch, MCP server, setup
360
+ crates/cdcx-tui/ # Terminal dashboard (ratatui + crossterm)
361
+ schemas/ # CLI overlay files (command aliases, positional args, defaults)
362
+ skills/ # Agent skill files for guided workflows
363
+ site/ # Marketing site (single HTML file)
364
+ ```
365
+
366
+ - **OpenAPI sole source:** All API commands and MCP tools are generated from the exchange's OpenAPI spec at runtime (24h cache). Thin TOML overlay files in `schemas/` add CLI-only metadata (positional args, defaults, command aliases). No hand-maintained endpoint definitions.
367
+ - **Single binary:** ~11MB, no runtime dependencies
368
+ - **Zero flicker:** ratatui double-buffer character-level diffing
369
+
370
+ ## Development
371
+
372
+ ```bash
373
+ cargo test # Run all tests
374
+ cargo build --release # Build release binary
375
+ cargo run -- market ticker BTC_USDT # Run from source
376
+ cargo run -- tui # TUI from source
377
+ ```
378
+
379
+ ### Git hooks
380
+
381
+ Install once per clone to catch CI failures locally:
382
+
383
+ ```bash
384
+ ./hooks/install.sh
385
+ ```
386
+
387
+ - `pre-commit` runs `cargo fmt --check` + `cargo clippy -- -D warnings`
388
+ - `pre-push` runs the full test suite (skipped for doc-only pushes)
389
+
390
+ The toolchain is pinned to `stable` via `rust-toolchain.toml`; run `rustup update stable` if your local clippy is older than CI's.
391
+
392
+ ## License
393
+
394
+ Dual-licensed under [MIT](LICENSE-MIT) and [Apache 2.0](LICENSE-APACHE).
package/install.sh ADDED
@@ -0,0 +1,251 @@
1
+ #!/bin/sh
2
+ # cdcx installer — detects platform, downloads latest release, verifies checksum, installs.
3
+ #
4
+ # Usage:
5
+ # curl -sSfL https://raw.githubusercontent.com/crypto-com/cdcx-cli/main/install.sh | sh
6
+ #
7
+ # Or from source:
8
+ # cargo install --git https://github.com/crypto-com/cdcx-cli.git --bin cdcx
9
+
10
+ set -eu
11
+
12
+ REPO="crypto-com/cdcx-cli"
13
+ BINARY="cdcx"
14
+ # INSTALL_DIR is resolved after the banner:
15
+ # 1. honour an explicit INSTALL_DIR env var if set
16
+ # 2. otherwise prefer /usr/local/bin when writable
17
+ # 3. otherwise fall back to ~/.local/bin (no sudo required)
18
+ DEFAULT_SYSTEM_DIR="/usr/local/bin"
19
+ DEFAULT_USER_DIR="${HOME}/.local/bin"
20
+ SKIP_VERIFICATION=false
21
+
22
+ # ── Colors ──────────────────────────────────────────────────────────────────────
23
+
24
+ RED='\033[0;31m'
25
+ GREEN='\033[0;32m'
26
+ YELLOW='\033[0;33m'
27
+ CYAN='\033[0;36m'
28
+ BOLD='\033[1m'
29
+ NC='\033[0m'
30
+
31
+ info() { printf "${CYAN}${BOLD}==>${NC} %s\n" "$1"; }
32
+ ok() { printf "${GREEN}${BOLD} ✓${NC} %s\n" "$1"; }
33
+ warn() { printf "${YELLOW}${BOLD} !${NC} %s\n" "$1"; }
34
+ error() { printf "${RED}${BOLD}Error:${NC} %s\n" "$1" >&2; exit 1; }
35
+
36
+ # Parse command-line flags (must be after function definitions)
37
+ while [ $# -gt 0 ]; do
38
+ case "$1" in
39
+ --skip-verification)
40
+ SKIP_VERIFICATION=true
41
+ shift
42
+ ;;
43
+ *)
44
+ error "Unknown option: $1"
45
+ ;;
46
+ esac
47
+ done
48
+
49
+ # ── Banner ──────────────────────────────────────────────────────────────────────
50
+
51
+ printf "${CYAN}${BOLD}"
52
+ cat << 'BANNER'
53
+
54
+ ██████╗██████╗ ██████╗██╗ ██╗
55
+ ██╔════╝██╔══██╗██╔════╝╚██╗██╔╝
56
+ ██║ ██║ ██║██║ ╚███╔╝
57
+ ██║ ██║ ██║██║ ██╔██╗
58
+ ╚██████╗██████╔╝╚██████╗██╔╝██╗
59
+ ╚═════╝╚═════╝ ╚═════╝╚═╝ ╚═╝
60
+
61
+ Crypto.com Exchange CLI
62
+
63
+ BANNER
64
+ printf "${NC}"
65
+
66
+ # ── Platform detection ──────────────────────────────────────────────────────────
67
+
68
+ detect_os() {
69
+ case "$(uname -s)" in
70
+ Linux*) echo "linux" ;;
71
+ Darwin*) echo "darwin" ;;
72
+ MINGW*|MSYS*|CYGWIN*) echo "windows" ;;
73
+ *) error "Unsupported operating system: $(uname -s)" ;;
74
+ esac
75
+ }
76
+
77
+ detect_arch() {
78
+ case "$(uname -m)" in
79
+ x86_64|amd64) echo "x86_64" ;;
80
+ arm64|aarch64) echo "aarch64" ;;
81
+ *) error "Unsupported architecture: $(uname -m)" ;;
82
+ esac
83
+ }
84
+
85
+ OS="$(detect_os)"
86
+ ARCH="$(detect_arch)"
87
+
88
+ info "Detected platform: ${OS}-${ARCH}"
89
+
90
+ # ── Fetch latest release ────────────────────────────────────────────────────────
91
+
92
+ info "Fetching latest release..."
93
+
94
+ RELEASE_JSON="$(curl -sSfL "https://api.github.com/repos/${REPO}/releases/latest" 2>/dev/null)" || error "Failed to fetch release info from GitHub."
95
+
96
+ # Extract version tag
97
+ VERSION="$(echo "$RELEASE_JSON" | grep '"tag_name"' | head -1 | sed 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/')"
98
+ if [ -z "$VERSION" ]; then
99
+ error "Could not determine latest release version."
100
+ fi
101
+
102
+ # Validate VERSION against semantic versioning pattern to prevent code injection
103
+ if ! echo "$VERSION" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$'; then
104
+ error "Invalid version format: ${VERSION}. Expected semantic version (e.g., v1.0.0)."
105
+ fi
106
+
107
+ ok "Latest version: ${VERSION}"
108
+
109
+ # ── Construct download URL ──────────────────────────────────────────────────────
110
+
111
+ # Release assets are named with the bare version (no leading "v"),
112
+ # matching the release.yml workflow which strips the "v" prefix.
113
+ VERSION_BARE="${VERSION#v}"
114
+
115
+ # Archive naming: cdcx-{version}-{arch}-{os}.tar.gz (or .zip for windows)
116
+ # Linux binaries ship as musl (statically linked, glibc-free) for portability.
117
+ PLATFORM="${OS}"
118
+ if [ "$OS" = "darwin" ]; then
119
+ PLATFORM="apple-darwin"
120
+ elif [ "$OS" = "linux" ]; then
121
+ PLATFORM="unknown-linux-musl"
122
+ fi
123
+
124
+ if [ "$OS" = "windows" ]; then
125
+ ARCHIVE="${BINARY}-${VERSION_BARE}-${ARCH}-pc-windows-msvc.zip"
126
+ else
127
+ ARCHIVE="${BINARY}-${VERSION_BARE}-${ARCH}-${PLATFORM}.tar.gz"
128
+ fi
129
+
130
+ DOWNLOAD_URL="https://github.com/${REPO}/releases/download/${VERSION}/${ARCHIVE}"
131
+ CHECKSUM_URL="https://github.com/${REPO}/releases/download/${VERSION}/checksums.txt"
132
+
133
+ info "Downloading ${ARCHIVE}..."
134
+
135
+ # ── Download and verify ─────────────────────────────────────────────────────────
136
+
137
+ TMPDIR="$(mktemp -d)"
138
+ trap 'rm -rf "$TMPDIR"' EXIT
139
+
140
+ # Download archive
141
+ curl -sSfL -o "${TMPDIR}/${ARCHIVE}" "$DOWNLOAD_URL" || \
142
+ error "Download failed. This platform (${ARCH}-${PLATFORM}) may not have a pre-built binary.\n Try: cargo install --git https://github.com/${REPO}.git --bin cdcx"
143
+
144
+ ok "Downloaded ${ARCHIVE}"
145
+
146
+ # Download and verify checksum (if available)
147
+ CHECKSUM_DOWNLOADED=false
148
+ if curl -sSfL -o "${TMPDIR}/checksums.txt" "$CHECKSUM_URL" 2>/dev/null; then
149
+ CHECKSUM_DOWNLOADED=true
150
+ fi
151
+
152
+ if [ "$SKIP_VERIFICATION" = true ]; then
153
+ warn "Checksum verification skipped — this is insecure. Only skip if you trust the download source."
154
+ warn "For security, verification is enabled by default. Re-run without --skip-verification for secure installs."
155
+ else
156
+ if [ "$CHECKSUM_DOWNLOADED" = false ]; then
157
+ error "Checksums not available for this release. Cannot verify binary integrity.\n To bypass verification (not recommended), re-run with --skip-verification"
158
+ fi
159
+
160
+ EXPECTED="$(awk -v f="$ARCHIVE" '$2 == f { print $1 }' "${TMPDIR}/checksums.txt")"
161
+ if [ -z "$EXPECTED" ]; then
162
+ error "Checksum entry not found for ${ARCHIVE}. Binary file name mismatch or corrupted checksums.txt.\n To bypass verification (not recommended), re-run with --skip-verification"
163
+ fi
164
+
165
+ if command -v sha256sum > /dev/null 2>&1; then
166
+ ACTUAL="$(sha256sum "${TMPDIR}/${ARCHIVE}" | awk '{print $1}')"
167
+ elif command -v shasum > /dev/null 2>&1; then
168
+ ACTUAL="$(shasum -a 256 "${TMPDIR}/${ARCHIVE}" | awk '{print $1}')"
169
+ else
170
+ error "No SHA256 tool found (neither sha256sum nor shasum available). Cannot verify checksum.\n Install sha256sum or shasum, or re-run with --skip-verification (not recommended)"
171
+ fi
172
+
173
+ if [ "$ACTUAL" != "$EXPECTED" ]; then
174
+ error "Checksum verification failed!\n Expected: ${EXPECTED}\n Got: ${ACTUAL}\n The downloaded file may be corrupted. Please try again."
175
+ fi
176
+ ok "Checksum verified"
177
+ fi
178
+
179
+ # ── Extract ─────────────────────────────────────────────────────────────────────
180
+
181
+ info "Extracting..."
182
+
183
+ if [ "$OS" = "windows" ]; then
184
+ unzip -qo "${TMPDIR}/${ARCHIVE}" -d "${TMPDIR}" || error "Failed to extract archive."
185
+ else
186
+ tar -xzf "${TMPDIR}/${ARCHIVE}" -C "${TMPDIR}" || error "Failed to extract archive."
187
+ fi
188
+
189
+ # Find the binary (may be in a subdirectory)
190
+ EXTRACTED_BIN="$(find "${TMPDIR}" -name "${BINARY}" -type f | head -1)"
191
+ if [ -z "$EXTRACTED_BIN" ]; then
192
+ # Try with .exe for Windows
193
+ EXTRACTED_BIN="$(find "${TMPDIR}" -name "${BINARY}.exe" -type f | head -1)"
194
+ fi
195
+ if [ -z "$EXTRACTED_BIN" ]; then
196
+ error "Could not find ${BINARY} binary in extracted archive."
197
+ fi
198
+
199
+ chmod +x "$EXTRACTED_BIN"
200
+ ok "Extracted ${BINARY}"
201
+
202
+ # ── Install ─────────────────────────────────────────────────────────────────────
203
+
204
+ # Resolve install location. Honour an explicit INSTALL_DIR; otherwise prefer the
205
+ # system dir when writable, fall back to ~/.local/bin when not. Never prompt for
206
+ # sudo automatically — scripts piped to `sh` can't read a TTY, and many
207
+ # environments (CI, corporate laptops, rootless containers) lack sudo entirely.
208
+ if [ -n "${INSTALL_DIR:-}" ]; then
209
+ : # user supplied INSTALL_DIR; respect it verbatim
210
+ elif [ -w "$DEFAULT_SYSTEM_DIR" ] 2>/dev/null; then
211
+ INSTALL_DIR="$DEFAULT_SYSTEM_DIR"
212
+ else
213
+ INSTALL_DIR="$DEFAULT_USER_DIR"
214
+ info "${DEFAULT_SYSTEM_DIR} is not writable — installing to ${INSTALL_DIR} (no sudo needed)"
215
+ fi
216
+
217
+ mkdir -p "$INSTALL_DIR" || error "Could not create ${INSTALL_DIR}"
218
+
219
+ info "Installing to ${INSTALL_DIR}/${BINARY}..."
220
+
221
+ if [ -w "$INSTALL_DIR" ]; then
222
+ mv "$EXTRACTED_BIN" "${INSTALL_DIR}/${BINARY}" || \
223
+ error "Failed to move binary into ${INSTALL_DIR}. Set INSTALL_DIR to a writable directory and re-run."
224
+ else
225
+ error "${INSTALL_DIR} is not writable. Set INSTALL_DIR=\$HOME/.local/bin (or another writable path) and re-run."
226
+ fi
227
+
228
+ ok "Installed ${BINARY} to ${INSTALL_DIR}/${BINARY}"
229
+
230
+ # ── Verify ──────────────────────────────────────────────────────────────────────
231
+
232
+ if command -v "$BINARY" > /dev/null 2>&1; then
233
+ INSTALLED_VERSION="$("$BINARY" --version 2>/dev/null || echo "cdcx")"
234
+ printf "\n"
235
+ printf "${GREEN}${BOLD} ✓ ${INSTALLED_VERSION} installed successfully!${NC}\n"
236
+ printf "\n"
237
+ info "Binary: ${INSTALL_DIR}/${BINARY}"
238
+ printf "\n"
239
+ printf " ${CYAN}Get started:${NC}\n"
240
+ printf " ${BOLD}cdcx market ticker BTC_USDT${NC} # Live ticker\n"
241
+ printf " ${BOLD}cdcx tui${NC} # Interactive dashboard\n"
242
+ printf " ${BOLD}cdcx setup${NC} # Configure API keys\n"
243
+ printf " ${BOLD}cdcx --help${NC} # All commands\n"
244
+ printf "\n"
245
+ else
246
+ warn "${BINARY} was installed but is not in your PATH."
247
+ printf " Add this line to ${BOLD}~/.zshrc${NC} or ${BOLD}~/.bashrc${NC}:\n"
248
+ printf " ${BOLD}export PATH=\"${INSTALL_DIR}:\$PATH\"${NC}\n"
249
+ printf " Then reload: ${BOLD}source ~/.zshrc${NC} (or open a new shell).\n"
250
+ printf " Or run directly without modifying PATH: ${BOLD}${INSTALL_DIR}/${BINARY}${NC}\n"
251
+ fi
package/npm/bin.mjs ADDED
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execFileSync } from "child_process";
4
+ import { existsSync } from "fs";
5
+ import { findBinary, install, ROOT_DIR, LOCAL_BIN } from "./lib.mjs";
6
+
7
+ let bin = findBinary();
8
+ if (!bin) {
9
+ try {
10
+ install();
11
+ } catch {
12
+ // global install failed — fall through to local attempt
13
+ }
14
+ bin = findBinary();
15
+ if (!bin) {
16
+ try {
17
+ install(ROOT_DIR);
18
+ } catch {
19
+ process.stderr.write("cdcx installation failed.\n");
20
+ process.exit(1);
21
+ }
22
+ if (!existsSync(LOCAL_BIN)) {
23
+ process.stderr.write("cdcx installation failed — binary not found.\n");
24
+ process.exit(1);
25
+ }
26
+ bin = LOCAL_BIN;
27
+ }
28
+ }
29
+
30
+ try {
31
+ execFileSync(bin, process.argv.slice(2), { stdio: "inherit" });
32
+ } catch (e) {
33
+ process.exit(e.status ?? 1);
34
+ }
package/npm/lib.mjs ADDED
@@ -0,0 +1,52 @@
1
+ import { execFileSync, execSync } from "child_process";
2
+ import { existsSync } from "fs";
3
+ import { join, dirname } from "path";
4
+ import { fileURLToPath } from "url";
5
+
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ export const BINARY = "cdcx";
8
+ export const ROOT_DIR = join(__dirname, "..");
9
+ export const LOCAL_BIN = join(ROOT_DIR, BINARY);
10
+ const INSTALL_SCRIPT = join(ROOT_DIR, "install.sh");
11
+
12
+ export function findBinary() {
13
+ if (existsSync(LOCAL_BIN)) {
14
+ try {
15
+ execFileSync(LOCAL_BIN, ["--version"], { stdio: "pipe" });
16
+ return LOCAL_BIN;
17
+ } catch {
18
+ // exists but not functional — fall through
19
+ }
20
+ }
21
+ try {
22
+ const bin = execSync(`command -v ${BINARY}`, { encoding: "utf8" }).trim();
23
+ execFileSync(bin, ["--version"], { stdio: "pipe" });
24
+ return bin;
25
+ } catch {
26
+ return null;
27
+ }
28
+ }
29
+
30
+ export function installedVersion(bin) {
31
+ try {
32
+ const out = execFileSync(bin, ["--version"], { encoding: "utf8" }).trim();
33
+ const match = out.match(/(\d+\.\d+\.\d+)/);
34
+ return match ? match[1] : null;
35
+ } catch {
36
+ return null;
37
+ }
38
+ }
39
+
40
+ export function install(dir) {
41
+ if (!existsSync(INSTALL_SCRIPT)) {
42
+ process.stderr.write(
43
+ `${BINARY} not found. Install it: curl -sSfL https://raw.githubusercontent.com/crypto-com/cdcx-cli/main/install.sh | sh\n`
44
+ );
45
+ process.exit(1);
46
+ }
47
+ const env = dir ? { ...process.env, INSTALL_DIR: dir } : process.env;
48
+ execFileSync("sh", [INSTALL_SCRIPT], {
49
+ stdio: ["pipe", process.stderr, process.stderr],
50
+ env,
51
+ });
52
+ }
@@ -0,0 +1,58 @@
1
+ import { readFileSync, existsSync } from "fs";
2
+ import { join } from "path";
3
+ import { homedir } from "os";
4
+ import {
5
+ findBinary,
6
+ install,
7
+ installedVersion,
8
+ ROOT_DIR,
9
+ } from "./lib.mjs";
10
+
11
+ function isUpdateDisabled() {
12
+ try {
13
+ const configPath = join(homedir(), ".config", "cdcx", "config.toml");
14
+ if (!existsSync(configPath)) return false;
15
+ const content = readFileSync(configPath, "utf8");
16
+ return /^\s*disable_update_check\s*=\s*"?true"?\s*$/m.test(content);
17
+ } catch {
18
+ return false;
19
+ }
20
+ }
21
+
22
+ const bin = findBinary();
23
+
24
+ if (!bin) {
25
+ // No binary at all — must install regardless of update preference
26
+ try {
27
+ install();
28
+ } catch {
29
+ try {
30
+ install(ROOT_DIR);
31
+ } catch {
32
+ process.stderr.write("cdcx installation failed.\n");
33
+ process.exit(1);
34
+ }
35
+ }
36
+ } else if (!isUpdateDisabled()) {
37
+ const expected = JSON.parse(
38
+ readFileSync(join(ROOT_DIR, "package.json"), "utf8")
39
+ ).version;
40
+ const current = installedVersion(bin);
41
+
42
+ if (current !== expected) {
43
+ try {
44
+ install();
45
+ } catch {
46
+ // global failed — try local
47
+ }
48
+ const updated = findBinary();
49
+ if (!updated || installedVersion(updated) !== expected) {
50
+ try {
51
+ install(ROOT_DIR);
52
+ } catch {
53
+ process.stderr.write("cdcx installation failed.\n");
54
+ process.exit(1);
55
+ }
56
+ }
57
+ }
58
+ }
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@cryptocom/cdcx-cli",
3
+ "version": "1.2.2",
4
+ "description": "MCP server for crypto.com exchange CLI",
5
+ "author": "Crypto.com",
6
+ "homepage": "https://github.com/crypto-com/cdcx-cli",
7
+ "license": "MIT OR Apache-2.0",
8
+ "keywords": [
9
+ "crypto.com",
10
+ "crypto",
11
+ "mcp",
12
+ "model-context-protocol"
13
+ ],
14
+ "repository": {
15
+ "url": "git+https://github.com/crypto-com/cdcx-cli.git",
16
+ "type": "git"
17
+ },
18
+ "engines": {
19
+ "node": ">=20.0.0"
20
+ },
21
+ "type": "module",
22
+ "os": [
23
+ "darwin",
24
+ "linux"
25
+ ],
26
+ "files": [
27
+ "README.md",
28
+ "install.sh",
29
+ "npm/bin.mjs",
30
+ "npm/lib.mjs",
31
+ "npm/post-install.mjs"
32
+ ],
33
+ "bin": {
34
+ "cdcx-cli": "npm/bin.mjs"
35
+ },
36
+ "scripts": {
37
+ "bump": "./scripts/version-bump.sh",
38
+ "postinstall": "node ./npm/post-install.mjs"
39
+ }
40
+ }