dexterm-cli 0.1.5 → 0.1.7

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 (379) hide show
  1. package/dist/packages/agents/src/index.js +2 -0
  2. package/dist/packages/agents/src/schema.js +22 -1
  3. package/dist/packages/agents/src/spectator.js +54 -0
  4. package/dist/packages/agents/src/story.js +532 -0
  5. package/dist/packages/agents/src/tiers.js +28 -2
  6. package/dist/packages/agents/src/tools.js +31 -2
  7. package/dist/packages/autotrade/assets/exit-profile.schema.json +492 -0
  8. package/dist/packages/autotrade/assets/profiles/moonbag.json +46 -0
  9. package/dist/packages/autotrade/assets/profiles/runner.json +88 -0
  10. package/dist/packages/autotrade/assets/profiles/scalp.json +88 -0
  11. package/dist/packages/autotrade/assets/profiles/swing.json +88 -0
  12. package/dist/packages/autotrade/assets/strategies/moonbag.json +101 -0
  13. package/dist/packages/autotrade/assets/strategies/runner.json +101 -0
  14. package/dist/packages/autotrade/assets/strategies/sample-dip-ladder.json +188 -0
  15. package/dist/packages/autotrade/assets/strategies/scalp.json +98 -0
  16. package/dist/packages/autotrade/assets/strategies/swing.json +97 -0
  17. package/dist/packages/autotrade/assets/strategies/yolo.json +157 -0
  18. package/dist/packages/autotrade/assets/tapes/yolo-rehearsal.json +1 -0
  19. package/dist/packages/autotrade/src/account.js +74 -0
  20. package/dist/packages/autotrade/src/backtest.js +357 -0
  21. package/dist/packages/autotrade/src/basis-text.js +32 -0
  22. package/dist/packages/autotrade/src/chat/approvals.js +484 -0
  23. package/dist/packages/autotrade/src/chat/audit.js +140 -0
  24. package/dist/packages/autotrade/src/chat/config.js +93 -0
  25. package/dist/packages/autotrade/src/chat/connector.js +24 -0
  26. package/dist/packages/autotrade/src/chat/control.js +103 -0
  27. package/dist/packages/autotrade/src/chat/fake.js +100 -0
  28. package/dist/packages/autotrade/src/chat/format.js +71 -0
  29. package/dist/packages/autotrade/src/chat/hub.js +187 -0
  30. package/dist/packages/autotrade/src/chat/index.js +18 -0
  31. package/dist/packages/autotrade/src/chat/notify.js +292 -0
  32. package/dist/packages/autotrade/src/chat/pairing.js +46 -0
  33. package/dist/packages/autotrade/src/chat/redact.js +48 -0
  34. package/dist/packages/autotrade/src/chat/secrets.js +99 -0
  35. package/dist/packages/autotrade/src/chat/service.js +248 -0
  36. package/dist/packages/autotrade/src/chat/telegram.js +290 -0
  37. package/dist/packages/autotrade/src/desk-executor.js +188 -0
  38. package/dist/packages/autotrade/src/engine.js +387 -0
  39. package/dist/packages/autotrade/src/execution-port.js +97 -0
  40. package/dist/packages/autotrade/src/fleet-config.js +169 -0
  41. package/dist/packages/autotrade/src/fleet-control.js +276 -0
  42. package/dist/packages/autotrade/src/fleet.js +639 -0
  43. package/dist/packages/autotrade/src/index.js +53 -0
  44. package/dist/packages/autotrade/src/ledger.js +108 -0
  45. package/dist/packages/autotrade/src/live-source.js +182 -0
  46. package/dist/packages/autotrade/src/monitor-daemon.js +715 -0
  47. package/dist/packages/autotrade/src/monitor.js +190 -0
  48. package/dist/packages/autotrade/src/ollama-sessions.js +137 -0
  49. package/dist/packages/autotrade/src/paper-accounts.js +72 -0
  50. package/dist/packages/autotrade/src/replay.js +198 -0
  51. package/dist/packages/autotrade/src/runner-config.js +99 -0
  52. package/dist/packages/autotrade/src/runner.js +872 -0
  53. package/dist/packages/autotrade/src/safety.js +243 -0
  54. package/dist/packages/autotrade/src/session.js +269 -0
  55. package/dist/packages/autotrade/src/sessions.js +503 -0
  56. package/dist/packages/autotrade/src/store.js +250 -0
  57. package/dist/packages/autotrade/src/strategy.js +256 -0
  58. package/dist/packages/autotrade/src/trade-ledger.js +241 -0
  59. package/dist/packages/autotrade/src/yolo.js +140 -0
  60. package/dist/packages/cli/assets/claude/analyst-system.md +4 -4
  61. package/dist/packages/cli/assets/claude/plugin/skills/REGISTRY.json +1 -1
  62. package/dist/packages/cli/assets/claude/plugin/skills/larp-check/SKILL.md +15 -8
  63. package/dist/packages/cli/assets/claude/plugin/skills/token-dossier/SKILL.md +1 -1
  64. package/dist/packages/cli/src/agent-cmd.js +6 -4
  65. package/dist/packages/cli/src/agent-spectator.js +17 -1
  66. package/dist/packages/cli/src/ai-cmd.js +412 -0
  67. package/dist/packages/cli/src/analyst/backend.js +105 -15
  68. package/dist/packages/cli/src/analyst/codex.js +14 -9
  69. package/dist/packages/cli/src/analyst/larp-gauge.js +60 -0
  70. package/dist/packages/cli/src/analyst/ollama.js +263 -0
  71. package/dist/packages/cli/src/analyst/session.js +17 -3
  72. package/dist/packages/cli/src/app-help-gen.js +51 -15
  73. package/dist/packages/cli/src/autotrade-cmd/audit.js +57 -0
  74. package/dist/packages/cli/src/autotrade-cmd/backtest.js +199 -0
  75. package/dist/packages/cli/src/autotrade-cmd/flatten.js +64 -0
  76. package/dist/packages/cli/src/autotrade-cmd/fleet.js +397 -0
  77. package/dist/packages/cli/src/autotrade-cmd/requests.js +79 -0
  78. package/dist/packages/cli/src/autotrade-cmd/run.js +413 -0
  79. package/dist/packages/cli/src/autotrade-cmd/stop.js +76 -0
  80. package/dist/packages/cli/src/autotrade-cmd/strategies.js +198 -0
  81. package/dist/packages/cli/src/autotrade-cmd/strategy-control.js +174 -0
  82. package/dist/packages/cli/src/autotrade-cmd/telegram-host.js +101 -0
  83. package/dist/packages/cli/src/autotrade-cmd.js +168 -0
  84. package/dist/packages/cli/src/backtest-cmd.js +13 -2
  85. package/dist/packages/cli/src/display.js +208 -23
  86. package/dist/packages/cli/src/doctor.js +62 -3
  87. package/dist/packages/cli/src/export.js +10 -2
  88. package/dist/packages/cli/src/index.js +1 -1
  89. package/dist/packages/cli/src/ledger-cmd.js +288 -0
  90. package/dist/packages/cli/src/live/chart-fills.js +46 -0
  91. package/dist/packages/cli/src/live/dev-history.js +31 -15
  92. package/dist/packages/cli/src/live/index.js +28 -90
  93. package/dist/packages/cli/src/live/screens/newpairs-live.js +1 -1
  94. package/dist/packages/cli/src/live/screens/token-live.js +48 -15
  95. package/dist/packages/cli/src/live/screens/watchlist-live.js +1 -1
  96. package/dist/packages/cli/src/live/trade.js +30 -453
  97. package/dist/packages/cli/src/live/watchlist.js +1 -1
  98. package/dist/packages/cli/src/main.js +290 -199
  99. package/dist/packages/cli/src/mcp-cmd.js +7 -1
  100. package/dist/packages/cli/src/mcp-follow.js +103 -6
  101. package/dist/packages/cli/src/plan-cmd.js +15 -5
  102. package/dist/packages/cli/src/pnl-app.js +31 -21
  103. package/dist/packages/cli/src/pnl-card.js +158 -21
  104. package/dist/packages/cli/src/popup.js +38 -6
  105. package/dist/packages/cli/src/record-cmd.js +141 -20
  106. package/dist/packages/cli/src/scan/ui.js +7 -1
  107. package/dist/packages/cli/src/screens/agent-hud.js +773 -0
  108. package/dist/packages/cli/src/screens/analyst-session.js +11 -4
  109. package/dist/packages/cli/src/screens/analyst.js +3 -2
  110. package/dist/packages/cli/src/screens/autotrade-keys.js +169 -0
  111. package/dist/packages/cli/src/screens/autotrade-proposals.js +123 -0
  112. package/dist/packages/cli/src/screens/autotrade-screen.js +725 -0
  113. package/dist/packages/cli/src/screens/autotrade-ui.js +640 -0
  114. package/dist/packages/cli/src/screens/autotrade-worker.js +89 -0
  115. package/dist/packages/cli/src/screens/brain.js +634 -0
  116. package/dist/packages/cli/src/screens/newpairs.js +1 -1
  117. package/dist/packages/cli/src/screens/overlay.js +5 -2
  118. package/dist/packages/cli/src/screens/plans.js +5 -17
  119. package/dist/packages/cli/src/screens/pnl-chip.js +144 -0
  120. package/dist/packages/cli/src/screens/positions.js +6 -28
  121. package/dist/packages/cli/src/screens/screener.js +1 -0
  122. package/dist/packages/cli/src/screens/ticket.js +38 -205
  123. package/dist/packages/cli/src/screens/token.js +18 -9
  124. package/dist/packages/cli/src/screens/trending.js +1 -1
  125. package/dist/packages/cli/src/state.js +88 -18
  126. package/dist/packages/cli/src/telegram-cmd.js +451 -0
  127. package/dist/packages/cli/src/trade.js +3 -128
  128. package/dist/packages/cli/src/version.js +1 -1
  129. package/dist/packages/cli/src/wallet-cmd.js +39 -340
  130. package/dist/packages/cli/src/wallet-command.js +8 -11
  131. package/dist/packages/cli/src/widgets.js +0 -12
  132. package/dist/packages/custom/src/config.js +20 -2
  133. package/dist/packages/custom/src/schema.js +41 -10
  134. package/dist/packages/custom/src/workspace.js +3 -3
  135. package/dist/packages/data/src/basis.js +191 -0
  136. package/dist/packages/data/src/detail.js +53 -2
  137. package/dist/packages/data/src/index.js +2 -14
  138. package/dist/packages/data/src/larp/score.js +220 -0
  139. package/dist/packages/data/src/larp/x-account.js +316 -0
  140. package/dist/packages/data/src/store.js +14 -5
  141. package/dist/packages/data/src/trade/agent/paper-desk.js +300 -23
  142. package/dist/packages/data/src/trade/agent/rendezvous.js +3 -2
  143. package/dist/packages/data/src/trade/bridge.js +4 -102
  144. package/dist/packages/data/src/trade/ledger/export.js +101 -0
  145. package/dist/packages/data/src/trade/ledger/file.js +135 -0
  146. package/dist/packages/data/src/trade/ledger/fold.js +191 -0
  147. package/dist/packages/data/src/trade/ledger/index.js +9 -0
  148. package/dist/packages/data/src/trade/ledger/schema.js +83 -0
  149. package/dist/packages/data/src/trade/ledger/sources.js +307 -0
  150. package/dist/packages/data/src/trade/ledger/stats.js +123 -0
  151. package/dist/packages/data/src/trade/ledger/tags.js +116 -0
  152. package/dist/packages/data/src/trade/ledger/view.js +51 -0
  153. package/dist/packages/data/src/trade/plans/engine.js +7 -0
  154. package/dist/packages/data/src/trade/plans/index.js +0 -1
  155. package/dist/packages/data/src/trade/plans/mandate.js +28 -15
  156. package/dist/packages/data/src/trade/plans/service.js +4 -28
  157. package/dist/packages/mcp/assets/kb/app-help/autotrade-chat.md +48 -0
  158. package/dist/packages/mcp/assets/kb/app-help/autotrade-parallel.md +42 -0
  159. package/dist/packages/mcp/assets/kb/app-help/autotrade-runner.md +35 -0
  160. package/dist/packages/mcp/assets/kb/app-help/autotrade-stop.md +37 -0
  161. package/dist/packages/mcp/assets/kb/app-help/autotrade-strategies.md +35 -0
  162. package/dist/packages/mcp/assets/kb/app-help/autotrade-telegram.md +40 -0
  163. package/dist/packages/mcp/assets/kb/app-help/chart-trade-markers.md +42 -0
  164. package/dist/packages/mcp/assets/kb/app-help/dev-history.md +1 -1
  165. package/dist/packages/mcp/assets/kb/app-help/larp-check.md +5 -1
  166. package/dist/packages/mcp/assets/kb/app-help/link-a-wallet.md +4 -10
  167. package/dist/packages/mcp/assets/kb/app-help/live-trading.md +38 -0
  168. package/dist/packages/mcp/assets/kb/app-help/live-yolo.md +34 -0
  169. package/dist/packages/mcp/assets/kb/app-help/order-plans.md +1 -1
  170. package/dist/packages/mcp/assets/kb/app-help/price-or-marketcap.md +5 -2
  171. package/dist/packages/mcp/assets/kb/app-help/scan-mode.md +1 -1
  172. package/dist/packages/mcp/assets/kb/app-help/screen-analyst.md +3 -0
  173. package/dist/packages/mcp/assets/kb/app-help/screen-autotrade.md +217 -0
  174. package/dist/packages/mcp/assets/kb/app-help/screen-kol.md +3 -0
  175. package/dist/packages/mcp/assets/kb/app-help/screen-newpairs.md +3 -0
  176. package/dist/packages/mcp/assets/kb/app-help/screen-positions.md +3 -0
  177. package/dist/packages/mcp/assets/kb/app-help/screen-screener.md +3 -0
  178. package/dist/packages/mcp/assets/kb/app-help/screen-token.md +6 -0
  179. package/dist/packages/mcp/assets/kb/app-help/screen-trending.md +3 -0
  180. package/dist/packages/mcp/assets/kb/app-help/screen-watchlist.md +3 -0
  181. package/dist/packages/mcp/assets/kb/app-help/spectate-an-agent.md +2 -1
  182. package/dist/packages/mcp/assets/kb/app-help/standing-mandates.md +1 -1
  183. package/dist/packages/mcp/assets/kb/app-help/trade-ledger.md +54 -0
  184. package/dist/packages/mcp/assets/kb/app-help/use-local-model.md +38 -0
  185. package/dist/packages/mcp/assets/kb/docs/docs-agents-agent-paper-trading.md +7 -3
  186. package/dist/packages/mcp/assets/kb/docs/docs-agents-reading-your-trade-ledger.md +31 -0
  187. package/dist/packages/mcp/assets/kb/docs/docs-agents-untrusted-by-default.md +1 -1
  188. package/dist/packages/mcp/assets/kb/docs/docs-analyst-if-claude-is-missing.md +1 -1
  189. package/dist/packages/mcp/assets/kb/docs/docs-analyst-starting-a-run.md +2 -0
  190. package/dist/packages/mcp/assets/kb/docs/docs-analyst-use-a-local-model-instead.md +27 -0
  191. package/dist/packages/mcp/assets/kb/docs/docs-analyst-what-it-sees.md +2 -0
  192. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-backtests-and-their-limits.md +56 -0
  193. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-change-a-strategy-by-chat.md +49 -0
  194. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-checking-the-record-of-a-run.md +28 -0
  195. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-comparing-them.md +41 -0
  196. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-exits-and-wakes.md +76 -0
  197. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-how-a-stop-reaches-the-runner.md +32 -0
  198. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-on-the-q-screen.md +37 -0
  199. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-one-strategy-or-all-of-them.md +35 -0
  200. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-paper-accounts.md +50 -0
  201. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-presets.md +37 -0
  202. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-running-it-all-day.md +31 -0
  203. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-sessions-and-their-limits.md +31 -0
  204. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-several-strategies-at-once.md +33 -0
  205. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-stopping-it.md +35 -0
  206. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-strategies-and-presets.md +34 -0
  207. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-the-autotrade-json-file.md +48 -0
  208. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-the-heartbeat.md +27 -0
  209. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-the-run-file-and-the-heartbeat.md +34 -0
  210. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-the-runner-and-candidate-sessions.md +45 -0
  211. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-what-each-session-shows-first.md +31 -0
  212. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-what-it-costs-claude-usage-per-session.md +58 -0
  213. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-what-it-is-paper-self-directed.md +43 -0
  214. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-what-it-will-not-do.md +31 -0
  215. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-which-account-day-caps-and-the-usage-guard.md +44 -0
  216. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-your-strategies.md +37 -0
  217. package/dist/packages/mcp/assets/kb/docs/docs-autotrade.md +22 -0
  218. package/dist/packages/mcp/assets/kb/docs/docs-beginners-before-any-experimental-trading.md +2 -2
  219. package/dist/packages/mcp/assets/kb/docs/docs-beginners.md +1 -1
  220. package/dist/packages/mcp/assets/kb/docs/docs-configuration-chart-markers.md +30 -0
  221. package/dist/packages/mcp/assets/kb/docs/docs-configuration-chart-y-axis.md +32 -0
  222. package/dist/packages/mcp/assets/kb/docs/docs-configuration-environment-variables.md +4 -1
  223. package/dist/packages/mcp/assets/kb/docs/docs-configuration-files-on-disk.md +1 -0
  224. package/dist/packages/mcp/assets/kb/docs/docs-configuration-headless-recorder-dexterm-record.md +3 -1
  225. package/dist/packages/mcp/assets/kb/docs/docs-configuration-price-display-mode.md +9 -7
  226. package/dist/packages/mcp/assets/kb/docs/docs-copy-trading-stage-2-the-one-key-mirror-ticket-a-proposal.md +1 -1
  227. package/dist/packages/mcp/assets/kb/docs/docs-copy-trading-stage-3-capped-auto-mirror-default-off-less.md +1 -1
  228. package/dist/packages/mcp/assets/kb/docs/docs-copy-trading-what-is-proven-what-is-not.md +1 -1
  229. package/dist/packages/mcp/assets/kb/docs/docs-copy-trading.md +1 -1
  230. package/dist/packages/mcp/assets/kb/docs/docs-data-sources-recorded-history-and-retention.md +36 -0
  231. package/dist/packages/mcp/assets/kb/docs/docs-data-sources-sources.md +1 -0
  232. package/dist/packages/mcp/assets/kb/docs/docs-getting-started-first-run.md +1 -1
  233. package/dist/packages/mcp/assets/kb/docs/docs-getting-started-install.md +3 -3
  234. package/dist/packages/mcp/assets/kb/docs/docs-getting-started-requirements.md +1 -1
  235. package/dist/packages/mcp/assets/kb/docs/docs-getting-started-running-the-tests.md +1 -1
  236. package/dist/packages/mcp/assets/kb/docs/docs-getting-started.md +1 -1
  237. package/dist/packages/mcp/assets/kb/docs/docs-larp-measured-accuracy.md +1 -0
  238. package/dist/packages/mcp/assets/kb/docs/docs-larp-the-larp-score.md +60 -0
  239. package/dist/packages/mcp/assets/kb/docs/docs-larp-the-verdict.md +0 -2
  240. package/dist/packages/mcp/assets/kb/docs/docs-larp-what-it-looks-at.md +4 -1
  241. package/dist/packages/mcp/assets/kb/docs/docs-larp.md +1 -1
  242. package/dist/packages/mcp/assets/kb/docs/docs-live-trading-changed-in-0-1-7.md +26 -0
  243. package/dist/packages/mcp/assets/kb/docs/docs-live-trading-stopping.md +28 -0
  244. package/dist/packages/mcp/assets/kb/docs/docs-live-trading-the-short-version.md +34 -0
  245. package/dist/packages/mcp/assets/kb/docs/docs-live-trading-using-a-trading-bot-with-dexterm.md +33 -0
  246. package/dist/packages/mcp/assets/kb/docs/docs-live-trading-what-dexterm-does-not-do.md +30 -0
  247. package/dist/packages/mcp/assets/kb/docs/docs-live-trading-what-dexterm-does.md +29 -0
  248. package/dist/packages/mcp/assets/kb/docs/docs-live-trading.md +23 -0
  249. package/dist/packages/mcp/assets/kb/docs/docs-ollama-another-machine.md +28 -0
  250. package/dist/packages/mcp/assets/kb/docs/docs-ollama-autotrade-on-a-local-model.md +29 -0
  251. package/dist/packages/mcp/assets/kb/docs/docs-ollama-check-your-model-dexterm-ai-probe.md +38 -0
  252. package/dist/packages/mcp/assets/kb/docs/docs-ollama-how-we-checked.md +27 -0
  253. package/dist/packages/mcp/assets/kb/docs/docs-ollama-models-without-tool-calling.md +32 -0
  254. package/dist/packages/mcp/assets/kb/docs/docs-ollama-pick-the-engine-globally-or-per-surface.md +43 -0
  255. package/dist/packages/mcp/assets/kb/docs/docs-ollama-restriction-profiles.md +35 -0
  256. package/dist/packages/mcp/assets/kb/docs/docs-ollama-set-it-up-in-two-minutes.md +39 -0
  257. package/dist/packages/mcp/assets/kb/docs/docs-ollama-troubleshooting.md +35 -0
  258. package/dist/packages/mcp/assets/kb/docs/docs-ollama-what-runs-on-a-local-model.md +39 -0
  259. package/dist/packages/mcp/assets/kb/docs/docs-ollama-what-stays-outside-the-model.md +36 -0
  260. package/dist/packages/mcp/assets/kb/docs/docs-ollama-which-model.md +38 -0
  261. package/dist/packages/mcp/assets/kb/docs/docs-ollama-your-own-agent-on-the-local-model.md +28 -0
  262. package/dist/packages/mcp/assets/kb/docs/docs-ollama.md +28 -0
  263. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-letting-an-agent-paper-trade-experimental.md +3 -4
  264. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-link-a-wallet-read-only.md +30 -0
  265. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-order-plans-and-standing-mandates.md +4 -13
  266. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-panic.md +4 -7
  267. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-paper-only-mandates.md +40 -0
  268. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-pnl-cards.md +7 -7
  269. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-safety-model.md +34 -0
  270. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-ticket.md +3 -4
  271. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-trade-ledger.md +42 -0
  272. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-wallet.md +4 -5
  273. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-trade-moments.md +4 -5
  274. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading.md +4 -5
  275. package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-buy-and-sell-markers.md +37 -0
  276. package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-market-cap-axis.md +1 -1
  277. package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-what-it-shows.md +3 -1
  278. package/dist/packages/mcp/assets/kb/docs/docs-scan-the-read.md +2 -0
  279. package/dist/packages/mcp/assets/kb/docs/docs-screens-autotrade-paper.md +26 -0
  280. package/dist/packages/mcp/assets/kb/docs/docs-screens-dev-history.md +10 -7
  281. package/dist/packages/mcp/assets/kb/docs/docs-screens-order-plans.md +1 -1
  282. package/dist/packages/mcp/assets/kb/docs/docs-screens-token-screen.md +2 -0
  283. package/dist/packages/mcp/assets/kb/docs/docs-spectator-follow-over-mcp-in-the-running-terminal.md +1 -1
  284. package/dist/packages/mcp/assets/kb/docs/docs-spectator-limits.md +2 -0
  285. package/dist/packages/mcp/assets/kb/docs/docs-spectator-the-agent-hud-spectator-v2.md +58 -0
  286. package/dist/packages/mcp/assets/kb/docs/docs-spectator-the-brain-view-and-the-pnl-chip.md +46 -0
  287. package/dist/packages/mcp/assets/kb/docs/docs-spectator-the-three-surfaces.md +1 -1
  288. package/dist/packages/mcp/assets/kb/docs/docs-spectator.md +1 -1
  289. package/dist/packages/mcp/assets/kb/docs/docs-telegram-approve-one-tap-entries.md +50 -0
  290. package/dist/packages/mcp/assets/kb/docs/docs-telegram-control-the-commands.md +43 -0
  291. package/dist/packages/mcp/assets/kb/docs/docs-telegram-if-something-goes-wrong.md +30 -0
  292. package/dist/packages/mcp/assets/kb/docs/docs-telegram-notify-what-reaches-your-phone.md +41 -0
  293. package/dist/packages/mcp/assets/kb/docs/docs-telegram-set-it-up.md +47 -0
  294. package/dist/packages/mcp/assets/kb/docs/docs-telegram-the-record.md +26 -0
  295. package/dist/packages/mcp/assets/kb/docs/docs-telegram-what-it-is.md +33 -0
  296. package/dist/packages/mcp/assets/kb/docs/docs-telegram-what-it-will-not-do.md +31 -0
  297. package/dist/packages/mcp/assets/kb/docs/docs-telegram.md +23 -0
  298. package/dist/packages/mcp/assets/kb/docs/docs-troubleshooting-common-questions.md +1 -1
  299. package/dist/packages/mcp/assets/kb/docs/docs-troubleshooting-doctor-lines.md +4 -0
  300. package/dist/packages/mcp/assets/kb/docs/docs-voice-linux-and-windows.md +1 -1
  301. package/dist/packages/mcp/assets/kb/docs/docs-voice.md +1 -1
  302. package/dist/packages/mcp/assets/kb/docs/docs-yolo-1-replay-it-on-your-own-history.md +42 -0
  303. package/dist/packages/mcp/assets/kb/docs/docs-yolo-2-run-it-on-paper.md +34 -0
  304. package/dist/packages/mcp/assets/kb/docs/docs-yolo-3-watch-it-and-stop-it.md +32 -0
  305. package/dist/packages/mcp/assets/kb/docs/docs-yolo-the-rules.md +37 -0
  306. package/dist/packages/mcp/assets/kb/docs/docs-yolo-what-it-is.md +34 -0
  307. package/dist/packages/mcp/assets/kb/docs/docs-yolo-what-it-will-not-do.md +31 -0
  308. package/dist/packages/mcp/assets/kb/docs/docs-yolo.md +26 -0
  309. package/dist/packages/mcp/assets/kb/entries/autotrade.md +38 -0
  310. package/dist/packages/mcp/src/app-help.js +1 -1
  311. package/dist/packages/mcp/src/autotrade-tools.js +944 -0
  312. package/dist/packages/mcp/src/backtest-requests.js +71 -0
  313. package/dist/packages/mcp/src/engine/config.js +159 -0
  314. package/dist/packages/mcp/src/engine/index.js +10 -0
  315. package/dist/packages/mcp/src/engine/loop.js +101 -0
  316. package/dist/packages/mcp/src/engine/mcp-client.js +123 -0
  317. package/dist/packages/mcp/src/engine/ollama.js +258 -0
  318. package/dist/packages/mcp/src/engine/probe.js +110 -0
  319. package/dist/packages/mcp/src/engine/reason.js +35 -0
  320. package/dist/packages/mcp/src/engine/restrictions.js +111 -0
  321. package/dist/packages/mcp/src/index.js +7 -1
  322. package/dist/packages/mcp/src/ledger-tools.js +346 -0
  323. package/dist/packages/mcp/src/paper-agent.js +5 -2
  324. package/dist/packages/mcp/src/server.js +285 -36
  325. package/dist/packages/mcp/src/spectator-sink.js +85 -0
  326. package/dist/packages/packs/src/backtest.js +3 -1
  327. package/dist/packages/packs/src/index.js +1 -0
  328. package/dist/packages/packs/src/larp-score-backtest.js +119 -0
  329. package/dist/packages/popup/src/pages/chart-lib.js +169 -35
  330. package/dist/packages/popup/src/pages/chart.css +18 -0
  331. package/dist/packages/popup/src/pages/chart.html +6 -1
  332. package/dist/packages/popup/src/pages/chart.js +136 -10
  333. package/dist/packages/popup/src/pages/spectator.css +45 -0
  334. package/dist/packages/popup/src/pages/spectator.html +1 -0
  335. package/dist/packages/popup/src/pages/spectator.js +69 -0
  336. package/dist/packages/popup/src/protocol.js +4 -0
  337. package/dist/packages/popup/src/server.js +9 -1
  338. package/dist/packages/recorder/src/dev-history.js +7 -3
  339. package/dist/packages/recorder/src/index.js +2 -0
  340. package/dist/packages/recorder/src/recorder.js +63 -6
  341. package/dist/packages/recorder/src/retention.js +100 -0
  342. package/dist/packages/recorder/src/schema.js +34 -1
  343. package/dist/packages/recorder/src/ticks.js +237 -0
  344. package/dist/packages/tui/src/canvas.js +7 -0
  345. package/dist/packages/tui/src/fmt.js +53 -0
  346. package/dist/packages/tui/src/index.js +1 -0
  347. package/dist/packages/tui/src/keymap.js +25 -1
  348. package/dist/packages/tui/src/markers.js +219 -0
  349. package/dist/packages/tui/src/widgets.js +158 -6
  350. package/package.json +2 -1
  351. package/dist/packages/data/src/trade/caps.js +0 -323
  352. package/dist/packages/data/src/trade/executor.js +0 -933
  353. package/dist/packages/data/src/trade/plans/executor-live.js +0 -220
  354. package/dist/packages/data/src/trade/rpc-exec.js +0 -229
  355. package/dist/packages/data/src/trade/signer/client.js +0 -197
  356. package/dist/packages/data/src/trade/signer/fast-wallet.js +0 -154
  357. package/dist/packages/data/src/trade/signer/host.js +0 -97
  358. package/dist/packages/data/src/trade/signer/main.js +0 -121
  359. package/dist/packages/data/src/trade/signer/probe-builder.js +0 -85
  360. package/dist/packages/data/src/trade/signer/protocol.js +0 -92
  361. package/dist/packages/data/src/trade/signer/service.js +0 -400
  362. package/dist/packages/data/src/trade/signer/sol-usd-feed.js +0 -98
  363. package/dist/packages/data/src/trade/sol-usd.js +0 -86
  364. package/dist/packages/data/src/trade/swap-build.js +0 -108
  365. package/dist/packages/data/src/trade/token-delta.js +0 -201
  366. package/dist/packages/data/vendor/solana-web3/LICENSE +0 -20
  367. package/dist/packages/data/vendor/solana-web3/NOTICE.md +0 -13
  368. package/dist/packages/data/vendor/solana-web3/index.iife.min.js +0 -20
  369. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-a-live-ticket.md +0 -42
  370. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-before-you-press-size-vs-caps.md +0 -34
  371. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-devnet-signer-mainnet-token.md +0 -35
  372. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-jupiter-rate-limits.md +0 -33
  373. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-link-a-wallet.md +0 -32
  374. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-live-trading-devnet-first.md +0 -30
  375. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-mainnet.md +0 -31
  376. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-live-fire-path-devnet-the-fast-wallet.md +0 -41
  377. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-signer-process.md +0 -34
  378. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-what-the-live-path-keeps.md +0 -37
  379. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-your-first-live-trade.md +0 -41
