perp-cli 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/README.md +30 -25
  2. package/dist/_stderr-filter.d.ts +0 -0
  3. package/dist/_stderr-filter.js +30 -0
  4. package/dist/agent-wallet/expiry.d.ts +15 -0
  5. package/dist/agent-wallet/expiry.js +26 -0
  6. package/dist/agent-wallet/lighter-keystore.d.ts +34 -0
  7. package/dist/agent-wallet/lighter-keystore.js +232 -0
  8. package/dist/agent-wallet/passphrase.d.ts +13 -0
  9. package/dist/agent-wallet/passphrase.js +54 -0
  10. package/dist/agent-wallet/signing-strategy.d.ts +67 -0
  11. package/dist/agent-wallet/signing-strategy.js +51 -0
  12. package/dist/agent-wallet/store.d.ts +37 -0
  13. package/dist/agent-wallet/store.js +172 -0
  14. package/dist/api/public/_http.d.ts +15 -0
  15. package/dist/api/public/_http.js +24 -0
  16. package/dist/api/public/hyperliquid.js +36 -24
  17. package/dist/api/public/lighter.d.ts +7 -1
  18. package/dist/api/public/lighter.js +85 -37
  19. package/dist/api/public/pacifica.js +47 -18
  20. package/dist/bridge-engine.js +102 -49
  21. package/dist/cli-spec.js +1 -2
  22. package/dist/commands/account.js +2 -500
  23. package/dist/commands/agent.d.ts +8 -2
  24. package/dist/commands/agent.js +1903 -366
  25. package/dist/commands/alerts.js +3 -1
  26. package/dist/commands/arb/index.js +37 -7
  27. package/dist/commands/arb-auto.js +44 -11
  28. package/dist/commands/arb.js +83 -34
  29. package/dist/commands/bot.d.ts +1 -1
  30. package/dist/commands/bot.js +18 -14
  31. package/dist/commands/bridge.d.ts +1 -1
  32. package/dist/commands/bridge.js +4 -4
  33. package/dist/commands/funds.d.ts +1 -1
  34. package/dist/commands/funds.js +18 -68
  35. package/dist/commands/jobs.d.ts +1 -1
  36. package/dist/commands/jobs.js +2 -2
  37. package/dist/commands/manage.d.ts +1 -1
  38. package/dist/commands/manage.js +12 -84
  39. package/dist/commands/plan.d.ts +1 -1
  40. package/dist/commands/plan.js +2 -2
  41. package/dist/commands/portfolio.d.ts +19 -3
  42. package/dist/commands/portfolio.js +747 -163
  43. package/dist/commands/rebalance.d.ts +1 -1
  44. package/dist/commands/rebalance.js +18 -12
  45. package/dist/commands/risk.js +2 -6
  46. package/dist/commands/settings.js +30 -53
  47. package/dist/commands/trade.js +16 -15
  48. package/dist/commands/wallet.d.ts +2 -1
  49. package/dist/commands/wallet.js +756 -28
  50. package/dist/errors.d.ts +64 -0
  51. package/dist/errors.js +82 -2
  52. package/dist/event-stream.js +12 -1
  53. package/dist/exchanges/aster-typed-data.d.ts +156 -0
  54. package/dist/exchanges/aster-typed-data.js +189 -0
  55. package/dist/exchanges/aster.d.ts +60 -11
  56. package/dist/exchanges/aster.js +278 -136
  57. package/dist/exchanges/hyperliquid.d.ts +14 -0
  58. package/dist/exchanges/hyperliquid.js +84 -34
  59. package/dist/exchanges/lighter-spot.js +14 -3
  60. package/dist/exchanges/lighter.d.ts +66 -0
  61. package/dist/exchanges/lighter.js +199 -27
  62. package/dist/exchanges/pacifica-typed-data.d.ts +75 -0
  63. package/dist/exchanges/pacifica-typed-data.js +74 -0
  64. package/dist/exchanges/pacifica.d.ts +29 -1
  65. package/dist/exchanges/pacifica.js +94 -6
  66. package/dist/funding/rates.js +59 -21
  67. package/dist/guardrail/perp-guardrail.js +9 -1
  68. package/dist/index.d.ts +1 -1
  69. package/dist/index.js +255 -360
  70. package/dist/jobs.js +3 -1
  71. package/dist/mcp-server.js +85 -83
  72. package/dist/position-history.js +47 -4
  73. package/dist/settings.d.ts +67 -3
  74. package/dist/settings.js +1 -2
  75. package/dist/signer/ows-evm.d.ts +14 -0
  76. package/dist/signer/ows-evm.js +28 -9
  77. package/dist/smart-order.d.ts +8 -2
  78. package/dist/smart-order.js +46 -11
  79. package/dist/strategies/funding-arb.js +29 -8
  80. package/dist/trade-validator.js +30 -5
  81. package/dist/utils.d.ts +10 -0
  82. package/dist/utils.js +19 -0
  83. package/package.json +2 -2
  84. package/skills/perp-cli/SKILL.md +23 -14
  85. package/skills/perp-cli/references/agent-operations.md +6 -4
  86. package/skills/perp-cli/references/commands.md +55 -34
  87. package/skills/perp-cli/scripts/preflight.sh +4 -4
  88. package/skills/perp-cli/scripts/spot-perp-scan.sh +2 -2
  89. package/dist/__tests__/alert-logic.test.d.ts +0 -1
  90. package/dist/__tests__/alert-logic.test.js +0 -107
  91. package/dist/__tests__/arb-auto-3dex.test.d.ts +0 -1
  92. package/dist/__tests__/arb-auto-3dex.test.js +0 -397
  93. package/dist/__tests__/arb-history-stats.test.d.ts +0 -1
  94. package/dist/__tests__/arb-history-stats.test.js +0 -176
  95. package/dist/__tests__/arb-logic.test.d.ts +0 -1
  96. package/dist/__tests__/arb-logic.test.js +0 -84
  97. package/dist/__tests__/arb-manage.test.d.ts +0 -1
  98. package/dist/__tests__/arb-manage.test.js +0 -253
  99. package/dist/__tests__/arb-new-features.test.d.ts +0 -1
  100. package/dist/__tests__/arb-new-features.test.js +0 -457
  101. package/dist/__tests__/arb-sizing.test.d.ts +0 -1
  102. package/dist/__tests__/arb-sizing.test.js +0 -48
  103. package/dist/__tests__/arb-state.test.d.ts +0 -1
  104. package/dist/__tests__/arb-state.test.js +0 -284
  105. package/dist/__tests__/arb-userflow.test.d.ts +0 -1
  106. package/dist/__tests__/arb-userflow.test.js +0 -945
  107. package/dist/__tests__/arb-utils.test.d.ts +0 -1
  108. package/dist/__tests__/arb-utils.test.js +0 -264
  109. package/dist/__tests__/bot-conditions.test.d.ts +0 -1
  110. package/dist/__tests__/bot-conditions.test.js +0 -341
  111. package/dist/__tests__/client-id-tracker.test.d.ts +0 -1
  112. package/dist/__tests__/client-id-tracker.test.js +0 -137
  113. package/dist/__tests__/commands/new-atomic-commands.test.d.ts +0 -1
  114. package/dist/__tests__/commands/new-atomic-commands.test.js +0 -502
  115. package/dist/__tests__/commands/order-intent.test.d.ts +0 -1
  116. package/dist/__tests__/commands/order-intent.test.js +0 -600
  117. package/dist/__tests__/commands/trade-commands.test.d.ts +0 -1
  118. package/dist/__tests__/commands/trade-commands.test.js +0 -821
  119. package/dist/__tests__/config.test.d.ts +0 -1
  120. package/dist/__tests__/config.test.js +0 -86
  121. package/dist/__tests__/cross-chain-margin.test.d.ts +0 -1
  122. package/dist/__tests__/cross-chain-margin.test.js +0 -287
  123. package/dist/__tests__/dex-asset-map.test.d.ts +0 -1
  124. package/dist/__tests__/dex-asset-map.test.js +0 -191
  125. package/dist/__tests__/errors.test.d.ts +0 -1
  126. package/dist/__tests__/errors.test.js +0 -110
  127. package/dist/__tests__/event-stream.test.d.ts +0 -1
  128. package/dist/__tests__/event-stream.test.js +0 -276
  129. package/dist/__tests__/exchanges/interface.test.d.ts +0 -1
  130. package/dist/__tests__/exchanges/interface.test.js +0 -132
  131. package/dist/__tests__/exchanges/mock-adapter.d.ts +0 -69
  132. package/dist/__tests__/exchanges/mock-adapter.js +0 -137
  133. package/dist/__tests__/execution-log.test.d.ts +0 -1
  134. package/dist/__tests__/execution-log.test.js +0 -106
  135. package/dist/__tests__/funding-calc.test.d.ts +0 -1
  136. package/dist/__tests__/funding-calc.test.js +0 -71
  137. package/dist/__tests__/funding-history.test.d.ts +0 -1
  138. package/dist/__tests__/funding-history.test.js +0 -343
  139. package/dist/__tests__/funding-rates.test.d.ts +0 -1
  140. package/dist/__tests__/funding-rates.test.js +0 -342
  141. package/dist/__tests__/funding.test.d.ts +0 -1
  142. package/dist/__tests__/funding.test.js +0 -173
  143. package/dist/__tests__/gap-logic.test.d.ts +0 -1
  144. package/dist/__tests__/gap-logic.test.js +0 -43
  145. package/dist/__tests__/hip3-dex.test.d.ts +0 -1
  146. package/dist/__tests__/hip3-dex.test.js +0 -234
  147. package/dist/__tests__/integration/agent-features.integration.test.d.ts +0 -1
  148. package/dist/__tests__/integration/agent-features.integration.test.js +0 -553
  149. package/dist/__tests__/integration/atomic-commands.integration.test.d.ts +0 -13
  150. package/dist/__tests__/integration/atomic-commands.integration.test.js +0 -246
  151. package/dist/__tests__/integration/bridge-simulation.integration.test.d.ts +0 -1
  152. package/dist/__tests__/integration/bridge-simulation.integration.test.js +0 -453
  153. package/dist/__tests__/integration/bridge-strict.integration.test.d.ts +0 -1
  154. package/dist/__tests__/integration/bridge-strict.integration.test.js +0 -812
  155. package/dist/__tests__/integration/bridge.integration.test.d.ts +0 -1
  156. package/dist/__tests__/integration/bridge.integration.test.js +0 -309
  157. package/dist/__tests__/integration/cli-e2e.integration.test.d.ts +0 -1
  158. package/dist/__tests__/integration/cli-e2e.integration.test.js +0 -202
  159. package/dist/__tests__/integration/dex-arb.integration.test.d.ts +0 -1
  160. package/dist/__tests__/integration/dex-arb.integration.test.js +0 -116
  161. package/dist/__tests__/integration/envelope-consistency.integration.test.d.ts +0 -13
  162. package/dist/__tests__/integration/envelope-consistency.integration.test.js +0 -205
  163. package/dist/__tests__/integration/hip3-dex.integration.test.d.ts +0 -1
  164. package/dist/__tests__/integration/hip3-dex.integration.test.js +0 -147
  165. package/dist/__tests__/integration/hyperliquid.integration.test.d.ts +0 -1
  166. package/dist/__tests__/integration/hyperliquid.integration.test.js +0 -79
  167. package/dist/__tests__/integration/lighter.integration.test.d.ts +0 -1
  168. package/dist/__tests__/integration/lighter.integration.test.js +0 -53
  169. package/dist/__tests__/integration/new-commands-e2e.integration.test.d.ts +0 -9
  170. package/dist/__tests__/integration/new-commands-e2e.integration.test.js +0 -236
  171. package/dist/__tests__/integration/order-verification.integration.test.d.ts +0 -1
  172. package/dist/__tests__/integration/order-verification.integration.test.js +0 -321
  173. package/dist/__tests__/integration/pacifica.integration.test.d.ts +0 -1
  174. package/dist/__tests__/integration/pacifica.integration.test.js +0 -75
  175. package/dist/__tests__/integration/response-shapes.integration.test.d.ts +0 -1
  176. package/dist/__tests__/integration/response-shapes.integration.test.js +0 -278
  177. package/dist/__tests__/liquidity.test.d.ts +0 -1
  178. package/dist/__tests__/liquidity.test.js +0 -225
  179. package/dist/__tests__/plan-executor.test.d.ts +0 -1
  180. package/dist/__tests__/plan-executor.test.js +0 -314
  181. package/dist/__tests__/position-history.test.d.ts +0 -1
  182. package/dist/__tests__/position-history.test.js +0 -367
  183. package/dist/__tests__/retry.test.d.ts +0 -1
  184. package/dist/__tests__/retry.test.js +0 -310
  185. package/dist/__tests__/risk-assessment.test.d.ts +0 -1
  186. package/dist/__tests__/risk-assessment.test.js +0 -288
  187. package/dist/__tests__/security-adversarial.test.d.ts +0 -1
  188. package/dist/__tests__/security-adversarial.test.js +0 -574
  189. package/dist/__tests__/strategies.test.d.ts +0 -1
  190. package/dist/__tests__/strategies.test.js +0 -539
  191. package/dist/__tests__/trade-execution.test.d.ts +0 -1
  192. package/dist/__tests__/trade-execution.test.js +0 -129
  193. package/dist/__tests__/trade-validator.test.d.ts +0 -1
  194. package/dist/__tests__/trade-validator.test.js +0 -655
  195. package/dist/__tests__/utils.test.d.ts +0 -1
  196. package/dist/__tests__/utils.test.js +0 -76
  197. package/dist/arb/reconcile.d.ts +0 -28
  198. package/dist/arb/reconcile.js +0 -162
  199. package/dist/commands/alert.d.ts +0 -2
  200. package/dist/commands/alert.js +0 -421
  201. package/dist/commands/analytics.d.ts +0 -3
  202. package/dist/commands/analytics.js +0 -311
  203. package/dist/commands/arb-manage.d.ts +0 -5
  204. package/dist/commands/arb-manage.js +0 -5
  205. package/dist/commands/dashboard.d.ts +0 -3
  206. package/dist/commands/dashboard.js +0 -176
  207. package/dist/commands/deposit.d.ts +0 -4
  208. package/dist/commands/deposit.js +0 -573
  209. package/dist/commands/dex.d.ts +0 -3
  210. package/dist/commands/dex.js +0 -120
  211. package/dist/commands/env.d.ts +0 -2
  212. package/dist/commands/env.js +0 -136
  213. package/dist/commands/funding.d.ts +0 -3
  214. package/dist/commands/funding.js +0 -554
  215. package/dist/commands/gap.d.ts +0 -2
  216. package/dist/commands/gap.js +0 -305
  217. package/dist/commands/health.d.ts +0 -2
  218. package/dist/commands/health.js +0 -67
  219. package/dist/commands/multileg.d.ts +0 -16
  220. package/dist/commands/multileg.js +0 -174
  221. package/dist/commands/ows.d.ts +0 -2
  222. package/dist/commands/ows.js +0 -887
  223. package/dist/commands/pnl.d.ts +0 -12
  224. package/dist/commands/pnl.js +0 -243
  225. package/dist/commands/run.d.ts +0 -3
  226. package/dist/commands/run.js +0 -202
  227. package/dist/commands/stream.d.ts +0 -5
  228. package/dist/commands/stream.js +0 -200
  229. package/dist/commands/withdraw.d.ts +0 -3
  230. package/dist/commands/withdraw.js +0 -187
  231. package/dist/exchanges/edgex.d.ts +0 -62
  232. package/dist/exchanges/edgex.js +0 -552
  233. package/dist/exchanges/nado.d.ts +0 -52
  234. package/dist/exchanges/nado.js +0 -223
  235. package/dist/funding/index.d.ts +0 -3
  236. package/dist/funding/index.js +0 -3
  237. package/dist/retry.d.ts +0 -74
  238. package/dist/retry.js +0 -129
  239. package/dist/ws/market-feed.d.ts +0 -74
  240. package/dist/ws/market-feed.js +0 -227
