nansen-cli 1.20.0 → 1.22.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/CHANGELOG.md +26 -0
- package/README.md +26 -1
- package/package.json +1 -1
- package/skills/nansen-trading/SKILL.md +14 -2
- package/skills/nansen-wallet-manager/SKILL.md +12 -0
- package/src/api.js +6 -5
- package/src/cli.js +36 -22
- package/src/commands/agent.js +344 -0
- package/src/cost-cache.js +67 -0
- package/src/schema.json +90 -1
- package/src/trading.js +129 -5
- package/src/wallet.js +7 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.22.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#336](https://github.com/nansen-ai/nansen-cli/pull/336) [`c3b1fbd`](https://github.com/nansen-ai/nansen-cli/commit/c3b1fbdee46c15326a1656bf27a314f6c55dddf8) Thanks [@kome12](https://github.com/kome12)! - Add --label option to `token flows` command to filter by holder segment (top_100_holders, smart_money, public_figure, whale, exchange).
|
|
8
|
+
|
|
9
|
+
- [#334](https://github.com/nansen-ai/nansen-cli/pull/334) [`83244c6`](https://github.com/nansen-ai/nansen-cli/commit/83244c658d4ece2072dea0c6ed405a088c98aa4f) Thanks [@kome12](https://github.com/kome12)! - Add `--include-stablecoins` flag to `token screener` command. Pass `--include-stablecoins false` to exclude stablecoins from screener results (API default is `true`). Supports combined usage with `--smart-money`.
|
|
10
|
+
|
|
11
|
+
- [#339](https://github.com/nansen-ai/nansen-cli/pull/339) [`27ebcfc`](https://github.com/nansen-ai/nansen-cli/commit/27ebcfc2a3afd836db595df6d5a2a5f9242b624c) Thanks [@TimNooren](https://github.com/TimNooren)! - Add --amount-unit token flag to trade quote for human-readable amounts
|
|
12
|
+
|
|
13
|
+
## 1.21.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- [#315](https://github.com/nansen-ai/nansen-cli/pull/315) [`908fa0c`](https://github.com/nansen-ai/nansen-cli/commit/908fa0ccdf18cb79b7efb58b9b31f66e0afedff6) Thanks [@TimNooren](https://github.com/TimNooren)! - Add `nansen agent` command for the Nansen AI research agent with fast/expert modes, SSE streaming, conversation continuation, and JSON output.
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- [#326](https://github.com/nansen-ai/nansen-cli/pull/326) [`1532ba4`](https://github.com/nansen-ai/nansen-cli/commit/1532ba420174ed7635a42641f0c1a2802077fdc0) Thanks [@TimNooren](https://github.com/TimNooren)! - Show API credit cost in research subcommand help text (fetched from OpenAPI spec, cached 24h).
|
|
22
|
+
|
|
23
|
+
- [#330](https://github.com/nansen-ai/nansen-cli/pull/330) [`a6b9b8f`](https://github.com/nansen-ai/nansen-cli/commit/a6b9b8fc7d291ee7375941bb275c224939338161) Thanks [@0xlaveen](https://github.com/0xlaveen)! - Suppress misleading PASSWORD_REQUIRED error when `--provider privy` is specified. Privy wallets don't need a password — only the Privy-specific credentials error is now shown when PRIVY_APP_ID/PRIVY_APP_SECRET are missing.
|
|
24
|
+
|
|
25
|
+
- [#329](https://github.com/nansen-ai/nansen-cli/pull/329) [`f047833`](https://github.com/nansen-ai/nansen-cli/commit/f047833c7e6fb55cb713e0b69f82282fe87d4566) Thanks [@TimNooren](https://github.com/TimNooren)! - Limit deprecation warnings and update notices to help output only, keeping stdout/stderr clean for programmatic usage.
|
|
26
|
+
|
|
27
|
+
- [#332](https://github.com/nansen-ai/nansen-cli/pull/332) [`e9b6de1`](https://github.com/nansen-ai/nansen-cli/commit/e9b6de17fdba3f46733dff026c2495c095bfbf35) Thanks [@0xlaveen](https://github.com/0xlaveen)! - docs: add trading examples and Privy wallet setup to README
|
|
28
|
+
|
|
3
29
|
## 1.20.0
|
|
4
30
|
|
|
5
31
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -36,10 +36,35 @@ nansen schema [command] [--pretty] # full command reference (no API key neede
|
|
|
36
36
|
|
|
37
37
|
**Trade:** `quote`, `execute` — DEX swaps on Solana and Base.
|
|
38
38
|
|
|
39
|
-
**Wallet:** `create`, `list`, `show`, `export`, `default`, `delete`, `send` — local
|
|
39
|
+
**Wallet:** `create`, `list`, `show`, `export`, `default`, `delete`, `send` — local or Privy server-side wallets (EVM + Solana).
|
|
40
40
|
|
|
41
41
|
Run `nansen schema --pretty` for the full subcommand and field reference.
|
|
42
42
|
|
|
43
|
+
## Trading
|
|
44
|
+
|
|
45
|
+
DEX swaps on `solana` and `base`. Two-step: quote then execute.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
nansen trade quote --chain solana --from SOL --to USDC --amount 1000000000
|
|
49
|
+
nansen trade execute --quote <quoteId>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Amounts are in base units (lamports, wei). Common symbols (`SOL`, `ETH`, `USDC`, `USDT`) resolve automatically. A wallet is required — set one with `nansen wallet default <name>`.
|
|
53
|
+
|
|
54
|
+
## Wallet
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
nansen wallet create --name my-wallet # local keypair (EVM + Solana)
|
|
58
|
+
nansen wallet create --name my-wallet --provider privy # server-side via Privy
|
|
59
|
+
nansen wallet list
|
|
60
|
+
nansen wallet default <name>
|
|
61
|
+
nansen wallet send --wallet <name> --to <addr> --amount <n> --chain <chain>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Local wallets** are password-encrypted. Set `NANSEN_WALLET_PASSWORD` to skip the prompt.
|
|
65
|
+
|
|
66
|
+
**Privy wallets** are server-side — no password, no local key storage. Requires `PRIVY_APP_ID` and `PRIVY_APP_SECRET` env vars. Get credentials at [dashboard.privy.io](https://dashboard.privy.io).
|
|
67
|
+
|
|
43
68
|
## Key Options
|
|
44
69
|
|
|
45
70
|
| Option | Description |
|
package/package.json
CHANGED
|
@@ -58,7 +58,16 @@ nansen trade execute --quote "$quote_id"
|
|
|
58
58
|
| ETH | Base | `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee` |
|
|
59
59
|
| USDC | Base | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` |
|
|
60
60
|
|
|
61
|
-
## Amounts
|
|
61
|
+
## Amounts
|
|
62
|
+
|
|
63
|
+
By default, `--amount` accepts **integer base units** (lamports, wei, etc). Use `--amount-unit token` to specify human-readable token amounts instead — the CLI resolves decimals locally and sends base units to the API.
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Base units (default)
|
|
67
|
+
nansen trade quote --chain solana --from SOL --to USDC --amount 1000000000
|
|
68
|
+
# Token units (0.5 SOL = 500000000 lamports, resolved automatically)
|
|
69
|
+
nansen trade quote --chain solana --from SOL --to USDC --amount 0.5 --amount-unit token
|
|
70
|
+
```
|
|
62
71
|
|
|
63
72
|
| Token | Decimals | 1 token = |
|
|
64
73
|
|-------|----------|-----------|
|
|
@@ -66,6 +75,8 @@ nansen trade execute --quote "$quote_id"
|
|
|
66
75
|
| ETH | 18 | `1000000000000000000` |
|
|
67
76
|
| USDC | 6 | `1000000` |
|
|
68
77
|
|
|
78
|
+
If the user says "$20 worth of X", you must convert USD → token amount, then either pass base units or use `--amount-unit token`. For example, to buy $20 of SOL at $150/SOL: $20 ÷ $150 = 0.1333 SOL → `--amount 0.1333 --amount-unit token`. Use a price lookup (e.g. `nansen research token info`) to get the current price first.
|
|
79
|
+
|
|
69
80
|
## Flags
|
|
70
81
|
|
|
71
82
|
| Flag | Purpose |
|
|
@@ -73,7 +84,8 @@ nansen trade execute --quote "$quote_id"
|
|
|
73
84
|
| `--chain` | `solana` or `base` |
|
|
74
85
|
| `--from` | Source token (symbol or address) |
|
|
75
86
|
| `--to` | Destination token (symbol or address) |
|
|
76
|
-
| `--amount` | Amount in base units (integer) |
|
|
87
|
+
| `--amount` | Amount in base units (integer), or token units with `--amount-unit token` |
|
|
88
|
+
| `--amount-unit` | Set to `token` to specify amount in token units (e.g. 0.5 SOL) |
|
|
77
89
|
| `--wallet` | Wallet name (default: default wallet) |
|
|
78
90
|
| `--slippage` | Slippage tolerance as decimal (e.g. 0.03) |
|
|
79
91
|
| `--quote` | Quote ID for execute |
|
|
@@ -109,6 +109,18 @@ If the `.credentials` file fallback is used, the CLI prints a warning on every o
|
|
|
109
109
|
|
|
110
110
|
## Create
|
|
111
111
|
|
|
112
|
+
### Privy (server-side, no password)
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
nansen wallet create --provider privy
|
|
116
|
+
# Or with a custom name:
|
|
117
|
+
nansen wallet create --name trading --provider privy
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Requires `PRIVY_APP_ID` + `PRIVY_APP_SECRET` env vars. No password needed.
|
|
121
|
+
|
|
122
|
+
### Local (encrypted on disk, password required)
|
|
123
|
+
|
|
112
124
|
```bash
|
|
113
125
|
# Ask the user for a password first, then:
|
|
114
126
|
NANSEN_WALLET_PASSWORD="<password_from_user>" nansen wallet create
|
package/src/api.js
CHANGED
|
@@ -11,12 +11,12 @@ import { getAnonymousId, TELEMETRY_DISABLED } from './telemetry.js';
|
|
|
11
11
|
|
|
12
12
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
13
13
|
|
|
14
|
-
function telemetryHeaders() {
|
|
14
|
+
export function telemetryHeaders() {
|
|
15
15
|
if (TELEMETRY_DISABLED) return {};
|
|
16
16
|
return { 'X-Anonymous-Id': getAnonymousId() };
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
const { version: packageVersion } = JSON.parse(
|
|
19
|
+
export const { version: packageVersion } = JSON.parse(
|
|
20
20
|
fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8')
|
|
21
21
|
);
|
|
22
22
|
|
|
@@ -85,7 +85,7 @@ export class NansenError extends Error {
|
|
|
85
85
|
/**
|
|
86
86
|
* Map HTTP status codes to error codes
|
|
87
87
|
*/
|
|
88
|
-
function statusToErrorCode(status, data = {}) {
|
|
88
|
+
export function statusToErrorCode(status, data = {}) {
|
|
89
89
|
const message = data?.message || data?.error || '';
|
|
90
90
|
const messageLower = message.toLowerCase();
|
|
91
91
|
|
|
@@ -486,7 +486,7 @@ export class NansenAPI {
|
|
|
486
486
|
return cached;
|
|
487
487
|
}
|
|
488
488
|
}
|
|
489
|
-
|
|
489
|
+
|
|
490
490
|
let lastError;
|
|
491
491
|
|
|
492
492
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
@@ -974,7 +974,7 @@ export class NansenAPI {
|
|
|
974
974
|
}
|
|
975
975
|
|
|
976
976
|
async tokenFlows(params = {}) {
|
|
977
|
-
const { tokenAddress, chain = 'solana', filters = {}, orderBy, pagination, days = 30, date } = params;
|
|
977
|
+
const { tokenAddress, chain = 'solana', label, filters = {}, orderBy, pagination, days = 30, date } = params;
|
|
978
978
|
if (tokenAddress) {
|
|
979
979
|
const validation = validateTokenAddress(tokenAddress, chain);
|
|
980
980
|
if (!validation.valid) throw new NansenError(validation.error, validation.code);
|
|
@@ -984,6 +984,7 @@ export class NansenAPI {
|
|
|
984
984
|
token_address: tokenAddress,
|
|
985
985
|
chain,
|
|
986
986
|
date: dateRange,
|
|
987
|
+
label,
|
|
987
988
|
filters,
|
|
988
989
|
order_by: orderBy,
|
|
989
990
|
pagination
|
package/src/cli.js
CHANGED
|
@@ -7,9 +7,11 @@ import { NansenAPI, NansenError, ErrorCode, saveConfig, deleteConfig, getConfigF
|
|
|
7
7
|
import { buildWalletCommands } from './wallet.js';
|
|
8
8
|
import { buildTradingCommands } from './trading.js';
|
|
9
9
|
import { formatAlertsTable, buildAlertsCommands } from './commands/alerts.js';
|
|
10
|
+
import { buildAgentCommands } from './commands/agent.js';
|
|
10
11
|
import { resolveAddress, isEnsName } from './ens.js';
|
|
11
12
|
import fs from 'fs';
|
|
12
13
|
import { getUpdateNotification, getUpgradeNotice, scheduleUpdateCheck } from './update-check.js';
|
|
14
|
+
import { refreshCostMapIfStale, getCostForEndpoint } from './cost-cache.js';
|
|
13
15
|
import { trackCommandSucceeded, trackCommandFailed } from './telemetry.js';
|
|
14
16
|
import { createRequire } from 'module';
|
|
15
17
|
import * as readline from 'readline';
|
|
@@ -165,7 +167,7 @@ export function parseArgs(args) {
|
|
|
165
167
|
const key = arg.slice(2);
|
|
166
168
|
const next = args[i + 1];
|
|
167
169
|
|
|
168
|
-
if (key === 'pretty' || key === 'help' || key === 'version' || key === 'table' || key === 'no-retry' || key === 'cache' || key === 'no-cache' || key === 'stream' || key === 'enrich' || key === 'full' || key === 'human' || key === 'enabled' || key === 'disabled') {
|
|
170
|
+
if (key === 'pretty' || key === 'help' || key === 'version' || key === 'table' || key === 'no-retry' || key === 'cache' || key === 'no-cache' || key === 'stream' || key === 'enrich' || key === 'full' || key === 'human' || key === 'enabled' || key === 'disabled' || key === 'expert' || key === 'json') {
|
|
169
171
|
result.flags[key] = true;
|
|
170
172
|
} else if (next && (!next.startsWith('-') || /^-\d/.test(next))) {
|
|
171
173
|
// Try to parse as JSON first (for objects/arrays/booleans),
|
|
@@ -682,6 +684,7 @@ COMMANDS:
|
|
|
682
684
|
research smart-money, profiler, token, search, perp, portfolio, points
|
|
683
685
|
trade quote, execute
|
|
684
686
|
wallet create, list, show, export, default, delete, forget-password
|
|
687
|
+
agent Ask the Nansen AI research agent (fast/expert modes)
|
|
685
688
|
alerts list, create, update, toggle, delete
|
|
686
689
|
web search, fetch
|
|
687
690
|
account Show API key status, plan, and remaining credits
|
|
@@ -701,6 +704,10 @@ EXAMPLES:
|
|
|
701
704
|
nansen research profiler balance --address 0x... --chain ethereum
|
|
702
705
|
nansen trade quote --chain base --from ETH --to USDC --amount 1000000000000000000
|
|
703
706
|
|
|
707
|
+
DEPRECATED ALIASES (still work, will be removed in a future version):
|
|
708
|
+
smart-money, profiler, token, search, perp, portfolio, points → use "nansen research <command>"
|
|
709
|
+
quote, execute → use "nansen trade <command>"
|
|
710
|
+
|
|
704
711
|
Research chains: ethereum, solana, base, bnb, arbitrum, polygon, optimism, avalanche, linea, scroll, mantle, ronin, sei, plasma, sonic, monad, hyperevm, iotaevm
|
|
705
712
|
Trade chains: solana, base
|
|
706
713
|
Labels: Fund, Smart Trader, 30D/90D/180D Smart Trader, Smart HL Perps Trader
|
|
@@ -1193,10 +1200,15 @@ export function buildCommands(deps = {}) {
|
|
|
1193
1200
|
// Convenience filter for smart money only
|
|
1194
1201
|
const onlySmartMoney = options['smart-money'] || flags['smart-money'] || false;
|
|
1195
1202
|
if (onlySmartMoney) {
|
|
1196
|
-
filters.include_smart_money_labels = filters.include_smart_money_labels ||
|
|
1203
|
+
filters.include_smart_money_labels = filters.include_smart_money_labels ||
|
|
1197
1204
|
['Fund', 'Smart Trader', '30D Smart Trader', '90D Smart Trader', '180D Smart Trader'];
|
|
1198
1205
|
}
|
|
1199
1206
|
|
|
1207
|
+
const includeStablecoins = options['include-stablecoins'] ?? flags['include-stablecoins'];
|
|
1208
|
+
if (includeStablecoins !== undefined) {
|
|
1209
|
+
filters.include_stablecoins = includeStablecoins;
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1200
1212
|
const handlers = {
|
|
1201
1213
|
'indicators': () => apiInstance.tokenIndicators({ tokenAddress, chain }),
|
|
1202
1214
|
'ohlcv': () => apiInstance.tokenOhlcv({ tokenAddress, chain, timeframe: options.timeframe || '1d' }),
|
|
@@ -1228,7 +1240,8 @@ export function buildCommands(deps = {}) {
|
|
|
1228
1240
|
'holders': () => apiInstance.tokenHolders({ tokenAddress, chain, labelType: onlySmartMoney ? 'smart_money' : 'all_holders', filters, orderBy, pagination }),
|
|
1229
1241
|
'flows': () => {
|
|
1230
1242
|
const date = parseDateOption(options.date, days);
|
|
1231
|
-
|
|
1243
|
+
const label = options.label;
|
|
1244
|
+
return apiInstance.tokenFlows({ tokenAddress, chain, label, filters, orderBy, pagination, days, date });
|
|
1232
1245
|
},
|
|
1233
1246
|
'dex-trades': () => apiInstance.tokenDexTrades({ tokenAddress, chain, onlySmartMoney, filters, orderBy, pagination, days }),
|
|
1234
1247
|
'pnl': () => apiInstance.tokenPnlLeaderboard({ tokenAddress, chain, filters, orderBy, pagination, days }),
|
|
@@ -1250,7 +1263,7 @@ export function buildCommands(deps = {}) {
|
|
|
1250
1263
|
'help': () => ({
|
|
1251
1264
|
commands: ['info', 'ohlcv', 'screener', 'holders', 'flows', 'dex-trades', 'pnl', 'who-bought-sold', 'flow-intelligence', 'transfers', 'jup-dca', 'perp-trades', 'perp-positions', 'perp-pnl-leaderboard'],
|
|
1252
1265
|
description: 'Token God Mode endpoints',
|
|
1253
|
-
example: 'nansen token screener --chain solana --timeframe 24h --smart-money'
|
|
1266
|
+
example: 'nansen token screener --chain solana --timeframe 24h --smart-money --include-stablecoins false'
|
|
1254
1267
|
})
|
|
1255
1268
|
};
|
|
1256
1269
|
|
|
@@ -1509,6 +1522,11 @@ export function generateSubcommandHelp(command, subcommand, prefix = null) {
|
|
|
1509
1522
|
lines.push(`Params (* required): ${params.join(', ')}`);
|
|
1510
1523
|
}
|
|
1511
1524
|
|
|
1525
|
+
if (subSchema.endpoint) {
|
|
1526
|
+
const cost = getCostForEndpoint(subSchema.endpoint);
|
|
1527
|
+
if (cost) lines.push(`Cost: ${cost.free} credit${cost.free === 1 ? '' : 's'} (Free tier) / ${cost.pro} credit${cost.pro === 1 ? '' : 's'} (Pro tier)`);
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1512
1530
|
if (subSchema.returns?.length) {
|
|
1513
1531
|
lines.push(`Returns: ${subSchema.returns.join(', ')}`);
|
|
1514
1532
|
}
|
|
@@ -1548,12 +1566,7 @@ export async function runCLI(rawArgs, deps = {}) {
|
|
|
1548
1566
|
const subArgs = positional.slice(1);
|
|
1549
1567
|
const subcommand = subArgs[0];
|
|
1550
1568
|
|
|
1551
|
-
|
|
1552
|
-
if (DEPRECATED_TO_RESEARCH.has(command)) {
|
|
1553
|
-
errorOutput(`Warning: "nansen ${command}" is deprecated. Use "nansen research ${command}" instead.`);
|
|
1554
|
-
} else if (DEPRECATED_TO_TRADE.has(command)) {
|
|
1555
|
-
errorOutput(`Warning: "nansen ${command}" is deprecated. Use "nansen trade ${command}" instead.`);
|
|
1556
|
-
}
|
|
1569
|
+
|
|
1557
1570
|
|
|
1558
1571
|
const pretty = flags.pretty || flags.p;
|
|
1559
1572
|
const table = flags.table || flags.t;
|
|
@@ -1569,7 +1582,14 @@ export async function runCLI(rawArgs, deps = {}) {
|
|
|
1569
1582
|
if (updateNotification) errorOutput(updateNotification);
|
|
1570
1583
|
};
|
|
1571
1584
|
|
|
1572
|
-
|
|
1585
|
+
// Deprecation note for help output
|
|
1586
|
+
const deprecationNote = (cmd) => {
|
|
1587
|
+
if (DEPRECATED_TO_RESEARCH.has(cmd)) return `Note: "nansen ${cmd}" is deprecated. Use "nansen research ${cmd}" instead.\n\n`;
|
|
1588
|
+
if (DEPRECATED_TO_TRADE.has(cmd)) return `Note: "nansen ${cmd}" is deprecated. Use "nansen trade ${cmd}" instead.\n\n`;
|
|
1589
|
+
return '';
|
|
1590
|
+
};
|
|
1591
|
+
|
|
1592
|
+
const commands = { ...buildCommands(deps), ...buildWalletCommands(deps), ...buildTradingCommands(deps), ...buildAlertsCommands(deps), ...buildAgentCommands(deps), ...commandOverrides };
|
|
1573
1593
|
|
|
1574
1594
|
if (flags.version || flags.v) {
|
|
1575
1595
|
output(VERSION);
|
|
@@ -1577,6 +1597,7 @@ export async function runCLI(rawArgs, deps = {}) {
|
|
|
1577
1597
|
}
|
|
1578
1598
|
|
|
1579
1599
|
if (command === 'help' || flags.help || flags.h) {
|
|
1600
|
+
await refreshCostMapIfStale();
|
|
1580
1601
|
// Check for subcommand-specific help: nansen <command> <subcommand> --help
|
|
1581
1602
|
if (flags.help || flags.h) {
|
|
1582
1603
|
// Handle 'research <category> <sub> --help' (3-level)
|
|
@@ -1607,17 +1628,17 @@ export async function runCLI(rawArgs, deps = {}) {
|
|
|
1607
1628
|
}
|
|
1608
1629
|
// First try subcommand help
|
|
1609
1630
|
// Skip for 'trade'/'alerts' — their handlers show their own rich usage
|
|
1610
|
-
if (command && subcommand && command !== 'trade' && command !== 'alerts') {
|
|
1631
|
+
if (command && subcommand && command !== 'trade' && command !== 'alerts' && command !== 'agent') {
|
|
1611
1632
|
const subHelp = generateSubcommandHelp(command, subcommand);
|
|
1612
1633
|
if (subHelp) {
|
|
1613
|
-
output(subHelp);
|
|
1634
|
+
output(deprecationNote(command) + subHelp);
|
|
1614
1635
|
notify();
|
|
1615
1636
|
return { type: 'subcommand-help', command, subcommand };
|
|
1616
1637
|
}
|
|
1617
1638
|
}
|
|
1618
1639
|
// Then try command-level help (list subcommands)
|
|
1619
1640
|
// Skip for 'trade'/'alerts' — let the handler show its own usage
|
|
1620
|
-
const cmdSchemaLookup = command !== 'trade' && command !== 'alerts' && (SCHEMA.commands[command] || SCHEMA.commands.research.subcommands[command]);
|
|
1641
|
+
const cmdSchemaLookup = command !== 'trade' && command !== 'alerts' && command !== 'agent' && (SCHEMA.commands[command] || SCHEMA.commands.research.subcommands[command]);
|
|
1621
1642
|
if (command && cmdSchemaLookup) {
|
|
1622
1643
|
const cmdSchema = cmdSchemaLookup;
|
|
1623
1644
|
const lines = [`${command} — ${cmdSchema.description}`];
|
|
@@ -1638,7 +1659,7 @@ export async function runCLI(rawArgs, deps = {}) {
|
|
|
1638
1659
|
if (cmdSchema.examples?.length) {
|
|
1639
1660
|
lines.push(`\nExamples:\n ${cmdSchema.examples.join('\n ')}`);
|
|
1640
1661
|
}
|
|
1641
|
-
output(lines.join('\n'));
|
|
1662
|
+
output(deprecationNote(command) + lines.join('\n'));
|
|
1642
1663
|
notify();
|
|
1643
1664
|
return { type: 'command-help', command };
|
|
1644
1665
|
}
|
|
@@ -1681,7 +1702,6 @@ export async function runCLI(rawArgs, deps = {}) {
|
|
|
1681
1702
|
const formatted = formatOutput(errorData, { pretty, table });
|
|
1682
1703
|
output(formatted.text);
|
|
1683
1704
|
trackCommandFailed({ command: fullCommand, duration_ms: Date.now() - startTime, error_code: 'UNKNOWN_COMMAND', flags: usedFlags, chain });
|
|
1684
|
-
notify();
|
|
1685
1705
|
exit(1);
|
|
1686
1706
|
return { type: 'error', data: errorData };
|
|
1687
1707
|
}
|
|
@@ -1709,7 +1729,6 @@ export async function runCLI(rawArgs, deps = {}) {
|
|
|
1709
1729
|
// Commands that handle their own output return undefined
|
|
1710
1730
|
if (result === undefined) {
|
|
1711
1731
|
trackCommandSucceeded({ command: fullCommand, duration_ms: Date.now() - startTime, flags: usedFlags, chain });
|
|
1712
|
-
notify();
|
|
1713
1732
|
return { type: 'no-output', command };
|
|
1714
1733
|
}
|
|
1715
1734
|
|
|
@@ -1718,7 +1737,6 @@ export async function runCLI(rawArgs, deps = {}) {
|
|
|
1718
1737
|
const formatted = formatOutput(result, { pretty, table: false });
|
|
1719
1738
|
output(formatted.text);
|
|
1720
1739
|
trackCommandSucceeded({ command: fullCommand, duration_ms: Date.now() - startTime, flags: usedFlags, chain });
|
|
1721
|
-
notify();
|
|
1722
1740
|
return { type: 'schema', data: result };
|
|
1723
1741
|
}
|
|
1724
1742
|
|
|
@@ -1731,7 +1749,6 @@ export async function runCLI(rawArgs, deps = {}) {
|
|
|
1731
1749
|
// Alerts list with --table uses custom table format
|
|
1732
1750
|
if (command === 'alerts' && subcommand === 'list' && table) {
|
|
1733
1751
|
output(formatAlertsTable(result));
|
|
1734
|
-
notify();
|
|
1735
1752
|
return { type: 'success', data: result };
|
|
1736
1753
|
}
|
|
1737
1754
|
|
|
@@ -1743,7 +1760,6 @@ export async function runCLI(rawArgs, deps = {}) {
|
|
|
1743
1760
|
output(streamOutput);
|
|
1744
1761
|
}
|
|
1745
1762
|
trackCommandSucceeded({ command: fullCommand, duration_ms: Date.now() - startTime, from_cache: !!result?.fromCache, flags: usedFlags, chain });
|
|
1746
|
-
notify();
|
|
1747
1763
|
return { type: 'stream', data: result };
|
|
1748
1764
|
}
|
|
1749
1765
|
|
|
@@ -1751,7 +1767,6 @@ export async function runCLI(rawArgs, deps = {}) {
|
|
|
1751
1767
|
const formatted = formatOutput(successData, { pretty, table, csv });
|
|
1752
1768
|
output(formatted.text);
|
|
1753
1769
|
trackCommandSucceeded({ command: fullCommand, duration_ms: Date.now() - startTime, from_cache: !!result?.fromCache, flags: usedFlags, chain });
|
|
1754
|
-
notify();
|
|
1755
1770
|
return { type: csv ? 'csv' : 'success', data: result };
|
|
1756
1771
|
} catch (error) {
|
|
1757
1772
|
const errorData = formatError(error);
|
|
@@ -1765,7 +1780,6 @@ export async function runCLI(rawArgs, deps = {}) {
|
|
|
1765
1780
|
flags: usedFlags,
|
|
1766
1781
|
chain,
|
|
1767
1782
|
});
|
|
1768
|
-
notify();
|
|
1769
1783
|
exit(1);
|
|
1770
1784
|
return { type: 'error', data: errorData };
|
|
1771
1785
|
}
|