@@ -1,154 +0,0 @@
1
- // task-1363 — the capped FAST WALLET (SPEC §6.13.2 `wallet: 'fast'`): the one key dexterm ever holds, and only
2
- // on DEVNET. Standing-mandate fills must run at machine speed, which a Phantom round-trip per fill cannot do,
3
- // so an armed mandate fires from this separate hot key instead of the user's main wallet. The main wallet is
4
- // never named by a mandate (the schema says `fast`), and this signer refuses to sign for any other public key.
5
- //
6
- // Boundaries, by construction:
7
- // * devnet only — the record carries `network: 'devnet'`; create/load refuse anything else, and the signer
8
- // process only loads it when ITS RPC endpoint classifies as devnet (signer/main.ts). There is no mainnet path.
9
- // * created only by `dexterm wallet fast create` on a real TTY after a keypress; there is NO channel method
10
- // to create, export, import or replace it (the signer protocol has `fast` = status and `fill` = build).
11
- // * hard per-fill ceiling: a single fill may move at most FAST_MAX_SOL_PER_FILL SOL out of it (lamports
12
- // bound at build and again on the signed bytes), on top of the signer's USD caps which this lane enforces
13
- // even on devnet (task-1363: "per-trade and daily caps enforced signer-side").
14
- // * the seed lives in ~/.dexterm/fast-wallet.json at mode 600 and never leaves this module: `get()` returns
15
- // the public record only; `load()` returns a signer object with a sign method, not the key bytes.
16
- //
17
- // Ed25519 via node:crypto only (no wallet library). The signed wire tx is `shortvec(1) + sig + message`, the
18
- // same shape the executor decodes, compares to the approved message, Ed25519-verifies and re-simulates.
19
- import { createPrivateKey, createPublicKey, randomBytes, sign as edSign } from 'node:crypto';
20
- import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync, rmSync } from 'node:fs';
21
- import { homedir } from 'node:os';
22
- import { dirname, join } from 'node:path';
23
- import { base58 } from "../../sources/solana-rpc.js";
24
- import { decodeTransaction } from "../tx-decode.js";
25
- export const FAST_WALLET_NETWORK = 'devnet';
26
- /** Hard ceiling on the SOL a single mandate fill may move out of the fast wallet (devnet-sized). */
27
- export const FAST_MAX_SOL_PER_FILL = 0.05;
28
- export const FAST_MAX_SOL_PER_FILL_LAMPORTS = 50000000n;
29
- export const FAST_WALLET_PROVIDER = 'fast-wallet';
30
- const B58 = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
31
- /** PKCS#8 DER prefix for an Ed25519 private key (RFC 8410): the 32-byte seed follows. */
32
- const PKCS8_ED25519_PREFIX = Buffer.from('302e020100300506032b657004220420', 'hex');
33
- export function defaultFastWalletPath(env = process.env) {
34
- const home = env.DEXTERM_HOME && env.DEXTERM_HOME.length ? env.DEXTERM_HOME : join(homedir(), '.dexterm');
35
- return join(home, 'fast-wallet.json');
36
- }
37
- function privateKeyFromSeed(seed) {
38
- if (seed.length !== 32)
39
- throw new Error('fast wallet: seed must be 32 bytes');
40
- return createPrivateKey({ key: Buffer.concat([PKCS8_ED25519_PREFIX, seed]), format: 'der', type: 'pkcs8' });
41
- }
42
- function publicKeyOf(priv) {
43
- const der = createPublicKey(priv).export({ format: 'der', type: 'spki' });
44
- return base58(der.subarray(der.length - 32));
45
- }
46
- function shortvec(n) {
47
- const out = [];
48
- do {
49
- let b = n & 0x7f;
50
- n >>= 7;
51
- if (n)
52
- b |= 0x80;
53
- out.push(b);
54
- } while (n);
55
- return Buffer.from(out);
56
- }
57
- /** The thing that signs: holds the key object, exposes only `publicKey` and `signTransaction`. */
58
- export class FastWalletSigner {
59
- publicKey;
60
- provider = FAST_WALLET_PROVIDER;
61
- key;
62
- constructor(seed) {
63
- this.key = privateKeyFromSeed(seed);
64
- this.publicKey = publicKeyOf(this.key);
65
- }
66
- /**
67
- * Sign ONE transaction for the fast wallet itself (same call shape as the Phantom bridge, so the executor's
68
- * pipeline is unchanged). Refuses: a caller expecting any other key, a transaction whose fee payer / sole
69
- * required signer is not this wallet, more than one required signature, or undecodable bytes.
70
- */
71
- async signTransaction(args) {
72
- const t0 = Date.now();
73
- if (args.expectPublicKey !== undefined && args.expectPublicKey !== this.publicKey)
74
- throw new Error('fast wallet: refusing to sign for a different public key');
75
- const tx = decodeTransaction(Buffer.from(args.unsignedTxBase64, 'base64')); // throws on malformed bytes
76
- if (tx.numRequiredSignatures !== 1)
77
- throw new Error(`fast wallet: refusing a transaction with ${tx.numRequiredSignatures} required signatures`);
78
- if (tx.staticKeys[0] !== this.publicKey)
79
- throw new Error('fast wallet: the transaction fee payer is not the fast wallet');
80
- const sig = edSign(null, tx.message, this.key);
81
- const wire = Buffer.concat([shortvec(1), sig, tx.message]).toString('base64');
82
- return { signedTxBase64: wire, provider: FAST_WALLET_PROVIDER, roundTripMs: Date.now() - t0 };
83
- }
84
- }
85
- /**
86
- * The on-disk record. `create` writes a fresh key (never overwrites), `get` reads the PUBLIC fields only,
87
- * `load` returns a signer (or null when there is none / the file is unreadable or not devnet), `remove`
88
- * deletes the file. Nothing here talks to the network.
89
- */
90
- export class FastWalletStore {
91
- path;
92
- constructor(path = defaultFastWalletPath()) { this.path = path; }
93
- exists() { return existsSync(this.path); }
94
- read() {
95
- try {
96
- if (!existsSync(this.path))
97
- return null;
98
- const raw = JSON.parse(readFileSync(this.path, 'utf8'));
99
- if (raw.v !== 1 || raw.network !== FAST_WALLET_NETWORK)
100
- return null;
101
- if (typeof raw.publicKey !== 'string' || !B58.test(raw.publicKey) || typeof raw.seed !== 'string')
102
- return null;
103
- return { v: 1, network: FAST_WALLET_NETWORK, publicKey: raw.publicKey, seed: raw.seed, createdAt: Number(raw.createdAt) || 0 };
104
- }
105
- catch {
106
- return null;
107
- }
108
- }
109
- /** Public fields only (no seed). Null when absent/malformed. */
110
- get() {
111
- const r = this.read();
112
- return r ? { publicKey: r.publicKey, network: r.network, createdAt: r.createdAt } : null;
113
- }
114
- /** A signer over the stored seed, or null. The seed is checked against the stored public key. */
115
- load() {
116
- const r = this.read();
117
- if (!r)
118
- return null;
119
- try {
120
- const signer = new FastWalletSigner(Buffer.from(r.seed, 'base64'));
121
- return signer.publicKey === r.publicKey ? signer : null;
122
- }
123
- catch {
124
- return null;
125
- }
126
- }
127
- /**
128
- * Create a NEW devnet fast wallet. Refuses to overwrite an existing one (remove it first, after draining)
129
- * and refuses any network but devnet. The caller (the CLI) gates this behind a real TTY keypress.
130
- */
131
- create(opts) {
132
- if (opts.network !== FAST_WALLET_NETWORK)
133
- throw new Error('fast wallet: devnet only — there is no mainnet fast wallet');
134
- if (this.exists())
135
- throw new Error(`fast wallet: ${this.path} already exists; \`dexterm wallet fast remove\` first (after draining it)`);
136
- const seed = randomBytes(32);
137
- const signer = new FastWalletSigner(seed);
138
- const rec = { v: 1, network: FAST_WALLET_NETWORK, publicKey: signer.publicKey, seed: seed.toString('base64'), createdAt: opts.now ?? Date.now() };
139
- mkdirSync(dirname(this.path), { recursive: true });
140
- writeFileSync(this.path, JSON.stringify(rec, null, 2) + '\n', { mode: 0o600, flag: 'wx' });
141
- try {
142
- chmodSync(this.path, 0o600);
143
- }
144
- catch { /* best effort on platforms without chmod */ }
145
- return { publicKey: rec.publicKey, network: rec.network, createdAt: rec.createdAt };
146
- }
147
- /** Delete the record. Returns true when one existed. */
148
- remove() {
149
- if (!existsSync(this.path))
150
- return false;
151
- rmSync(this.path, { force: true });
152
- return true;
153
- }
154
- }
@@ -1,97 +0,0 @@
1
- // dexterm T2 — the signer HOST loop (task-1328): runs inside the signer process, reads authenticated
2
- // frames from `input` (the child's stdin), dispatches to the SignerService, and writes authenticated
3
- // responses to `output` (the child's stdout). Diagnostics go to `log` (stderr) and never carry bytes,
4
- // keys or the secret. Fails closed: a bad hello, too many bad frames, or a closed input ends the loop
5
- // (and the production entry exits the process).
6
- import { createInterface } from 'node:readline';
7
- import { decodeFrame, encodeFrame, isRequest, parseHello, MAX_BAD_FRAMES, MAX_FRAME_BYTES, SIGNER_METHODS } from "./protocol.js";
8
- /** Serve until the input ends. Resolves with the reason the loop stopped. */
9
- export function serveSigner(opts) {
10
- const log = opts.log ?? (() => { });
11
- return new Promise((resolve) => {
12
- let secret = null;
13
- let inSeq = 0;
14
- let outSeq = 0;
15
- let bad = 0;
16
- let ended = false;
17
- const rl = createInterface({ input: opts.input, crlfDelay: Infinity });
18
- const end = (why) => {
19
- if (ended)
20
- return;
21
- ended = true;
22
- try {
23
- rl.close();
24
- }
25
- catch { /* ignore */ }
26
- opts.onEnd?.(why);
27
- resolve(why);
28
- };
29
- const send = (m) => {
30
- if (!secret)
31
- return;
32
- try {
33
- opts.output.write(encodeFrame(secret, outSeq++, m));
34
- }
35
- catch (e) {
36
- log(`signer: write failed: ${e instanceof Error ? e.message : String(e)}`);
37
- end('output closed');
38
- }
39
- };
40
- const strike = (why) => {
41
- bad++;
42
- log(`signer: dropped frame (${why}) ${bad}/${MAX_BAD_FRAMES}`);
43
- if (bad >= MAX_BAD_FRAMES)
44
- end('too many bad frames');
45
- };
46
- rl.on('line', (line) => {
47
- if (ended)
48
- return;
49
- if (line.length > MAX_FRAME_BYTES) {
50
- strike('too large');
51
- return;
52
- }
53
- if (!secret) {
54
- const h = parseHello(line);
55
- if (!h) {
56
- end('bad hello');
57
- return;
58
- }
59
- secret = h.secret;
60
- send({ event: 'ready', detail: { pid: process.pid } });
61
- return;
62
- }
63
- const d = decodeFrame(secret, line, inSeq);
64
- if (!d.ok) {
65
- strike(d.why);
66
- return;
67
- }
68
- inSeq = d.seq + 1;
69
- const m = d.message;
70
- if (!isRequest(m)) {
71
- strike('not a request');
72
- return;
73
- }
74
- const id = m.id;
75
- if (!SIGNER_METHODS.has(m.method)) {
76
- send({ id, ok: false, error: `unknown method ${JSON.stringify(String(m.method).slice(0, 32))}` });
77
- return;
78
- }
79
- void opts.service.call(m.method, m.params).then((result) => send({ id, ok: true, result }), (e) => {
80
- if (!(e instanceof Error)) {
81
- send({ id, ok: false, error: String(e) });
82
- return;
83
- }
84
- const reason = e.reason;
85
- const retryAfterMs = e.retryAfterMs;
86
- send({
87
- id, ok: false,
88
- error: `${typeof reason === 'string' ? `${reason}: ` : ''}${e.message}`,
89
- ...(typeof reason === 'string' ? { reason } : {}),
90
- ...(typeof retryAfterMs === 'number' && Number.isFinite(retryAfterMs) ? { retryAfterMs } : {}),
91
- });
92
- });
93
- });
94
- rl.on('close', () => end('input closed'));
95
- opts.input.on('error', () => end('input error'));
96
- });
97
- }
@@ -1,121 +0,0 @@
1
- // dexterm T2 — the signer PROCESS entry (task-1328). `node main.ts [caps flags]`. Wires the real
2
- // dependencies — its OWN HTTP client for Jupiter + RPC, its OWN SOL/USD feed, the wallet bridge (opens
3
- // the system browser for Phantom), the kill-switch file, the shared daily-cap ledger and the live fill
4
- // ledger — and serves the authenticated stdio channel until the parent closes it.
5
- //
6
- // Caps come from THIS process's argv (what the user typed when starting dexterm), clamped to the hard
7
- // ceilings and, without --mainnet, only ever DOWN from the defaults. Nothing on the channel can change
8
- // them. The RPC defaults to DEVNET; `--mainnet` switches to the user's configured mainnet RPC
9
- // (DEXTERM_RPC_URL / ~/.dexterm/helius.key / public). `--rpc URL` is honoured but the NETWORK the
10
- // signer reports and caps by is always classified from the URL it will actually talk to.
11
- import { createDataLayer } from "../../index.js";
12
- import { JupiterSwapBuild } from "../swap-build.js";
13
- import { TradeRpc, DEVNET_RPC, rpcNetwork } from "../rpc-exec.js";
14
- import { WalletBridge } from "../bridge.js";
15
- import { defaultCaps, capsOnlyDownward, CapLedger, defaultCapLedgerPath, HARD_MAX_PER_TRADE_USD, HARD_MAX_DAILY_USD, HARD_MAX_SOL_OUT, HARD_MAX_SLIPPAGE_BPS } from "../caps.js";
16
- import { LiveExecutor, LiveLedger, defaultLiveLedgerPath } from "../executor.js";
17
- import { KillSwitch, defaultPanicPath } from "../kill-switch.js";
18
- import { WalletLinkStore, defaultLinkPath } from "../link-store.js";
19
- import { resolveRpcUrl } from "../../rpc-config.js";
20
- import { DevnetProbeBuilder } from "./probe-builder.js";
21
- import { SolUsdFeed } from "./sol-usd-feed.js";
22
- import { FastWalletStore, defaultFastWalletPath } from "./fast-wallet.js";
23
- import { SignerService } from "./service.js";
24
- import { serveSigner } from "./host.js";
25
- /** Parse the signer's argv. Over-ceiling caps are an error (never silently accepted). */
26
- export function parseSignerArgs(argv, env = process.env) {
27
- let mainnet = false;
28
- let perTradeUsd, dailyUsd, maxSolOut, maxSlippageBps;
29
- let rpcUrl;
30
- let ledgerPath = defaultCapLedgerPath(), liveLedgerPath = defaultLiveLedgerPath(), linkPath = defaultLinkPath(), panicPath = defaultPanicPath();
31
- let fastWalletPath = defaultFastWalletPath(env);
32
- let noBrowser = false;
33
- const take = (flag, raw, ceiling) => {
34
- const n = Number(raw);
35
- if (!Number.isFinite(n) || n <= 0)
36
- return undefined;
37
- if (n > ceiling)
38
- throw new Error(`${flag} ${n} exceeds the hard ceiling of ${ceiling}`);
39
- return n;
40
- };
41
- for (let i = 0; i < argv.length; i++) {
42
- const k = argv[i];
43
- if (k === '--mainnet')
44
- mainnet = true;
45
- else if (k === '--max-usd')
46
- perTradeUsd = take(k, argv[++i], HARD_MAX_PER_TRADE_USD);
47
- else if (k === '--daily-usd')
48
- dailyUsd = take(k, argv[++i], HARD_MAX_DAILY_USD);
49
- else if (k === '--max-sol-out')
50
- maxSolOut = take(k, argv[++i], HARD_MAX_SOL_OUT);
51
- else if (k === '--max-slippage-bps')
52
- maxSlippageBps = take(k, argv[++i], HARD_MAX_SLIPPAGE_BPS);
53
- else if (k === '--rpc')
54
- rpcUrl = argv[++i];
55
- else if (k === '--ledger')
56
- ledgerPath = argv[++i];
57
- else if (k === '--live-ledger')
58
- liveLedgerPath = argv[++i];
59
- else if (k === '--link')
60
- linkPath = argv[++i];
61
- else if (k === '--panic-file')
62
- panicPath = argv[++i];
63
- else if (k === '--fast-wallet')
64
- fastWalletPath = argv[++i];
65
- else if (k === '--no-browser')
66
- noBrowser = true;
67
- }
68
- const caps = capsOnlyDownward(defaultCaps({ network: mainnet ? 'mainnet' : 'devnet', mainnetEnabled: mainnet, perTradeUsd, dailyUsd, maxSolOut, maxSlippageBps }));
69
- // The RPC: explicit --rpc, else devnet; with --mainnet the user's configured mainnet endpoint.
70
- const url = rpcUrl ?? (mainnet ? resolveRpcUrl({ env }).url : DEVNET_RPC);
71
- // Never let a devnet-labelled signer talk to mainnet by accident: without --mainnet a non-devnet URL is refused.
72
- if (!mainnet && rpcNetwork(url) !== 'devnet')
73
- throw new Error('without --mainnet the signer RPC must be a devnet endpoint');
74
- return { caps, rpcUrl: url, ledgerPath, liveLedgerPath, linkPath, panicPath, fastWalletPath, noBrowser };
75
- }
76
- /**
77
- * task-1368: the signer's own `jupiter` bucket carries only its quote/build calls (a handful per ticket), so after a
78
- * 429 it pauses from this base (doubling per consecutive 429, capped as before) instead of the data layer's 30 s —
79
- * which was tuned for the terminal's enrichment flood and made every retry inside the 10 s budget impossible.
80
- * Retry-After from the server still wins when it is longer.
81
- */
82
- export const SIGNER_RATE_LIMIT_PAUSE_MS = 3_000;
83
- export function buildSignerService(a, log) {
84
- const dl = createDataLayer({ dbPath: ':memory:', rpcUrl: a.rpcUrl, rpcFallbackUrl: null, rateLimitPauseMs: SIGNER_RATE_LIMIT_PAUSE_MS });
85
- const rpc = new TradeRpc(dl.http, { url: a.rpcUrl, clock: dl.clock });
86
- const build = new JupiterSwapBuild(dl.http);
87
- const bridge = new WalletBridge(a.noBrowser ? { open: (url) => { log(`signer: open this page to approve: ${url}`); } } : {});
88
- const ledger = new CapLedger({ path: a.ledgerPath, clock: dl.clock });
89
- const liveLedger = new LiveLedger({ path: a.liveLedgerPath, clock: dl.clock });
90
- const killSwitch = new KillSwitch(a.panicPath);
91
- const linkStore = new WalletLinkStore(a.linkPath);
92
- const feed = new SolUsdFeed({ clock: dl.clock });
93
- // task-1363: the capped fast wallet is loaded ONLY against a devnet RPC (by classification of the URL the
94
- // signer will actually talk to). On mainnet there is no fast signer, so `fill` and fast-lane confirms refuse.
95
- const fastStore = new FastWalletStore(a.fastWalletPath);
96
- const fastSigner = rpc.network === 'devnet' ? fastStore.load() ?? undefined : undefined;
97
- if (fastSigner)
98
- log(`signer: fast wallet loaded (devnet) ${fastSigner.publicKey}`);
99
- const deps = { build, rpc, bridge, caps: a.caps, ledger, liveLedger, clock: dl.clock, solUsd: () => feed.samples(), killSwitch, probe: new DevnetProbeBuilder(rpc), fastSigner };
100
- const executor = new LiveExecutor(deps);
101
- return new SignerService({ executor, deps, linkStore, liveLedger, solUsdFeed: feed, clock: dl.clock, fastStore, log });
102
- }
103
- export async function main(argv) {
104
- const log = (l) => process.stderr.write(`${l}\n`);
105
- let args;
106
- try {
107
- args = parseSignerArgs(argv);
108
- }
109
- catch (e) {
110
- log(`signer: ${e instanceof Error ? e.message : String(e)}`);
111
- return 2;
112
- }
113
- const service = buildSignerService(args, log);
114
- const why = await serveSigner({ service, input: process.stdin, output: process.stdout, log });
115
- log(`signer: stopped (${why})`);
116
- return why === 'input closed' ? 0 : 1;
117
- }
118
- // Run when executed directly (never when imported by the client or the tests).
119
- if (process.argv[1] && import.meta.url === new URL(`file://${process.argv[1]}`).href) {
120
- main(process.argv.slice(2)).then((code) => { process.exitCode = code; process.stdin.destroy(); }, (e) => { process.stderr.write(`signer: fatal ${e instanceof Error ? e.message : String(e)}\n`); process.exitCode = 1; });
121
- }
@@ -1,85 +0,0 @@
1
- // dexterm T2 — the DEVNET PROBE transaction builder (task-1328). Jupiter has no devnet, so the way to
2
- // prove the real signing path end to end on devnet — keypress → Phantom sign → decode/verify →
3
- // re-simulate → submit → confirm — without any value at risk is a transaction dexterm builds itself:
4
- // the wrap-and-unwrap shape a Jupiter swap uses around its route, with NO route:
5
- //
6
- // AssociatedToken.CreateIdempotent(wallet's WSOL ATA) · System.Transfer(wallet → WSOL ATA, 0.001 SOL)
7
- // Token.SyncNative(WSOL ATA) · Memo("dexterm devnet probe") · Token.CloseAccount(WSOL ATA → wallet)
8
- //
9
- // The close returns the lamports (and the ATA rent) to the wallet in the same transaction, so the only
10
- // SOL that leaves is the network fee. The signer's policy for the probe kind refuses any other shape, and
11
- // the probe is refused outright unless the RPC endpoint classifies as devnet. No key, no network write:
12
- // this module only builds bytes; the executor simulates and the wallet signs.
13
- import { base58Decode } from "../../sources/pda.js";
14
- import { rpcNetwork } from "../rpc-exec.js";
15
- import { associatedTokenAddress, ASSOCIATED_TOKEN_PROGRAM, SYSTEM_PROGRAM, TOKEN_PROGRAM, MEMO_PROGRAM, WSOL_MINT } from "../tx-decode.js";
16
- export const PROBE_LAMPORTS = 1000000n; // 0.001 SOL, wrapped then unwrapped in the same tx
17
- export const PROBE_MEMO = 'dexterm devnet probe';
18
- function shortvec(n) {
19
- const out = [];
20
- do {
21
- let b = n & 0x7f;
22
- n >>= 7;
23
- if (n)
24
- b |= 0x80;
25
- out.push(b);
26
- } while (n);
27
- return Buffer.from(out);
28
- }
29
- /**
30
- * Compile a LEGACY message (no lookup tables needed) with the wallet as the single signer/fee payer.
31
- * Key order follows the runtime's rule: writable signers, then writable non-signers, then readonly
32
- * non-signers. Exported for the tests (they decode what this builds with the real decoder).
33
- */
34
- export function compileProbeMessage(user, blockhash, lamports = PROBE_LAMPORTS, memo = PROBE_MEMO) {
35
- const wsolAta = associatedTokenAddress(user, WSOL_MINT, TOKEN_PROGRAM);
36
- const transfer = Buffer.alloc(12);
37
- transfer.writeUInt32LE(2, 0);
38
- transfer.writeBigUInt64LE(lamports, 4);
39
- const ixs = [
40
- { program: ASSOCIATED_TOKEN_PROGRAM, accounts: [user, wsolAta, user, WSOL_MINT, SYSTEM_PROGRAM, TOKEN_PROGRAM], data: Buffer.from([1]) },
41
- { program: SYSTEM_PROGRAM, accounts: [user, wsolAta], data: transfer },
42
- { program: TOKEN_PROGRAM, accounts: [wsolAta], data: Buffer.from([17]) },
43
- { program: MEMO_PROGRAM, accounts: [], data: Buffer.from(memo, 'utf8') },
44
- { program: TOKEN_PROGRAM, accounts: [wsolAta, user, user], data: Buffer.from([9]) },
45
- ];
46
- const writable = [user, wsolAta];
47
- const readonly = [WSOL_MINT, SYSTEM_PROGRAM, TOKEN_PROGRAM, ASSOCIATED_TOKEN_PROGRAM, MEMO_PROGRAM];
48
- const keys = [...writable, ...readonly];
49
- const index = (k) => { const i = keys.indexOf(k); if (i < 0)
50
- throw new Error(`probe: unknown key ${k}`); return i; };
51
- const parts = [Buffer.from([1, 0, readonly.length]), shortvec(keys.length)];
52
- for (const k of keys)
53
- parts.push(Buffer.from(base58Decode(k)));
54
- parts.push(Buffer.from(base58Decode(blockhash)), shortvec(ixs.length));
55
- for (const ix of ixs) {
56
- const acc = ix.accounts.map(index);
57
- parts.push(Buffer.from([index(ix.program)]), shortvec(acc.length), Buffer.from(acc), shortvec(ix.data.length), ix.data);
58
- }
59
- return Buffer.concat(parts);
60
- }
61
- /** The unsigned wire transaction (one zero signature slot + the message), base64. */
62
- export function probeWire(message) {
63
- return Buffer.concat([shortvec(1), Buffer.alloc(64), message]).toString('base64');
64
- }
65
- export class DevnetProbeBuilder {
66
- rpc;
67
- constructor(rpc) { this.rpc = rpc; }
68
- /**
69
- * The probe (0.001 SOL, the fixed memo) or — task-1363 — a DEVNET FILL for the fast wallet: the same
70
- * wrap-and-unwrap shape sized to a plan's SOL leg, with a memo naming the plan leg. Devnet only either way.
71
- */
72
- async build(userPublicKey, opts = {}) {
73
- if (rpcNetwork(this.rpc.url, this.rpc.network ?? null) !== 'devnet')
74
- throw new Error('the probe builds only against a devnet RPC endpoint');
75
- if (base58Decode(userPublicKey).length !== 32)
76
- throw new Error('probe: bad wallet public key');
77
- const lamports = opts.lamports ?? PROBE_LAMPORTS;
78
- if (!(lamports > 0n))
79
- throw new Error('probe: lamports must be positive');
80
- const memo = (opts.memo ?? PROBE_MEMO).replace(/[^\x20-\x7e]/g, '?').slice(0, 96);
81
- const { blockhash } = await this.rpc.latestBlockhash();
82
- const message = compileProbeMessage(userPublicKey, blockhash, lamports, memo);
83
- return { txBase64: probeWire(message), lamports };
84
- }
85
- }
@@ -1,92 +0,0 @@
1
- // dexterm T2 — the SIGNER channel protocol (task-1328, SPEC §6.5 "separate process / hard-API module").
2
- //
3
- // The signer runs as its OWN PROCESS. The UI talks to it over the child's stdio pipes — a channel only
4
- // the spawning process holds — with every frame authenticated by an HMAC over a per-session secret the
5
- // parent hands the child as the FIRST line on stdin (never argv, never the environment, never a file).
6
- // Frames carry a strictly increasing sequence number per direction, so a replayed or reordered frame is
7
- // dropped. Anything that does not verify is ignored and counted; too many bad frames and the host exits
8
- // (fail closed: a confused signer stops signing).
9
- //
10
- // The API is DELIBERATELY small (SPEC §6.5): status · plan · probe · precheck · confirm · drop · panic.
11
- // There is no `sign(bytes)`, no `submit`, no `setCaps`. The UI never sends transaction bytes, a wallet
12
- // key, or a cap: the signer builds its own transaction from a Jupiter quote, reads the linked public key
13
- // from its own store, and applies the caps it was started with.
14
- import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto';
15
- export const SIGNER_PROTOCOL_VERSION = 1;
16
- /** A frame larger than this is dropped unread (a plan view is a few KB). */
17
- export const MAX_FRAME_BYTES = 64 * 1024;
18
- /** Bad frames tolerated before the host exits. */
19
- export const MAX_BAD_FRAMES = 8;
20
- export const SIGNER_METHODS = new Set(['status', 'plan', 'probe', 'precheck', 'confirm', 'drop', 'panic', 'fast', 'fill', 'quote']);
21
- export function newSecret() { return randomBytes(32); }
22
- export function mac(secret, seq, body) {
23
- return createHmac('sha256', secret).update(`${seq}\n${body}`).digest('hex');
24
- }
25
- /** Build one authenticated frame line (with the trailing newline). */
26
- export function encodeFrame(secret, seq, message) {
27
- const body = JSON.stringify(message);
28
- return `${JSON.stringify({ v: SIGNER_PROTOCOL_VERSION, seq, body, mac: mac(secret, seq, body) })}\n`;
29
- }
30
- /**
31
- * Verify and decode one frame line. `expectSeq` is the next sequence number this direction must carry;
32
- * anything else (replay, gap, reorder) is refused. Constant-time MAC comparison.
33
- */
34
- export function decodeFrame(secret, line, expectSeq) {
35
- if (line.length > MAX_FRAME_BYTES)
36
- return { ok: false, why: 'frame too large' };
37
- let f;
38
- try {
39
- f = JSON.parse(line);
40
- }
41
- catch {
42
- return { ok: false, why: 'not json' };
43
- }
44
- if (f === null || typeof f !== 'object' || Array.isArray(f))
45
- return { ok: false, why: 'not an object' };
46
- const fr = f;
47
- if (fr.v !== SIGNER_PROTOCOL_VERSION)
48
- return { ok: false, why: 'bad version' };
49
- if (typeof fr.seq !== 'number' || !Number.isInteger(fr.seq) || fr.seq !== expectSeq)
50
- return { ok: false, why: `bad seq ${String(fr.seq)} (expected ${expectSeq})` };
51
- if (typeof fr.body !== 'string' || typeof fr.mac !== 'string')
52
- return { ok: false, why: 'missing body/mac' };
53
- const want = Buffer.from(mac(secret, fr.seq, fr.body), 'hex');
54
- const got = Buffer.from(fr.mac, 'hex');
55
- if (want.length !== got.length || !timingSafeEqual(want, got))
56
- return { ok: false, why: 'bad mac' };
57
- let message;
58
- try {
59
- message = JSON.parse(fr.body);
60
- }
61
- catch {
62
- return { ok: false, why: 'body not json' };
63
- }
64
- if (message === null || typeof message !== 'object' || Array.isArray(message))
65
- return { ok: false, why: 'body not an object' };
66
- return { ok: true, seq: fr.seq, message: message };
67
- }
68
- export function isRequest(m) { return typeof m.method === 'string' && typeof m.id === 'number'; }
69
- export function isResponse(m) { return typeof m.id === 'number' && typeof m.ok === 'boolean'; }
70
- export function isEvent(m) { return typeof m.event === 'string'; }
71
- /** Parse the unauthenticated hello line the parent writes first. Null when malformed. */
72
- export function parseHello(line) {
73
- let h;
74
- try {
75
- h = JSON.parse(line);
76
- }
77
- catch {
78
- return null;
79
- }
80
- if (h === null || typeof h !== 'object')
81
- return null;
82
- const x = h;
83
- if (x.hello !== 'dexterm-signer' || x.v !== SIGNER_PROTOCOL_VERSION || typeof x.secret !== 'string')
84
- return null;
85
- const secret = Buffer.from(x.secret, 'base64');
86
- if (secret.length !== 32)
87
- return null;
88
- return { secret };
89
- }
90
- export function encodeHello(secret) {
91
- return `${JSON.stringify({ hello: 'dexterm-signer', v: SIGNER_PROTOCOL_VERSION, secret: secret.toString('base64') })}\n`;
92
- }