@@ -1,3 +1,3 @@
1
1
  import { Command } from "commander";
2
2
  import type { ExchangeAdapter } from "../exchanges/index.js";
3
- export declare function registerRebalanceCommands(program: Command, getAdapterForExchange: (exchange: string) => Promise<ExchangeAdapter>, isJson: () => boolean): void;
3
+ export declare function registerFundsRebalanceCommands(parent: Command, getAdapterForExchange: (exchange: string) => Promise<ExchangeAdapter>, isJson: () => boolean): void;
@@ -3,8 +3,8 @@ import { formatUsd, makeTable, printJson, jsonOk } from "../utils.js";
3
3
  import { fetchAllBalances, computeRebalancePlan, describeBridgeRoute, estimateMoveTime, } from "../rebalance.js";
4
4
  import { EXCHANGE_TO_CHAIN, executeBestBridge } from "../bridge-engine.js";
5
5
  import { loadPrivateKey, parseSolanaKeypair } from "../config.js";
6
- export function registerRebalanceCommands(program, getAdapterForExchange, isJson) {
7
- const rebalance = program.command("rebalance").description("Cross-exchange balance management");
6
+ export function registerFundsRebalanceCommands(parent, getAdapterForExchange, isJson) {
7
+ const rebalance = parent.command("rebalance").description("Cross-exchange balance management");
8
8
  // ── rebalance check ──
9
9
  rebalance
10
10
  .command("check")
@@ -13,15 +13,18 @@ export function registerRebalanceCommands(program, getAdapterForExchange, isJson
13
13
  .action(async (opts) => {
14
14
  const exchangeNames = opts.exchanges.split(",").map((e) => e.trim());
15
15
  const adapters = new Map();
16
+ const unavailable = [];
16
17
  for (const name of exchangeNames) {
17
18
  try {
18
19
  adapters.set(name, await getAdapterForExchange(name));
19
20
  }
20
- catch {
21
- // skip unavailable
21
+ catch (e) {
22
+ unavailable.push({ exchange: name, error: e instanceof Error ? e.message : String(e) });
22
23
  }
23
24
  }
24
25
  if (adapters.size === 0) {
26
+ if (isJson())
27
+ return printJson(jsonOk({ snapshots: [], unavailable }));
25
28
  console.error(chalk.red("\n No exchanges available. Check credentials.\n"));
26
29
  return;
27
30
  }
@@ -29,7 +32,7 @@ export function registerRebalanceCommands(program, getAdapterForExchange, isJson
29
32
  console.log(chalk.cyan("\n Fetching balances across exchanges...\n"));
30
33
  const snapshots = await fetchAllBalances(adapters);
31
34
  if (isJson())
32
- return printJson(jsonOk(snapshots));
35
+ return printJson(jsonOk({ snapshots, unavailable }));
33
36
  const totalEquity = snapshots.reduce((s, e) => s + e.equity, 0);
34
37
  const totalAvailable = snapshots.reduce((s, e) => s + e.available, 0);
35
38
  const rows = snapshots.map((s) => {
@@ -61,15 +64,18 @@ export function registerRebalanceCommands(program, getAdapterForExchange, isJson
61
64
  .action(async (opts) => {
62
65
  const exchangeNames = opts.exchanges.split(",").map((e) => e.trim());
63
66
  const adapters = new Map();
67
+ const unavailable = [];
64
68
  for (const name of exchangeNames) {
65
69
  try {
66
70
  adapters.set(name, await getAdapterForExchange(name));
67
71
  }
68
- catch {
69
- // skip unavailable
72
+ catch (e) {
73
+ unavailable.push({ exchange: name, error: e instanceof Error ? e.message : String(e) });
70
74
  }
71
75
  }
72
76
  if (adapters.size < 2) {
77
+ if (isJson())
78
+ return printJson(jsonOk({ moves: [], unavailable, error: "Need at least 2 exchanges for rebalancing" }));
73
79
  console.error(chalk.red("\n Need at least 2 exchanges for rebalancing.\n"));
74
80
  return;
75
81
  }
@@ -81,7 +87,7 @@ export function registerRebalanceCommands(program, getAdapterForExchange, isJson
81
87
  reserve: parseFloat(opts.reserve),
82
88
  });
83
89
  if (isJson())
84
- return printJson(jsonOk(plan));
90
+ return printJson(jsonOk({ ...plan, unavailable }));
85
91
  // Show current state
86
92
  const rows = plan.snapshots.map((s) => {
87
93
  const target = plan.targetPerExchange;
@@ -109,7 +115,7 @@ export function registerRebalanceCommands(program, getAdapterForExchange, isJson
109
115
  console.log(chalk.gray(` Time: ${estimateMoveTime(m)}`));
110
116
  console.log();
111
117
  }
112
- console.log(chalk.yellow(` To execute: perp rebalance execute --exchanges ${opts.exchanges}\n`));
118
+ console.log(chalk.yellow(` To execute: perp funds rebalance execute --exchanges ${opts.exchanges}\n`));
113
119
  });
114
120
  // ── rebalance execute ──
115
121
  rebalance
@@ -207,14 +213,14 @@ export function registerRebalanceCommands(program, getAdapterForExchange, isJson
207
213
  catch (err) {
208
214
  console.error(chalk.red(` Bridge failed: ${err instanceof Error ? err.message : err}`));
209
215
  if (!isJson())
210
- console.log(chalk.yellow(` Manual fallback: perp bridge exchange --from ${move.from} --to ${move.to} --amount ${move.amount}\n`));
216
+ console.log(chalk.yellow(` Manual fallback: perp funds bridge exchange --from ${move.from} --to ${move.to} --amount ${move.amount}\n`));
211
217
  moveResults.push({ from: move.from, to: move.to, amount: move.amount, status: "bridge_failed", error: err instanceof Error ? err.message : String(err) });
212
218
  }
213
219
  }
214
220
  else {
215
221
  if (!isJson()) {
216
222
  console.log(chalk.gray(` Step 2: Bridge needed.`));
217
- console.log(chalk.gray(` Run: perp bridge exchange --from ${move.from} --to ${move.to} --amount ${move.amount}`));
223
+ console.log(chalk.gray(` Run: perp funds bridge exchange --from ${move.from} --to ${move.to} --amount ${move.amount}`));
218
224
  console.log();
219
225
  }
220
226
  moveResults.push({ from: move.from, to: move.to, amount: move.amount, status: "needs_bridge" });
@@ -222,7 +228,7 @@ export function registerRebalanceCommands(program, getAdapterForExchange, isJson
222
228
  }
223
229
  if (isJson())
224
230
  return printJson(jsonOk({ status: "executed", moves: moveResults }));
225
- console.log(chalk.cyan(" Rebalance initiated. Monitor progress with 'perp rebalance check'.\n"));
231
+ console.log(chalk.cyan(" Rebalance initiated. Monitor progress with 'perp funds rebalance check'.\n"));
226
232
  });
227
233
  }
228
234
  /**
@@ -336,14 +336,10 @@ export function registerRiskCommands(program, getAdapterForExchange, isJson) {
336
336
  }
337
337
  });
338
338
  });
339
- // ── deprecated: health (merged into risk) ──
340
- const healthCmd = program
339
+ program
341
340
  .command("health")
342
- .description("Use 'perp status --health'")
341
+ .description("Adapter health check across all 4 DEX")
343
342
  .action(async () => {
344
- if (!isJson())
345
- console.log(chalk.yellow(" Use 'perp status --health' instead.\n"));
346
343
  await runHealthCheck(isJson);
347
344
  });
348
- healthCmd._hidden = true;
349
345
  }
@@ -1,5 +1,5 @@
1
1
  import chalk from "chalk";
2
- import { printJson, jsonOk, jsonError, withJsonErrors } from "../utils.js";
2
+ import { printJson, jsonOk, withJsonErrors } from "../utils.js";
3
3
  import { loadSettings, saveSettings } from "../settings.js";
4
4
  import { ENV_FILE, loadEnvFile, setEnvVar, EXCHANGE_ENV_MAP, validateKey } from "./init.js";
5
5
  // Resolve exchange alias → env var key
@@ -34,7 +34,7 @@ export function registerSettingsCommands(program, isJson, getAdapterForExchange)
34
34
  return printJson(jsonOk(s));
35
35
  console.log(chalk.cyan.bold("\n CLI Settings\n"));
36
36
  console.log(` Default Exchange: ${s.defaultExchange ? chalk.cyan(s.defaultExchange) : chalk.gray("pacifica (built-in)")}`);
37
- console.log(` Referrals: ${s.referrals ? chalk.green("ON") : chalk.gray("OFF (opt-in)")}`);
37
+ console.log(` Referrals: ${chalk.green("MANDATORY (always on)")}`);
38
38
  console.log(chalk.white.bold("\n Referral Codes:"));
39
39
  console.log(` Pacifica: ${s.referralCodes.pacifica || chalk.gray("(none)")}`);
40
40
  console.log(` Hyperliquid: ${s.referralCodes.hyperliquid || chalk.gray("(none)")}`);
@@ -48,52 +48,13 @@ export function registerSettingsCommands(program, isJson, getAdapterForExchange)
48
48
  console.log(chalk.gray(`\n Config: ~/.perp/settings.json\n`));
49
49
  });
50
50
  });
51
- // ── settings referrals ──
52
- settings
53
- .command("referrals")
54
- .description("Enable or disable referral codes")
55
- .argument("<action>", "on | off")
56
- .action(async (action) => {
57
- await withJsonErrors(isJson(), async () => {
58
- const s = loadSettings();
59
- if (action === "on") {
60
- s.referrals = true;
61
- // Reset applied flags so referrals get re-sent on next connection
62
- s.referralApplied = { hyperliquid: false, lighter: false };
63
- saveSettings(s);
64
- if (isJson())
65
- return printJson(jsonOk({ referrals: true }));
66
- console.log(chalk.green("\n Referrals enabled. Codes will be sent on next connection.\n"));
67
- if (s.referralCodes.pacifica)
68
- console.log(` Pacifica builder code: ${s.referralCodes.pacifica}`);
69
- if (s.referralCodes.hyperliquid)
70
- console.log(` Hyperliquid referral: ${s.referralCodes.hyperliquid}`);
71
- if (s.referralCodes.lighter)
72
- console.log(` Lighter referral: ${s.referralCodes.lighter}`);
73
- console.log();
74
- }
75
- else if (action === "off") {
76
- s.referrals = false;
77
- saveSettings(s);
78
- if (isJson())
79
- return printJson(jsonOk({ referrals: false }));
80
- console.log(chalk.yellow("\n Referrals disabled. No codes will be sent.\n"));
81
- }
82
- else {
83
- if (isJson())
84
- return printJson(jsonError("INVALID_ARGS", `Invalid action "${action}". Usage: perp settings referrals <on|off>`));
85
- console.error(chalk.red(`\n Usage: perp settings referrals <on|off>\n`));
86
- }
87
- });
88
- });
51
+ // Note: `settings referrals on/off` removed in v0.12 — referral codes are
52
+ // now mandatory (SSOT-aligned with Pacifica's always-on builder code).
53
+ // To reset applied flags (force re-send on next connection):
54
+ // perp settings set referralApplied.hyperliquid false (and same for lighter)
89
55
  // ── settings fees ──
90
- const fees = settings
91
- .command("fees")
92
- .description("Show or sync exchange fee tiers");
93
- fees
94
- .command("show")
95
- .description("Show current fee tiers")
96
- .action(async () => {
56
+ // Bare `settings fees` shows current tiers (same as `settings fees show`).
57
+ const showFees = async () => {
97
58
  await withJsonErrors(isJson(), async () => {
98
59
  const s = loadSettings();
99
60
  if (isJson())
@@ -107,7 +68,15 @@ export function registerSettingsCommands(program, isJson, getAdapterForExchange)
107
68
  console.log(chalk.gray(`\n Sync from exchanges: perp settings fees sync`));
108
69
  console.log(chalk.gray(` Manual set: perp settings fees set <exchange> <taker> <maker>\n`));
109
70
  });
110
- });
71
+ };
72
+ const fees = settings
73
+ .command("fees")
74
+ .description("Show or sync exchange fee tiers (default action: show)")
75
+ .action(showFees);
76
+ fees
77
+ .command("show")
78
+ .description("Show current fee tiers")
79
+ .action(showFees);
111
80
  fees
112
81
  .command("sync")
113
82
  .description("Fetch fee tiers from exchange APIs and save")
@@ -228,9 +197,6 @@ export function registerSettingsCommands(program, isJson, getAdapterForExchange)
228
197
  }
229
198
  s.defaultExchange = value.toLowerCase();
230
199
  }
231
- else if (key === "referrals") {
232
- s.referrals = value === "true" || value === "on";
233
- }
234
200
  else if (key.startsWith("referralCodes.")) {
235
201
  const exchange = key.split(".")[1];
236
202
  if (exchange in s.referralCodes) {
@@ -241,9 +207,20 @@ export function registerSettingsCommands(program, isJson, getAdapterForExchange)
241
207
  return;
242
208
  }
243
209
  }
210
+ else if (key.startsWith("referralApplied.")) {
211
+ // Force re-apply: `set referralApplied.hyperliquid false`
212
+ const exchange = key.split(".")[1];
213
+ if (exchange in s.referralApplied) {
214
+ s.referralApplied[exchange] = value === "true" || value === "on";
215
+ }
216
+ else {
217
+ console.error(chalk.red(` Unknown exchange: ${exchange}`));
218
+ return;
219
+ }
220
+ }
244
221
  else {
245
222
  console.error(chalk.red(` Unknown key: ${key}`));
246
- console.log(chalk.gray(" Valid keys: default-exchange, referrals, referralCodes.pacifica, referralCodes.hyperliquid, referralCodes.lighter\n"));
223
+ console.log(chalk.gray(" Valid keys: default-exchange, referralCodes.{pacifica,hyperliquid,lighter}, referralApplied.{hyperliquid,lighter}\n"));
247
224
  return;
248
225
  }
249
226
  saveSettings(s);
@@ -320,7 +297,7 @@ export function registerSettingsCommands(program, isJson, getAdapterForExchange)
320
297
  console.log(` File: ${chalk.gray("~/.perp/.env")}\n`);
321
298
  }
322
299
  else {
323
- // Raw env var (e.g. LIGHTER_API_KEY, custom vars)
300
+ // Raw env var (e.g. LIGHTER_REFERRAL_CODE, custom vars)
324
301
  setEnvVar(name, value);
325
302
  if (isJson())
326
303
  return printJson(jsonOk({ key: name, file: ENV_FILE }));
@@ -1,4 +1,5 @@
1
1
  import { printJson, errorAndExit, withJsonErrors, jsonOk, jsonError, symbolMatch, formatUsd } from "../utils.js";
2
+ import { extractErrorMessage } from "../errors.js";
2
3
  import { logExecution } from "../execution-log.js";
3
4
  import { validateTrade } from "../trade-validator.js";
4
5
  import { generateClientId, logClientId, isOrderDuplicate } from "../client-id-tracker.js";
@@ -108,7 +109,7 @@ export function registerTradeCommands(program, getAdapter, isJson, isDryRun = ()
108
109
  logExecution({
109
110
  type: "market_order", exchange: adapter.name, symbol: symbol.toUpperCase(),
110
111
  side: s, size, status: "failed", dryRun: false,
111
- error: err instanceof Error ? err.message : String(err),
112
+ error: extractErrorMessage(err),
112
113
  meta: { ...(clientId ? { clientOrderId: clientId } : {}), ...(opts.smart ? { smart: true } : {}) },
113
114
  });
114
115
  throw err;
@@ -156,7 +157,7 @@ export function registerTradeCommands(program, getAdapter, isJson, isDryRun = ()
156
157
  logExecution({ type: "market_order", exchange: adapter.name, symbol: symbol.toUpperCase(), side: "buy", size, status: "success", dryRun: false, meta: opts.smart ? { smart: true } : undefined });
157
158
  }
158
159
  catch (err) {
159
- logExecution({ type: "market_order", exchange: adapter.name, symbol: symbol.toUpperCase(), side: "buy", size, status: "failed", dryRun: false, error: err instanceof Error ? err.message : String(err) });
160
+ logExecution({ type: "market_order", exchange: adapter.name, symbol: symbol.toUpperCase(), side: "buy", size, status: "failed", dryRun: false, error: extractErrorMessage(err) });
160
161
  throw err;
161
162
  }
162
163
  if (isJson())
@@ -194,7 +195,7 @@ export function registerTradeCommands(program, getAdapter, isJson, isDryRun = ()
194
195
  logExecution({ type: "market_order", exchange: adapter.name, symbol: symbol.toUpperCase(), side: "sell", size, status: "success", dryRun: false, meta: opts.smart ? { smart: true } : undefined });
195
196
  }
196
197
  catch (err) {
197
- logExecution({ type: "market_order", exchange: adapter.name, symbol: symbol.toUpperCase(), side: "sell", size, status: "failed", dryRun: false, error: err instanceof Error ? err.message : String(err) });
198
+ logExecution({ type: "market_order", exchange: adapter.name, symbol: symbol.toUpperCase(), side: "sell", size, status: "failed", dryRun: false, error: extractErrorMessage(err) });
198
199
  throw err;
199
200
  }
200
201
  if (isJson())
@@ -282,7 +283,7 @@ export function registerTradeCommands(program, getAdapter, isJson, isDryRun = ()
282
283
  logExecution({
283
284
  type: "limit_order", exchange: adapter.name, symbol: symbol.toUpperCase(),
284
285
  side: s, size, price, status: "failed", dryRun: false,
285
- error: err instanceof Error ? err.message : String(err),
286
+ error: extractErrorMessage(err),
286
287
  meta: clientId ? { clientOrderId: clientId } : undefined,
287
288
  });
288
289
  throw err;
@@ -317,7 +318,7 @@ export function registerTradeCommands(program, getAdapter, isJson, isDryRun = ()
317
318
  console.log(chalk.green(`\n Order ${oid} cancelled on ${adapter.name}.\n`));
318
319
  }
319
320
  catch (err) {
320
- logExecution({ type: "cancel", exchange: adapter.name, symbol, side: "cancel", size: "0", status: "failed", dryRun: false, error: err instanceof Error ? err.message : String(err), meta: { orderId: oid } });
321
+ logExecution({ type: "cancel", exchange: adapter.name, symbol, side: "cancel", size: "0", status: "failed", dryRun: false, error: extractErrorMessage(err), meta: { orderId: oid } });
321
322
  throw err;
322
323
  }
323
324
  return;
@@ -347,7 +348,7 @@ export function registerTradeCommands(program, getAdapter, isJson, isDryRun = ()
347
348
  console.log(chalk.green(`\n Order ${oid} cancelled on ${adapter.name}.\n`));
348
349
  }
349
350
  catch (err) {
350
- logExecution({ type: "cancel", exchange: adapter.name, symbol, side: "cancel", size: "0", status: "failed", dryRun: false, error: err instanceof Error ? err.message : String(err), meta: { orderId: oid } });
351
+ logExecution({ type: "cancel", exchange: adapter.name, symbol, side: "cancel", size: "0", status: "failed", dryRun: false, error: extractErrorMessage(err), meta: { orderId: oid } });
351
352
  throw err;
352
353
  }
353
354
  }
@@ -373,7 +374,7 @@ export function registerTradeCommands(program, getAdapter, isJson, isDryRun = ()
373
374
  console.log(chalk.green(`\n ${matching.length} order(s) for ${symbol} cancelled on ${adapter.name}.\n`));
374
375
  }
375
376
  catch (err) {
376
- logExecution({ type: "cancel", exchange: adapter.name, symbol, side: "cancel", size: "0", status: "failed", dryRun: false, error: err instanceof Error ? err.message : String(err), meta: { bySymbol: true } });
377
+ logExecution({ type: "cancel", exchange: adapter.name, symbol, side: "cancel", size: "0", status: "failed", dryRun: false, error: extractErrorMessage(err), meta: { bySymbol: true } });
377
378
  throw err;
378
379
  }
379
380
  }
@@ -422,8 +423,8 @@ export function registerTradeCommands(program, getAdapter, isJson, isDryRun = ()
422
423
  console.log(chalk.green(`\n TWAP job started in background.`));
423
424
  console.log(` ID: ${chalk.white.bold(job.id)}`);
424
425
  console.log(` Session: ${job.tmuxSession}`);
425
- console.log(` Logs: ${chalk.gray(`perp jobs logs ${job.id}`)}`);
426
- console.log(` Stop: ${chalk.gray(`perp jobs stop ${job.id}`)}\n`);
426
+ console.log(` Logs: ${chalk.gray(`perp background logs ${job.id}`)}`);
427
+ console.log(` Stop: ${chalk.gray(`perp background stop ${job.id}`)}\n`);
427
428
  return;
428
429
  }
429
430
  const adapter = await getAdapter();
@@ -484,7 +485,7 @@ export function registerTradeCommands(program, getAdapter, isJson, isDryRun = ()
484
485
  logExecution({ type: "stop_order", exchange: adapter.name, symbol: symbol.toUpperCase(), side: s, size, price: stopPrice, status: "success", dryRun: false });
485
486
  }
486
487
  catch (err) {
487
- logExecution({ type: "stop_order", exchange: adapter.name, symbol: symbol.toUpperCase(), side: s, size, price: stopPrice, status: "failed", dryRun: false, error: err instanceof Error ? err.message : String(err) });
488
+ logExecution({ type: "stop_order", exchange: adapter.name, symbol: symbol.toUpperCase(), side: s, size, price: stopPrice, status: "failed", dryRun: false, error: extractErrorMessage(err) });
488
489
  throw err;
489
490
  }
490
491
  if (isJson())
@@ -614,7 +615,7 @@ export function registerTradeCommands(program, getAdapter, isJson, isDryRun = ()
614
615
  });
615
616
  }
616
617
  catch (err) {
617
- const msg = err instanceof Error ? err.message : String(err);
618
+ const msg = extractErrorMessage(err);
618
619
  logExecution({
619
620
  type: "limit_order", exchange: adapter.name, symbol: sym,
620
621
  side: closeSide, size: levelSize, price: level.price,
@@ -709,13 +710,13 @@ export function registerTradeCommands(program, getAdapter, isJson, isDryRun = ()
709
710
  logExecution({
710
711
  type: "rebalance", exchange: adapter.name, symbol: symbol.toUpperCase(), side: mode,
711
712
  size: leverage, status: "failed", dryRun: false,
712
- error: err instanceof Error ? err.message : String(err),
713
+ error: extractErrorMessage(err),
713
714
  meta: { action: "set_leverage", leverage: parseInt(leverage), mode },
714
715
  });
715
716
  throw err;
716
717
  }
717
718
  });
718
- // grid/dca moved to 'perp bot grid' / 'perp bot dca'
719
+ // grid/dca moved to 'perp strategy grid' / 'perp strategy dca'
719
720
  // ── Position Management Shortcuts ──
720
721
  trade
721
722
  .command("close-all")
@@ -1080,7 +1081,7 @@ export function registerTradeCommands(program, getAdapter, isJson, isDryRun = ()
1080
1081
  });
1081
1082
  }
1082
1083
  catch (err) {
1083
- const msg = err instanceof Error ? err.message : String(err);
1084
+ const msg = extractErrorMessage(err);
1084
1085
  logExecution({
1085
1086
  type: "limit_order", exchange: adapter.name, symbol: sym,
1086
1087
  side: s, size: level.size, price: level.price,
@@ -1104,7 +1105,7 @@ export function registerTradeCommands(program, getAdapter, isJson, isDryRun = ()
1104
1105
  }
1105
1106
  console.log();
1106
1107
  });
1107
- // grid/dca/trailing-stop moved to 'perp bot'
1108
+ // grid/dca/trailing-stop moved to 'perp strategy'
1108
1109
  // ── PnL Tracker ──
1109
1110
  trade
1110
1111
  .command("pnl-track")
@@ -1,4 +1,5 @@
1
1
  import { Command } from "commander";
2
+ import type { ExchangeAdapter } from "../exchanges/index.js";
2
3
  /** Exported for smart landing page in index.ts */
3
4
  export declare function getWalletSetupStatus(): {
4
5
  hasWallets: boolean;
@@ -13,4 +14,4 @@ export declare function getWalletSetupStatus(): {
13
14
  export declare function getActiveWalletKey(exchange: string): string | null;
14
15
  /** Get wallet key by name. Returns null if wallet doesn't exist. */
15
16
  export declare function getWalletKeyByName(name: string): string | null;
16
- export declare function registerWalletCommands(program: Command, isJson: () => boolean): void;
17
+ export declare function registerWalletCommands(program: Command, isJson: () => boolean, getAdapter?: () => Promise<ExchangeAdapter>, getPacificaAdapter?: () => unknown): void;