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
@@ -0,0 +1,397 @@
1
+ // `dexterm autotrade run --all --paper` (task-1529): every strategy of autotrade.json at the same time, on ONE data
2
+ // feed. PAPER ONLY.
3
+ //
4
+ // The host around @dexterm/autotrade runFleet (fleet.ts): one process, one runner lock under the fleet's run id, one
5
+ // live data layer (or one paced tape), one shared dossier cache, one machine-load check and the global caps of
6
+ // autotrade.json; each strategy gets its own run id, ledger (autotrade/runs/<runId>.jsonl), simulated book (its own
7
+ // bankroll), breaker, sessions and spend budget.
8
+ //
9
+ // Files it writes, every heartbeat (10 s) and on change (throttled to 1 s):
10
+ // autotrade/runner-status.json the runner rendezvous, as an AGGREGATE of every strategy (book summed, positions /
11
+ // candidates / sessions tagged with their strategy), under the fleet's run id: the
12
+ // Q screen's runner view, `dexterm autotrade stop|flatten`, the monitor's dead-man and
13
+ // the MCP autotrade_status read it unchanged
14
+ // autotrade/fleet-status.json each strategy's state, book, spend and stats, the global caps and their use today
15
+ // autotrade/runs/<id>.summary.json each strategy's run summary and the fleet's (for `dexterm autotrade audit`)
16
+ //
17
+ // Paper accounts (task-1538): autotrade.json `accounts` are shared simulated wallets; a strategy with `account` trades
18
+ // from that wallet's cash (and one strategy can run on several accounts). Printed as their own table at the end.
19
+ //
20
+ // Switches: the panic file, `dexterm autotrade stop | flatten` and the Q screen's `!` / `f` / `p` act on EVERY strategy
21
+ // (the fleet's RunnerSafety); `dexterm autotrade stop | flatten | pause | resume --strategy ID` and `start ID` act on one
22
+ // (fleet-control.ts). Nothing here arms a mandate, signs, holds a key or touches a wallet; `--live` and `mode: live`
23
+ // are refused (task-1571: dexterm places no live order).
24
+ import { appendFileSync } from 'node:fs';
25
+ import { join } from 'node:path';
26
+ import { dextermHome } from '../../../custom/src/index.js';
27
+ import { KillSwitch, createDataLayer, defaultDbPath, resolveRpcUrl } from '../../../data/src/index.js';
28
+ import { FleetGuard, HEARTBEAT_MS, accountTable, LiveSource, RUNNER_RENDEZVOUS_SCHEMA, RUN_SUMMARY_SCHEMA, RunnerSafety, acquireRunLock, bankrollUsd, claudeSessionFactory, clearControl, clearMemberControls, clearStaleControl, compareRows, compareTable, controlPath, fileLedger, fleetStatusPath, fleetTotals, loadFleetConfig, loadRunnerConfig, loadTape, memberStrategy, newRunId, prepareAccount, releaseRunLock, renderDossierRecord, runFleet, runFiles, runnerRendezvousPath, runnerSystemPrompt, sharedDossier, stubSession, writeJsonAtomic, writeRendezvous, } from '../../../autotrade/src/index.js';
29
+ import { parseArgs, resolveStrategyArg } from "./strategies.js";
30
+ import { larpVet } from "./run.js";
31
+ export const FLEET_RUN_USAGE = 'dexterm autotrade run --all --paper [--config FILE] [--replay TAPE [--ms-per-tick 2000]] [--sol-usd N] [--model M] [--max-minutes N] [--stub] [--raw] [--quiet]';
32
+ const BOOL = ['all', 'paper', 'live', 'stub', 'quiet', 'raw'];
33
+ const SOL_MINT = 'So11111111111111111111111111111111111111112';
34
+ function num(v, dflt) {
35
+ const n = typeof v === 'string' ? Number(v) : NaN;
36
+ return Number.isFinite(n) && n > 0 ? n : dflt;
37
+ }
38
+ const round2 = (v) => Math.round(v * 100) / 100;
39
+ /** The single-runner rendezvous shape, filled with every strategy together (the existing readers need no change). */
40
+ export function aggregateRendezvous(st, states, tails) {
41
+ const tot = fleetTotals(st);
42
+ const live = st.members.filter((m) => m.runId && m.state !== 'stopped' && m.state !== 'error' && m.state !== 'idle');
43
+ const runnerState = st.state === 'stopped' ? 'stopped' : st.state === 'halted' ? 'halted'
44
+ : live.length && live.every((m) => m.state === 'paused' || m.state === 'halted') ? 'paused' : 'running';
45
+ const each = (pick, m) => (states.get(m) ? pick(states.get(m)) : []);
46
+ const ids = st.members.map((m) => m.id);
47
+ return {
48
+ schema: RUNNER_RENDEZVOUS_SCHEMA, pid: st.pid, mode: 'paper', runId: st.fleetId, startedAt: st.startedAt, ledgerPath: st.ledgerPath,
49
+ state: runnerState, haltReason: st.haltReason ?? (st.global.blocked ? `fleet: ${st.global.blocked}` : st.global.load.paused ? 'fleet-load-high' : null),
50
+ strategy: { id: 'parallel', version: `${st.members.length} strategies`, hash: st.fleetId.slice(-4) },
51
+ book: { startUsd: tot.startUsd, equityUsd: tot.equityUsd, cashUsd: tot.cashUsd, realizedTodayUsd: round2(st.members.reduce((a, m) => a + (m.book?.realizedTodayUsd ?? 0), 0)) },
52
+ spend: {
53
+ todayUsd: st.global.today.modelUsd, dayCapUsd: st.global.caps.modelUsdPerDay, turnsToday: st.global.today.turns,
54
+ candidateSessionsToday: st.global.today.candidateSessions, positionSessionsToday: st.global.today.positionSessions, allowance: st.global.allowance,
55
+ },
56
+ candidates: ids.flatMap((m) => each((s) => s.candidates, m).map((c) => ({ ...c, strategy: m }))),
57
+ sessions: ids.flatMap((m) => each((s) => s.sessions, m).map((x) => ({ ...x, id: `${m}:${x.id}`, strategy: m }))),
58
+ positions: ids.flatMap((m) => each((s) => s.positions, m).map((p) => ({ ...p, strategy: m }))),
59
+ ledgerTail: tails.slice(-12).map((e, i) => ({ seq: i + 1, t: e.t, kind: e.kind, text: `[${e.member}] ${e.text}` })),
60
+ ledgerHead: '', events: st.members.reduce((a, m) => a + (states.get(m.id)?.events ?? 0), 0),
61
+ fleet: { fleetId: st.fleetId, strategies: st.members.length, statusPath: '' },
62
+ };
63
+ }
64
+ export async function fleetRunCmd(argv, io, over = {}) {
65
+ const { pos, opts } = parseArgs(argv, BOOL);
66
+ if (opts.live) {
67
+ io.stderr.write('dexterm autotrade run --all: live money is not available; parallel strategies run on paper only (--paper)\n');
68
+ return 2;
69
+ }
70
+ if (!opts.paper) {
71
+ io.stderr.write(`dexterm autotrade run --all: pass --paper (autotrade runs on paper only)\nusage: ${FLEET_RUN_USAGE}\n`);
72
+ return 2;
73
+ }
74
+ if (pos.length || typeof opts.strategy === 'string') {
75
+ io.stderr.write(`dexterm autotrade run --all runs every strategy listed in autotrade.json; name no strategy here\nusage: ${FLEET_RUN_USAGE}\n`);
76
+ return 2;
77
+ }
78
+ const home = dextermHome(io.env);
79
+ const kill = over.killSwitch ?? new KillSwitch();
80
+ const panic = kill.engaged();
81
+ if (panic) {
82
+ io.stderr.write(`dexterm autotrade run --all: the panic switch is engaged (${panic.reason}); nothing starts until you run \`dexterm wallet resume\` in a terminal\n`);
83
+ return 1;
84
+ }
85
+ const rc = loadRunnerConfig(home);
86
+ if (!rc.ok) {
87
+ io.stderr.write(`dexterm autotrade run --all: ${rc.path} is invalid:\n${rc.errors.map((e) => ` ${e}`).join('\n')}\n`);
88
+ return 1;
89
+ }
90
+ const runnerCfg = rc.config;
91
+ const fc = loadFleetConfig(home, typeof opts.config === 'string' ? opts.config : undefined);
92
+ if (!fc.ok) {
93
+ io.stderr.write(`dexterm autotrade run --all: ${fc.path}:\n${fc.errors.map((e) => ` ${e}`).join('\n')}\n`);
94
+ if ('missing' in fc)
95
+ io.stderr.write(' example:\n { "schema": "dexterm-autotrade/1",\n "strategies": [ { "id": "moon-a", "preset": "moonbag", "bankroll": { "usd": 500 } },\n { "id": "scalp-b", "preset": "scalp", "bankroll": { "sol": 1 } } ],\n "global": { "maxConcurrentSessions": 3, "modelUsdPerDay": 10 } }\n shared paper accounts (many strategies on one simulated wallet, one strategy on many):\n { "schema": "dexterm-autotrade/1",\n "accounts": [ { "id": "main", "bankroll": { "usd": 1000 } }, { "id": "yolo", "bankroll": { "sol": 1 } } ],\n "strategies": [ { "id": "moon", "preset": "moonbag", "account": "main" },\n { "id": "scalp", "preset": "scalp", "account": ["main", "yolo"] } ] }\n');
96
+ return 1;
97
+ }
98
+ const fleetCfg = fc.config;
99
+ const enabled = fleetCfg.strategies.filter((m) => m.enabled);
100
+ if (!enabled.length) {
101
+ io.stderr.write(`dexterm autotrade run --all: every strategy in ${fc.path} is "enabled": false; nothing to run\n`);
102
+ return 1;
103
+ }
104
+ const replay = typeof opts.replay === 'string' ? opts.replay : null;
105
+ const quiet = !!opts.quiet;
106
+ const say = (s) => { if (!quiet)
107
+ io.stdout.write(`${s}\n`); };
108
+ // The market first (a SOL bankroll needs the SOL price before the books are built).
109
+ let tape;
110
+ let data = null;
111
+ if (replay) {
112
+ try {
113
+ tape = loadTape(replay);
114
+ }
115
+ catch (e) {
116
+ io.stderr.write(`dexterm autotrade run --all: ${e.message}\n`);
117
+ return 1;
118
+ }
119
+ }
120
+ else {
121
+ const rpc = resolveRpcUrl({ env: io.env });
122
+ data = createDataLayer({ dbPath: io.env.DEXTERM_DB_PATH || defaultDbPath(io.env), rpcUrl: rpc.url, rpcFallbackUrl: rpc.fallbackUrl });
123
+ }
124
+ const closeData = () => { try {
125
+ data?.close();
126
+ }
127
+ catch { /* closing */ } };
128
+ let solUsd = typeof opts['sol-usd'] === 'string' ? num(opts['sol-usd'], NaN) : fleetCfg.solUsd ?? null;
129
+ if (Number.isNaN(solUsd)) {
130
+ io.stderr.write('dexterm autotrade run --all: --sol-usd needs a positive number\n');
131
+ closeData();
132
+ return 2;
133
+ }
134
+ if (solUsd === null && data && (fleetCfg.strategies.some((m) => m.bankroll && 'sol' in m.bankroll) || (fleetCfg.accounts ?? []).some((a) => 'sol' in a.bankroll))) {
135
+ try {
136
+ const p = (await data.dexscreener.tokens([SOL_MINT])).get(SOL_MINT)?.pair.priceUsd ?? null;
137
+ solUsd = p && p > 1 && p < 100_000 ? p : null;
138
+ }
139
+ catch {
140
+ solUsd = null;
141
+ }
142
+ }
143
+ // Every strategy resolves, or nothing starts (fail closed: a typo never leaves one strategy silently out).
144
+ const members = [];
145
+ const problems = [];
146
+ // Shared paper accounts (task-1538): each one's starting balance in USD (a SOL balance at the SOL price).
147
+ const accounts = [];
148
+ for (const a of fleetCfg.accounts ?? []) {
149
+ const b = bankrollUsd(a.bankroll, solUsd);
150
+ if (b.error || b.usd === null) {
151
+ problems.push(`paper account ${a.id}: ${b.error ?? 'no balance'}`);
152
+ continue;
153
+ }
154
+ accounts.push({ id: a.id, startUsd: b.usd, ...('sol' in a.bankroll ? { sol: a.bankroll.sol, solUsd: solUsd } : {}) });
155
+ }
156
+ const accountOf = new Map(accounts.map((a) => [a.id, a]));
157
+ for (const m of fleetCfg.strategies) {
158
+ const r = resolveStrategyArg(m.preset ?? m.file, io);
159
+ if (!r || !r.ok) {
160
+ problems.push(`${m.id}: ${r ? r.errors.map((e) => `${e.path || '/'} ${e.msg}`).join('; ') : 'no strategy'}`);
161
+ continue;
162
+ }
163
+ if (r.strategy.mode !== 'paper') {
164
+ problems.push(`${m.id}: ${r.strategy.id} is mode "${r.strategy.mode}"; the runner refuses anything but paper`);
165
+ continue;
166
+ }
167
+ const acct = m.account ? accountOf.get(m.account) : undefined;
168
+ if (m.account && !acct)
169
+ continue; // its account already failed above
170
+ const b = acct ? { usd: acct.startUsd } : bankrollUsd(m.bankroll, solUsd);
171
+ if ('error' in b && b.error) {
172
+ problems.push(`${m.id}: ${b.error}`);
173
+ continue;
174
+ }
175
+ const { strategy, basedOn } = memberStrategy(r.strategy, m, b.usd);
176
+ const sol = acct ? (acct.sol !== undefined ? { sol: acct.sol, solUsd: acct.solUsd } : {}) : m.bankroll && 'sol' in m.bankroll ? { sol: m.bankroll.sol, solUsd: solUsd } : {};
177
+ members.push({ config: m, strategy, basedOn, bankroll: { usd: strategy.bankroll.startUsd, ...sol } });
178
+ }
179
+ if (problems.length) {
180
+ io.stderr.write(`dexterm autotrade run --all: nothing started:\n${problems.map((p) => ` ${p}`).join('\n')}\n`);
181
+ closeData();
182
+ return 1;
183
+ }
184
+ const fleetId = newRunId('fleet');
185
+ const lock = acquireRunLock(home, fleetId);
186
+ if (!lock.ok) {
187
+ io.stderr.write(`dexterm autotrade run --all: another runner is active (pid ${lock.holder.pid}, run ${lock.holder.runId}); stop it first\n`);
188
+ closeData();
189
+ return 1;
190
+ }
191
+ if (lock.reclaimed)
192
+ say(`reclaimed a stale runner lock (pid ${lock.reclaimed.pid} is gone)`);
193
+ if (!clearStaleControl(home, fleetId)) {
194
+ io.stderr.write(`dexterm autotrade run --all: ${controlPath(home)} cannot be read; look at it and remove it, then start again\n`);
195
+ releaseRunLock(home, fleetId);
196
+ closeData();
197
+ return 1;
198
+ }
199
+ clearMemberControls(home, fleetId);
200
+ const { ledger: fleetLedger, files: fleetFiles } = fileLedger(home, fleetId);
201
+ const startedAt = Date.now();
202
+ const guard = new FleetGuard(fleetCfg.global, runnerCfg, { loadavg: over.loadavg });
203
+ const rawPath = opts.raw ? join(home, 'autotrade', 'runs', `${fleetId}.stream.jsonl`) : null;
204
+ const sessions = over.sessions ?? (opts.stub
205
+ ? () => stubSession()
206
+ : (m, gate, log, clock) => claudeSessionFactory({
207
+ bin: typeof opts['claude-bin'] === 'string' ? opts['claude-bin'] : (io.env.DEXTERM_CLAUDE_BIN || 'claude'),
208
+ account: () => prepareAccount(runnerCfg.account, io.env),
209
+ model: typeof opts.model === 'string' ? opts.model : undefined,
210
+ systemPrompt: (s) => runnerSystemPrompt(s, { live: !replay }),
211
+ gate, log,
212
+ onRaw: rawPath ? (id, line) => appendFileSync(rawPath, `${JSON.stringify({ strategy: m.config.id, sessionId: id, line })}\n`, { mode: 0o600 }) : undefined,
213
+ now: clock,
214
+ }));
215
+ let live = null;
216
+ let source;
217
+ let dossier;
218
+ let vet;
219
+ if (data) {
220
+ live = new LiveSource({ store: data.store, dexscreener: data.dexscreener }, { onLog: (l) => fleetLedger.add(Date.now(), 'source_error', { error: l.slice(0, 300) }) });
221
+ const ls = live;
222
+ source = { name: 'live keyless data layer (Store + DexScreener tokens/v1 fast lane), shared by every strategy', ticks: ls.ticks(), startT: startedAt, setFocus: (marks) => { ls.setFocus(marks); writeFocus(home, marks); } };
223
+ // One dossier record per coin per 30 s, whichever strategy asks; each strategy renders its own text.
224
+ const { McpTools } = await import('../../../mcp/src/index.js');
225
+ const mcp = new McpTools(data, () => ({ screen: 'autotrade-runner', actions: { mints: [], feeds: [], sortKeys: [] } }));
226
+ const shared = sharedDossier(async (mint) => {
227
+ try {
228
+ return await mcp.call('get_dossier', { mint, interval: '5m' });
229
+ }
230
+ catch (e) {
231
+ return { availability: { present: [], missing: [`dossier: ${e.message}`], knownUnavailable: [] } };
232
+ }
233
+ });
234
+ dossier = () => async (k, h, matched, b) => renderDossierRecord(await shared.get(k.mint), { mint: k.mint, symbol: k.symbol, matched }, k, h, b);
235
+ // A member's LARP gate (entry.safety.larp, the yolo preset's) on live data, as `autotrade run` has it.
236
+ vet = fleetLarpVet((mint) => mcp.call('larp_check', { mint }));
237
+ }
238
+ // Heartbeat: the aggregate rendezvous, the fleet status, every summary.
239
+ const states = new Map();
240
+ const runOf = new Map();
241
+ const tails = [];
242
+ let lastStatus = null;
243
+ let lastWrite = 0;
244
+ let lastBeatOk = startedAt;
245
+ let beatFailing = false;
246
+ const writeAll = (force = false) => {
247
+ const st = lastStatus;
248
+ if (!st)
249
+ return;
250
+ const now = Date.now();
251
+ if (!force && now - lastWrite < 1000)
252
+ return;
253
+ lastWrite = now;
254
+ try {
255
+ const agg = aggregateRendezvous(st, states, tails);
256
+ agg.fleet.statusPath = fleetStatusPath(home);
257
+ writeRendezvous(home, { ...agg, heartbeatAt: now });
258
+ writeJsonAtomic(fleetStatusPath(home), { ...st, heartbeatAt: now });
259
+ writeJsonAtomic(fleetFiles.summary, { schema: RUN_SUMMARY_SCHEMA, runId: fleetId, strategy: { id: 'parallel', version: `${st.members.length} strategies`, hash: '' }, startedAt, updatedAt: now, state: st.state, book: agg.book, spend: agg.spend, events: fleetLedger.events.length, ledgerHead: fleetLedger.head(), source: st.source });
260
+ for (const m of st.members) {
261
+ const s = states.get(m.id);
262
+ const runId = runOf.get(m.id);
263
+ if (!s || !runId)
264
+ continue;
265
+ writeJsonAtomic(runFiles(home, runId).summary, { schema: RUN_SUMMARY_SCHEMA, runId, strategy: s.strategy, startedAt: m.startedAt, updatedAt: now, state: s.state, book: s.book, spend: s.spend, events: s.events, ledgerHead: s.ledgerHead, source: st.source, fleetId });
266
+ }
267
+ lastBeatOk = now;
268
+ if (beatFailing) {
269
+ beatFailing = false;
270
+ fleetLedger.add(now, 'heartbeat_ok', {});
271
+ }
272
+ }
273
+ catch (e) {
274
+ if (!beatFailing) {
275
+ beatFailing = true;
276
+ fleetLedger.add(now, 'heartbeat_failed', { error: e.message.slice(0, 200) });
277
+ }
278
+ }
279
+ };
280
+ const beat = setInterval(() => writeAll(true), HEARTBEAT_MS);
281
+ const maxMin = num(opts['max-minutes'], 0);
282
+ const stopAt = maxMin ? startedAt + maxMin * 60_000 : Infinity;
283
+ let stopping = false;
284
+ const stop = (why) => { if (stopping)
285
+ return; stopping = true; fleetLedger.add(Date.now(), 'stop_requested', { why }); say(`stopping every strategy (${why}): open sessions close, each paper book is kept in its ledger`); live?.stop(); };
286
+ const onSig = () => stop('signal');
287
+ process.once('SIGINT', onSig);
288
+ process.once('SIGTERM', onSig);
289
+ const safety = new RunnerSafety({ home, runId: fleetId, killSwitch: kill, heartbeatAgeMs: () => (beatFailing ? Date.now() - lastBeatOk : 0) });
290
+ say(`dexterm autotrade run --all · PAPER · ${members.length} strategies at once (${enabled.length} enabled) · ${replay ? `replay ${replay}` : 'live keyless data, one feed for all'} · sessions ${opts.stub ? 'stub' : `claude (${runnerCfg.account.kind}${typeof opts.model === 'string' ? `, ${opts.model}` : ''})`}`);
291
+ if (accounts.length)
292
+ say(`paper accounts: ${accounts.map((a) => `${a.id} $${a.startUsd}${a.sol !== undefined ? ` (${a.sol} SOL)` : ''} ← ${members.filter((m) => m.config.account === a.id).map((m) => m.config.id).join(', ') || 'no strategy'}`).join(' · ')}`);
293
+ // The single run's HIGH RISK line (task-1532), for every yolo-like member of the fleet (paper only here).
294
+ const risky = members.filter((m) => m.strategy.highRisk).map((m) => m.config.id);
295
+ if (risky.length)
296
+ say(`⚠ HIGH RISK strateg${risky.length === 1 ? 'y' : 'ies'} (${risky.join(', ')}): one position at a time, early entries, most of them lose. Experimental; can lose all funds; not financial advice.`);
297
+ say(`fleet ${fleetId} · global caps: ${guard.caps.maxConcurrentSessions} sessions at once, $${guard.caps.modelUsdPerDay}/day model spend, ${guard.caps.candidateSessionsPerDay} candidate sessions/day · ledger ${fleetFiles.ledger}`);
298
+ let code = 0;
299
+ try {
300
+ const res = await runFleet({
301
+ fleetId, home, members, tape, source, runner: runnerCfg, guard, fleetLedger, fleetLedgerPath: fleetFiles.ledger, ...(accounts.length ? { accounts } : {}),
302
+ pacing: replay ? { mode: 'paced', msPerTick: num(opts['ms-per-tick'], 2000) } : { mode: 'live' },
303
+ sessions, dossier, vet, newRunId: (id) => newRunId(id), verbose: true, onLine: say,
304
+ globalSafety: () => {
305
+ if (Date.now() >= stopAt)
306
+ stop('max-minutes');
307
+ const v = safety.step();
308
+ return stopping && !v.halt ? { ...v, halt: 'runner-stopped', detail: 'a signal or --max-minutes', endWhenFlat: true } : v;
309
+ },
310
+ hooks: {
311
+ onMemberEvent: (m, runId, e) => {
312
+ runOf.set(m, runId);
313
+ if (['candidate', 'fill', 'trade_closed', 'halt', 'refused', 'session_start', 'session_end', 'entries_paused', 'entries_resumed', 'stuck'].includes(e.kind)) {
314
+ tails.push({ t: e.t, kind: e.kind, member: m, text: tailLine(e) });
315
+ if (tails.length > 48)
316
+ tails.splice(0, tails.length - 24);
317
+ }
318
+ over.hooks?.onMemberEvent?.(m, runId, e);
319
+ },
320
+ onMemberState: (m, runId, s) => { runOf.set(m, runId); states.set(m, s); over.hooks?.onMemberState?.(m, runId, s); },
321
+ onFleetState: (st) => { lastStatus = st; writeAll(st.state === 'stopped'); over.hooks?.onFleetState?.(st); },
322
+ },
323
+ });
324
+ const rows = compareRows(res.status);
325
+ say('');
326
+ for (const l of compareTable(rows))
327
+ say(l);
328
+ const acctLines = accountTable(res.status);
329
+ if (acctLines.length) {
330
+ say('');
331
+ for (const l of acctLines)
332
+ say(l);
333
+ }
334
+ const tot = fleetTotals(res.status);
335
+ say(`done · ${members.length} strategies · together ${tot.pnlUsd >= 0 ? '+' : '-'}$${Math.abs(tot.pnlUsd).toFixed(2)} on $${tot.startUsd.toFixed(2)} (paper) · $${tot.spendUsd.toFixed(4)} model spend · fleet ledger head ${fleetLedger.head()}`);
336
+ }
337
+ catch (e) {
338
+ io.stderr.write(`dexterm autotrade run --all: ${e.message}\n`);
339
+ code = 1;
340
+ }
341
+ finally {
342
+ clearInterval(beat);
343
+ process.removeListener('SIGINT', onSig);
344
+ process.removeListener('SIGTERM', onSig);
345
+ if (lastStatus && lastStatus.state !== 'stopped')
346
+ lastStatus = { ...lastStatus, state: 'stopped' };
347
+ writeAll(true);
348
+ writeFocus(home, []);
349
+ live?.stop();
350
+ closeData();
351
+ clearControl(home, fleetId);
352
+ clearMemberControls(home, null);
353
+ releaseRunLock(home, fleetId);
354
+ }
355
+ return code;
356
+ }
357
+ /** One short line for the aggregate ledger tail (no message text). */
358
+ function tailLine(e) {
359
+ const v = (k) => (e[k] === undefined || e[k] === null ? '' : String(e[k]).slice(0, 40));
360
+ switch (e.kind) {
361
+ case 'candidate': return `candidate ${v('symbol')}`;
362
+ case 'fill': return `${v('side')} $${Number(e.usd ?? 0).toFixed(2)} ${v('reason')}`;
363
+ case 'trade_closed': {
364
+ const t = e.trade;
365
+ return `closed ${t?.symbol ?? ''} ${(t?.pnlUsd ?? 0) >= 0 ? '+' : '-'}$${Math.abs(t?.pnlUsd ?? 0).toFixed(2)} by ${t?.exitReason ?? ''}`;
366
+ }
367
+ case 'refused': return `refused ${v('rule')}`;
368
+ default: return [v('reason'), v('sessionId'), v('rule')].filter(Boolean).join(' ') || String(e.kind);
369
+ }
370
+ }
371
+ /** Candidate + held coins of every strategy for the recorder's tick lane (task-1504 focus file); best effort. */
372
+ function writeFocus(home, marks) {
373
+ void import('../../../recorder/src/index.js').then((m) => {
374
+ try {
375
+ m.writeFocusFile(m.focusFilePath(home), marks.map((x) => ({ mint: x.mint, role: x.role, until: Date.now() + 30 * 60_000 })), Date.now());
376
+ }
377
+ catch { /* the recorder is optional */ }
378
+ }).catch(() => { });
379
+ }
380
+ /**
381
+ * The fleet's LARP gate per member (entry.safety.larp, e.g. the yolo preset), on live data only, as `autotrade run` has
382
+ * it: without it a gated strategy would open candidates unchecked under `run --all`. One larp_check per coin for the
383
+ * whole fleet; each member applies its own maxScore / unknown, and a check that throws is not kept (the next asks again).
384
+ */
385
+ export function fleetLarpVet(check) {
386
+ const byMint = new Map();
387
+ const shared = (mint) => {
388
+ let p = byMint.get(mint);
389
+ if (!p) {
390
+ p = check(mint);
391
+ byMint.set(mint, p);
392
+ p.catch(() => byMint.delete(mint));
393
+ }
394
+ return p;
395
+ };
396
+ return (m) => (m.strategy.entry.safety.larp ? larpVet(m.strategy.entry.safety.larp, shared) : undefined);
397
+ }
@@ -0,0 +1,79 @@
1
+ // `dexterm autotrade requests list|run|dismiss` (task-1530): the user's side of the MCP `backtest_request` tool. An
2
+ // agent can only FILE a request ($DEXTERM_HOME/autotrade/requests/<id>.json); nothing runs until the user runs it here.
3
+ // `run` is the ordinary `dexterm autotrade backtest <id> --days N` on the recorded history (paper, no network, no
4
+ // model), and its one-line result is written back so the agent reads it with `backtest_requests`.
5
+ import { BacktestRequests, isRequestId } from '../../../mcp/src/index.js';
6
+ import { dextermHomeDir } from '../../../data/src/trade/ledger/index.js';
7
+ import { backtestCmd } from "./backtest.js";
8
+ const USAGE = 'dexterm autotrade requests [list [--all] [--json] | run <br_id> | dismiss <br_id>]';
9
+ const when = (t) => new Date(t).toISOString().slice(0, 16).replace('T', ' ');
10
+ function line(r) {
11
+ const head = `${r.requestId} ${r.status.padEnd(9)} ${when(r.createdAt)} ${r.id}${r.version ? `@${r.version}` : ''} · ${r.days}d${r.everyCandidate ? ' · every candidate' : ''} · by ${r.actor}`;
12
+ return `${head}\n why: ${r.why}${r.result ? `\n result: ${r.result}` : ''}`;
13
+ }
14
+ export async function requestsCmd(argv, io) {
15
+ const files = new BacktestRequests(dextermHomeDir(io.env));
16
+ const sub = argv[0] ?? 'list';
17
+ if (sub === 'list') {
18
+ const all = argv.includes('--all');
19
+ const rows = files.list(all ? {} : { status: 'pending' });
20
+ if (argv.includes('--json')) {
21
+ io.stdout.write(`${JSON.stringify({ requests: rows })}\n`);
22
+ return 0;
23
+ }
24
+ if (!rows.length) {
25
+ io.stdout.write(all ? 'no backtest requests\n' : 'no pending backtest requests (--all shows the resolved ones)\n');
26
+ return 0;
27
+ }
28
+ for (const r of rows)
29
+ io.stdout.write(`${line(r)}\n`);
30
+ io.stdout.write('\nAn agent filed these; nothing ran. `dexterm autotrade requests run <id>` runs one (paper, recorded data); `dismiss <id>` drops it.\n');
31
+ return 0;
32
+ }
33
+ if (sub !== 'run' && sub !== 'dismiss') {
34
+ io.stderr.write(`dexterm autotrade requests: unknown action ${JSON.stringify(sub)}\n ${USAGE}\n`);
35
+ return 2;
36
+ }
37
+ const id = argv[1];
38
+ if (!isRequestId(id)) {
39
+ io.stderr.write(`dexterm autotrade requests ${sub}: pass a request id (br_…, from \`dexterm autotrade requests\`)\n`);
40
+ return 2;
41
+ }
42
+ const r = files.get(id);
43
+ if (!r) {
44
+ io.stderr.write(`dexterm autotrade requests: no request ${id}\n`);
45
+ return 2;
46
+ }
47
+ if (r.status !== 'pending') {
48
+ io.stderr.write(`dexterm autotrade requests: ${id} is already ${r.status}\n`);
49
+ return 2;
50
+ }
51
+ if (sub === 'dismiss') {
52
+ files.resolve(id, 'dismissed', 'dismissed by the user');
53
+ io.stdout.write(`${id} dismissed\n`);
54
+ return 0;
55
+ }
56
+ // run: the ordinary backtest, its JSON captured for the one-line result, the human report shown after
57
+ let out = '';
58
+ let err = '';
59
+ const args = [r.id, '--days', String(r.days), ...(r.everyCandidate ? ['--every-candidate'] : []), '--json'];
60
+ const rc = await backtestCmd(args, { ...io, stdout: { write: (s) => { out += s; return true; } }, stderr: { write: (s) => { err += s; return true; } } });
61
+ if (rc !== 0) {
62
+ const why = err.trim().split('\n')[0] || `the backtest exited ${rc}`;
63
+ files.resolve(id, 'failed', why);
64
+ io.stderr.write(`${id} failed: ${why}\n`);
65
+ return rc;
66
+ }
67
+ let result;
68
+ try {
69
+ const rep = JSON.parse(out);
70
+ const wr = rep.winRate ? `${rep.winRate.value}% (95% ${rep.winRate.lo}–${rep.winRate.hi}%)` : '—';
71
+ result = `paper backtest ${r.days}d: ${rep.trades ?? 0} trades · win ${wr} · net $${(rep.netUsd ?? 0).toFixed(2)} (${rep.netPct ?? 0}%) · max drawdown ${rep.maxDrawdownPct ?? 0}%`;
72
+ }
73
+ catch {
74
+ result = 'the backtest ran but its report was not readable JSON';
75
+ }
76
+ files.resolve(id, 'done', result);
77
+ io.stdout.write(`${id} done: ${result}\n (the agent reads this with backtest_requests; the full report: \`dexterm autotrade backtest ${r.id} --days ${r.days}\`)\n`);
78
+ return 0;
79
+ }