dexterm-cli 0.1.6 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (395) hide show
  1. package/dist/packages/agents/src/schema.js +22 -1
  2. package/dist/packages/agents/src/spectator.js +3 -1
  3. package/dist/packages/agents/src/story.js +11 -2
  4. package/dist/packages/agents/src/tiers.js +36 -2
  5. package/dist/packages/agents/src/tools.js +35 -2
  6. package/dist/packages/autotrade/assets/exit-profile.schema.json +492 -0
  7. package/dist/packages/autotrade/assets/limits.schema.json +569 -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/examples/executor/README.md +70 -0
  20. package/dist/packages/autotrade/examples/executor/jsonl-tail-executor.mjs +57 -0
  21. package/dist/packages/autotrade/examples/executor/kit.mjs +144 -0
  22. package/dist/packages/autotrade/examples/executor/signal-cmd-executor.mjs +25 -0
  23. package/dist/packages/autotrade/examples/executor/telegram-bot-recipe.md +47 -0
  24. package/dist/packages/autotrade/examples/executor/webhook-executor.mjs +47 -0
  25. package/dist/packages/autotrade/src/account.js +74 -0
  26. package/dist/packages/autotrade/src/backtest.js +358 -0
  27. package/dist/packages/autotrade/src/basis-text.js +32 -0
  28. package/dist/packages/autotrade/src/chat/approvals.js +484 -0
  29. package/dist/packages/autotrade/src/chat/audit.js +140 -0
  30. package/dist/packages/autotrade/src/chat/config.js +95 -0
  31. package/dist/packages/autotrade/src/chat/connector.js +24 -0
  32. package/dist/packages/autotrade/src/chat/control.js +104 -0
  33. package/dist/packages/autotrade/src/chat/fake.js +100 -0
  34. package/dist/packages/autotrade/src/chat/format.js +71 -0
  35. package/dist/packages/autotrade/src/chat/hub.js +187 -0
  36. package/dist/packages/autotrade/src/chat/index.js +18 -0
  37. package/dist/packages/autotrade/src/chat/notify.js +302 -0
  38. package/dist/packages/autotrade/src/chat/pairing.js +46 -0
  39. package/dist/packages/autotrade/src/chat/redact.js +48 -0
  40. package/dist/packages/autotrade/src/chat/secrets.js +106 -0
  41. package/dist/packages/autotrade/src/chat/service.js +251 -0
  42. package/dist/packages/autotrade/src/chat/telegram.js +290 -0
  43. package/dist/packages/autotrade/src/desk-executor.js +188 -0
  44. package/dist/packages/autotrade/src/engine.js +401 -0
  45. package/dist/packages/autotrade/src/execution-port.js +97 -0
  46. package/dist/packages/autotrade/src/executor-health.js +217 -0
  47. package/dist/packages/autotrade/src/fleet-config.js +169 -0
  48. package/dist/packages/autotrade/src/fleet-control.js +276 -0
  49. package/dist/packages/autotrade/src/fleet.js +642 -0
  50. package/dist/packages/autotrade/src/forward.js +355 -0
  51. package/dist/packages/autotrade/src/index.js +72 -0
  52. package/dist/packages/autotrade/src/journey.js +477 -0
  53. package/dist/packages/autotrade/src/ledger.js +108 -0
  54. package/dist/packages/autotrade/src/limits.js +682 -0
  55. package/dist/packages/autotrade/src/live-source.js +182 -0
  56. package/dist/packages/autotrade/src/monitor-daemon.js +715 -0
  57. package/dist/packages/autotrade/src/monitor.js +190 -0
  58. package/dist/packages/autotrade/src/ollama-sessions.js +137 -0
  59. package/dist/packages/autotrade/src/outbox.js +394 -0
  60. package/dist/packages/autotrade/src/paper-accounts.js +72 -0
  61. package/dist/packages/autotrade/src/paper-limits.js +87 -0
  62. package/dist/packages/autotrade/src/real-mode.js +688 -0
  63. package/dist/packages/autotrade/src/receipts.js +330 -0
  64. package/dist/packages/autotrade/src/replay.js +198 -0
  65. package/dist/packages/autotrade/src/report.js +168 -0
  66. package/dist/packages/autotrade/src/runner-config.js +99 -0
  67. package/dist/packages/autotrade/src/runner.js +923 -0
  68. package/dist/packages/autotrade/src/safety.js +243 -0
  69. package/dist/packages/autotrade/src/service-guard.js +125 -0
  70. package/dist/packages/autotrade/src/service-install.js +213 -0
  71. package/dist/packages/autotrade/src/service-recover.js +232 -0
  72. package/dist/packages/autotrade/src/service.js +289 -0
  73. package/dist/packages/autotrade/src/session.js +269 -0
  74. package/dist/packages/autotrade/src/sessions.js +503 -0
  75. package/dist/packages/autotrade/src/signal-channels.js +312 -0
  76. package/dist/packages/autotrade/src/signal.js +196 -0
  77. package/dist/packages/autotrade/src/store.js +250 -0
  78. package/dist/packages/autotrade/src/strategy.js +258 -0
  79. package/dist/packages/autotrade/src/trade-ledger.js +241 -0
  80. package/dist/packages/autotrade/src/yolo.js +140 -0
  81. package/dist/packages/cli/assets/claude/analyst-system.md +4 -4
  82. package/dist/packages/cli/assets/claude/plugin/skills/token-dossier/SKILL.md +1 -1
  83. package/dist/packages/cli/src/ai-cmd.js +412 -0
  84. package/dist/packages/cli/src/analyst/backend.js +83 -15
  85. package/dist/packages/cli/src/analyst/codex.js +15 -9
  86. package/dist/packages/cli/src/analyst/ollama.js +263 -0
  87. package/dist/packages/cli/src/analyst/session.js +5 -2
  88. package/dist/packages/cli/src/app-help-gen.js +56 -8
  89. package/dist/packages/cli/src/autotrade-cmd/audit.js +74 -0
  90. package/dist/packages/cli/src/autotrade-cmd/backtest.js +216 -0
  91. package/dist/packages/cli/src/autotrade-cmd/executor.js +91 -0
  92. package/dist/packages/cli/src/autotrade-cmd/flatten.js +64 -0
  93. package/dist/packages/cli/src/autotrade-cmd/fleet.js +401 -0
  94. package/dist/packages/cli/src/autotrade-cmd/forward.js +283 -0
  95. package/dist/packages/cli/src/autotrade-cmd/journey.js +208 -0
  96. package/dist/packages/cli/src/autotrade-cmd/limits.js +393 -0
  97. package/dist/packages/cli/src/autotrade-cmd/receipt.js +63 -0
  98. package/dist/packages/cli/src/autotrade-cmd/report.js +79 -0
  99. package/dist/packages/cli/src/autotrade-cmd/requests.js +79 -0
  100. package/dist/packages/cli/src/autotrade-cmd/run.js +657 -0
  101. package/dist/packages/cli/src/autotrade-cmd/service.js +873 -0
  102. package/dist/packages/cli/src/autotrade-cmd/signal.js +824 -0
  103. package/dist/packages/cli/src/autotrade-cmd/stop.js +76 -0
  104. package/dist/packages/cli/src/autotrade-cmd/strategies.js +198 -0
  105. package/dist/packages/cli/src/autotrade-cmd/strategy-control.js +174 -0
  106. package/dist/packages/cli/src/autotrade-cmd/telegram-host.js +101 -0
  107. package/dist/packages/cli/src/autotrade-cmd.js +214 -0
  108. package/dist/packages/cli/src/display.js +156 -17
  109. package/dist/packages/cli/src/doctor.js +62 -3
  110. package/dist/packages/cli/src/export.js +10 -2
  111. package/dist/packages/cli/src/index.js +1 -1
  112. package/dist/packages/cli/src/ledger-cmd.js +290 -0
  113. package/dist/packages/cli/src/live/chart-fills.js +46 -0
  114. package/dist/packages/cli/src/live/index.js +23 -89
  115. package/dist/packages/cli/src/live/screens/token-live.js +9 -6
  116. package/dist/packages/cli/src/live/trade.js +12 -457
  117. package/dist/packages/cli/src/live/watchlist.js +1 -1
  118. package/dist/packages/cli/src/main.js +147 -190
  119. package/dist/packages/cli/src/mcp-cmd.js +7 -1
  120. package/dist/packages/cli/src/plan-cmd.js +1 -1
  121. package/dist/packages/cli/src/pnl-app.js +31 -21
  122. package/dist/packages/cli/src/pnl-card.js +162 -21
  123. package/dist/packages/cli/src/popup.js +22 -6
  124. package/dist/packages/cli/src/record-cmd.js +141 -20
  125. package/dist/packages/cli/src/screens/agent-hud.js +34 -2
  126. package/dist/packages/cli/src/screens/analyst-session.js +7 -4
  127. package/dist/packages/cli/src/screens/analyst.js +3 -2
  128. package/dist/packages/cli/src/screens/autotrade-journey.js +134 -0
  129. package/dist/packages/cli/src/screens/autotrade-keys.js +182 -0
  130. package/dist/packages/cli/src/screens/autotrade-proposals.js +123 -0
  131. package/dist/packages/cli/src/screens/autotrade-screen.js +776 -0
  132. package/dist/packages/cli/src/screens/autotrade-ui.js +650 -0
  133. package/dist/packages/cli/src/screens/autotrade-worker.js +91 -0
  134. package/dist/packages/cli/src/screens/brain.js +37 -11
  135. package/dist/packages/cli/src/screens/overlay.js +5 -2
  136. package/dist/packages/cli/src/screens/plans.js +5 -17
  137. package/dist/packages/cli/src/screens/pnl-chip.js +9 -8
  138. package/dist/packages/cli/src/screens/positions.js +6 -28
  139. package/dist/packages/cli/src/screens/ticket.js +38 -205
  140. package/dist/packages/cli/src/screens/token.js +3 -3
  141. package/dist/packages/cli/src/state.js +25 -19
  142. package/dist/packages/cli/src/telegram-cmd.js +454 -0
  143. package/dist/packages/cli/src/trade.js +3 -128
  144. package/dist/packages/cli/src/version.js +1 -1
  145. package/dist/packages/cli/src/wallet-cmd.js +39 -340
  146. package/dist/packages/cli/src/wallet-command.js +8 -11
  147. package/dist/packages/cli/src/widgets.js +0 -12
  148. package/dist/packages/custom/src/config.js +20 -2
  149. package/dist/packages/custom/src/schema.js +35 -10
  150. package/dist/packages/custom/src/workspace.js +3 -3
  151. package/dist/packages/data/src/basis.js +191 -0
  152. package/dist/packages/data/src/detail.js +53 -2
  153. package/dist/packages/data/src/index.js +0 -14
  154. package/dist/packages/data/src/store.js +14 -5
  155. package/dist/packages/data/src/trade/agent/paper-desk.js +228 -16
  156. package/dist/packages/data/src/trade/agent/rendezvous.js +3 -2
  157. package/dist/packages/data/src/trade/bridge.js +4 -102
  158. package/dist/packages/data/src/trade/ledger/export.js +101 -0
  159. package/dist/packages/data/src/trade/ledger/file.js +135 -0
  160. package/dist/packages/data/src/trade/ledger/fold.js +191 -0
  161. package/dist/packages/data/src/trade/ledger/index.js +9 -0
  162. package/dist/packages/data/src/trade/ledger/schema.js +83 -0
  163. package/dist/packages/data/src/trade/ledger/sources.js +307 -0
  164. package/dist/packages/data/src/trade/ledger/stats.js +123 -0
  165. package/dist/packages/data/src/trade/ledger/tags.js +116 -0
  166. package/dist/packages/data/src/trade/ledger/view.js +51 -0
  167. package/dist/packages/data/src/trade/plans/index.js +0 -1
  168. package/dist/packages/data/src/trade/plans/service.js +3 -27
  169. package/dist/packages/mcp/assets/kb/app-help/autotrade-chat.md +48 -0
  170. package/dist/packages/mcp/assets/kb/app-help/autotrade-executor-kit.md +44 -0
  171. package/dist/packages/mcp/assets/kb/app-help/autotrade-journey.md +46 -0
  172. package/dist/packages/mcp/assets/kb/app-help/autotrade-limits.md +48 -0
  173. package/dist/packages/mcp/assets/kb/app-help/autotrade-parallel.md +42 -0
  174. package/dist/packages/mcp/assets/kb/app-help/autotrade-real-signal.md +45 -0
  175. package/dist/packages/mcp/assets/kb/app-help/autotrade-runner.md +35 -0
  176. package/dist/packages/mcp/assets/kb/app-help/autotrade-stop.md +37 -0
  177. package/dist/packages/mcp/assets/kb/app-help/autotrade-strategies.md +35 -0
  178. package/dist/packages/mcp/assets/kb/app-help/autotrade-telegram.md +40 -0
  179. package/dist/packages/mcp/assets/kb/app-help/chart-trade-markers.md +42 -0
  180. package/dist/packages/mcp/assets/kb/app-help/link-a-wallet.md +4 -10
  181. package/dist/packages/mcp/assets/kb/app-help/live-trading.md +38 -0
  182. package/dist/packages/mcp/assets/kb/app-help/live-yolo.md +34 -0
  183. package/dist/packages/mcp/assets/kb/app-help/order-plans.md +1 -1
  184. package/dist/packages/mcp/assets/kb/app-help/price-or-marketcap.md +5 -2
  185. package/dist/packages/mcp/assets/kb/app-help/screen-analyst.md +3 -0
  186. package/dist/packages/mcp/assets/kb/app-help/screen-autotrade.md +229 -0
  187. package/dist/packages/mcp/assets/kb/app-help/screen-kol.md +3 -0
  188. package/dist/packages/mcp/assets/kb/app-help/screen-newpairs.md +3 -0
  189. package/dist/packages/mcp/assets/kb/app-help/screen-positions.md +3 -0
  190. package/dist/packages/mcp/assets/kb/app-help/screen-screener.md +3 -0
  191. package/dist/packages/mcp/assets/kb/app-help/screen-token.md +3 -0
  192. package/dist/packages/mcp/assets/kb/app-help/screen-trending.md +3 -0
  193. package/dist/packages/mcp/assets/kb/app-help/screen-watchlist.md +3 -0
  194. package/dist/packages/mcp/assets/kb/app-help/standing-mandates.md +1 -1
  195. package/dist/packages/mcp/assets/kb/app-help/trade-ledger.md +54 -0
  196. package/dist/packages/mcp/assets/kb/app-help/use-local-model.md +38 -0
  197. package/dist/packages/mcp/assets/kb/docs/docs-agents-agent-paper-trading.md +4 -1
  198. package/dist/packages/mcp/assets/kb/docs/docs-agents-reading-your-trade-ledger.md +31 -0
  199. package/dist/packages/mcp/assets/kb/docs/docs-agents-untrusted-by-default.md +1 -1
  200. package/dist/packages/mcp/assets/kb/docs/docs-analyst-if-claude-is-missing.md +1 -1
  201. package/dist/packages/mcp/assets/kb/docs/docs-analyst-use-a-local-model-instead.md +27 -0
  202. package/dist/packages/mcp/assets/kb/docs/docs-analyst-what-it-sees.md +2 -0
  203. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-backtests-and-their-limits.md +56 -0
  204. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-change-a-strategy-by-chat.md +51 -0
  205. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-checking-the-record-of-a-run.md +28 -0
  206. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-comparing-them.md +41 -0
  207. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-exits-and-wakes.md +76 -0
  208. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-how-a-stop-reaches-the-runner.md +32 -0
  209. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-on-the-q-screen.md +38 -0
  210. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-one-strategy-or-all-of-them.md +35 -0
  211. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-paper-accounts.md +50 -0
  212. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-presets.md +37 -0
  213. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-running-it-all-day.md +31 -0
  214. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-sessions-and-their-limits.md +31 -0
  215. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-several-strategies-at-once.md +33 -0
  216. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-stopping-it.md +37 -0
  217. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-strategies-and-presets.md +34 -0
  218. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-the-always-on-service.md +57 -0
  219. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-the-autotrade-json-file.md +48 -0
  220. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-the-heartbeat.md +27 -0
  221. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-the-run-file-and-the-heartbeat.md +34 -0
  222. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-the-runner-and-candidate-sessions.md +45 -0
  223. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-what-each-session-shows-first.md +31 -0
  224. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-what-it-costs-claude-usage-per-session.md +58 -0
  225. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-what-it-is-paper-self-directed.md +50 -0
  226. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-what-it-will-not-do.md +31 -0
  227. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-which-account-day-caps-and-the-usage-guard.md +44 -0
  228. package/dist/packages/mcp/assets/kb/docs/docs-autotrade-your-strategies.md +37 -0
  229. package/dist/packages/mcp/assets/kb/docs/docs-autotrade.md +22 -0
  230. package/dist/packages/mcp/assets/kb/docs/docs-beginners-before-any-experimental-trading.md +2 -2
  231. package/dist/packages/mcp/assets/kb/docs/docs-beginners.md +1 -1
  232. package/dist/packages/mcp/assets/kb/docs/docs-build-a-strategy-by-chat-1-ask-for-a-strategy.md +27 -0
  233. package/dist/packages/mcp/assets/kb/docs/docs-build-a-strategy-by-chat-2-backtest-it-held-out-split.md +31 -0
  234. package/dist/packages/mcp/assets/kb/docs/docs-build-a-strategy-by-chat-3-forward-test-it-on-live-data.md +44 -0
  235. package/dist/packages/mcp/assets/kb/docs/docs-build-a-strategy-by-chat-4-promote-it-to-always-on-paper.md +36 -0
  236. package/dist/packages/mcp/assets/kb/docs/docs-build-a-strategy-by-chat-5-real-only-if-you-choose.md +36 -0
  237. package/dist/packages/mcp/assets/kb/docs/docs-build-a-strategy-by-chat-the-ladder.md +39 -0
  238. package/dist/packages/mcp/assets/kb/docs/docs-build-a-strategy-by-chat-the-report.md +31 -0
  239. package/dist/packages/mcp/assets/kb/docs/docs-build-a-strategy-by-chat-what-the-analyst-knows.md +30 -0
  240. package/dist/packages/mcp/assets/kb/docs/docs-build-a-strategy-by-chat.md +24 -0
  241. package/dist/packages/mcp/assets/kb/docs/docs-configuration-chart-markers.md +30 -0
  242. package/dist/packages/mcp/assets/kb/docs/docs-configuration-chart-y-axis.md +1 -1
  243. package/dist/packages/mcp/assets/kb/docs/docs-configuration-environment-variables.md +4 -1
  244. package/dist/packages/mcp/assets/kb/docs/docs-configuration-files-on-disk.md +1 -0
  245. package/dist/packages/mcp/assets/kb/docs/docs-configuration-headless-recorder-dexterm-record.md +3 -1
  246. package/dist/packages/mcp/assets/kb/docs/docs-configuration-price-display-mode.md +8 -6
  247. package/dist/packages/mcp/assets/kb/docs/docs-copy-trading-stage-2-the-one-key-mirror-ticket-a-proposal.md +1 -1
  248. package/dist/packages/mcp/assets/kb/docs/docs-copy-trading-stage-3-capped-auto-mirror-default-off-less.md +1 -1
  249. package/dist/packages/mcp/assets/kb/docs/docs-copy-trading-what-is-proven-what-is-not.md +1 -1
  250. package/dist/packages/mcp/assets/kb/docs/docs-copy-trading.md +1 -1
  251. package/dist/packages/mcp/assets/kb/docs/docs-data-sources-recorded-history-and-retention.md +36 -0
  252. package/dist/packages/mcp/assets/kb/docs/docs-data-sources-sources.md +1 -0
  253. package/dist/packages/mcp/assets/kb/docs/docs-getting-started-first-run.md +1 -1
  254. package/dist/packages/mcp/assets/kb/docs/docs-getting-started-install.md +3 -3
  255. package/dist/packages/mcp/assets/kb/docs/docs-getting-started-requirements.md +1 -1
  256. package/dist/packages/mcp/assets/kb/docs/docs-getting-started.md +1 -1
  257. package/dist/packages/mcp/assets/kb/docs/docs-going-real-executor-health.md +38 -0
  258. package/dist/packages/mcp/assets/kb/docs/docs-going-real-paper-vs-real.md +33 -0
  259. package/dist/packages/mcp/assets/kb/docs/docs-going-real-the-digest.md +36 -0
  260. package/dist/packages/mcp/assets/kb/docs/docs-going-real-the-executor-kit.md +48 -0
  261. package/dist/packages/mcp/assets/kb/docs/docs-going-real-the-whole-path.md +37 -0
  262. package/dist/packages/mcp/assets/kb/docs/docs-going-real-what-dexterm-does-and-never-does.md +44 -0
  263. package/dist/packages/mcp/assets/kb/docs/docs-going-real-your-limits.md +77 -0
  264. package/dist/packages/mcp/assets/kb/docs/docs-going-real.md +24 -0
  265. package/dist/packages/mcp/assets/kb/docs/docs-live-trading-changed-in-0-1-7.md +26 -0
  266. package/dist/packages/mcp/assets/kb/docs/docs-live-trading-real-mode-your-strategy-s-trades-to-your.md +31 -0
  267. package/dist/packages/mcp/assets/kb/docs/docs-live-trading-stopping.md +28 -0
  268. package/dist/packages/mcp/assets/kb/docs/docs-live-trading-the-short-version.md +34 -0
  269. package/dist/packages/mcp/assets/kb/docs/docs-live-trading-using-a-trading-bot-with-dexterm.md +31 -0
  270. package/dist/packages/mcp/assets/kb/docs/docs-live-trading-what-dexterm-does-not-do.md +30 -0
  271. package/dist/packages/mcp/assets/kb/docs/docs-live-trading-what-dexterm-does.md +29 -0
  272. package/dist/packages/mcp/assets/kb/docs/docs-live-trading.md +23 -0
  273. package/dist/packages/mcp/assets/kb/docs/docs-ollama-another-machine.md +28 -0
  274. package/dist/packages/mcp/assets/kb/docs/docs-ollama-autotrade-on-a-local-model.md +29 -0
  275. package/dist/packages/mcp/assets/kb/docs/docs-ollama-check-your-model-dexterm-ai-probe.md +38 -0
  276. package/dist/packages/mcp/assets/kb/docs/docs-ollama-how-we-checked.md +27 -0
  277. package/dist/packages/mcp/assets/kb/docs/docs-ollama-models-without-tool-calling.md +32 -0
  278. package/dist/packages/mcp/assets/kb/docs/docs-ollama-pick-the-engine-globally-or-per-surface.md +43 -0
  279. package/dist/packages/mcp/assets/kb/docs/docs-ollama-restriction-profiles.md +35 -0
  280. package/dist/packages/mcp/assets/kb/docs/docs-ollama-set-it-up-in-two-minutes.md +39 -0
  281. package/dist/packages/mcp/assets/kb/docs/docs-ollama-troubleshooting.md +35 -0
  282. package/dist/packages/mcp/assets/kb/docs/docs-ollama-what-runs-on-a-local-model.md +39 -0
  283. package/dist/packages/mcp/assets/kb/docs/docs-ollama-what-stays-outside-the-model.md +36 -0
  284. package/dist/packages/mcp/assets/kb/docs/docs-ollama-which-model.md +38 -0
  285. package/dist/packages/mcp/assets/kb/docs/docs-ollama-your-own-agent-on-the-local-model.md +28 -0
  286. package/dist/packages/mcp/assets/kb/docs/docs-ollama.md +28 -0
  287. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-letting-an-agent-paper-trade-experimental.md +3 -4
  288. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-link-a-wallet-read-only.md +30 -0
  289. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-order-plans-and-standing-mandates.md +3 -4
  290. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-panic.md +4 -7
  291. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-paper-only-mandates.md +6 -7
  292. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-pnl-cards.md +7 -7
  293. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-safety-model.md +34 -0
  294. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-ticket.md +3 -4
  295. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-trade-ledger.md +42 -0
  296. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-wallet.md +4 -5
  297. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-trade-moments.md +4 -5
  298. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading.md +4 -5
  299. package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-buy-and-sell-markers.md +37 -0
  300. package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-what-it-shows.md +2 -1
  301. package/dist/packages/mcp/assets/kb/docs/docs-real-mode-receipts-what-your-executor-did.md +42 -0
  302. package/dist/packages/mcp/assets/kb/docs/docs-real-mode-safety.md +34 -0
  303. package/dist/packages/mcp/assets/kb/docs/docs-real-mode-set-it-up.md +47 -0
  304. package/dist/packages/mcp/assets/kb/docs/docs-real-mode-the-channels.md +42 -0
  305. package/dist/packages/mcp/assets/kb/docs/docs-real-mode-the-signal.md +48 -0
  306. package/dist/packages/mcp/assets/kb/docs/docs-real-mode-what-it-is.md +35 -0
  307. package/dist/packages/mcp/assets/kb/docs/docs-real-mode-what-it-will-not-do.md +34 -0
  308. package/dist/packages/mcp/assets/kb/docs/docs-real-mode-where-you-see-it.md +34 -0
  309. package/dist/packages/mcp/assets/kb/docs/docs-real-mode.md +27 -0
  310. package/dist/packages/mcp/assets/kb/docs/docs-screens-autotrade-paper.md +26 -0
  311. package/dist/packages/mcp/assets/kb/docs/docs-screens-order-plans.md +1 -1
  312. package/dist/packages/mcp/assets/kb/docs/docs-screens-token-screen.md +2 -0
  313. package/dist/packages/mcp/assets/kb/docs/docs-spectator-the-brain-view-and-the-pnl-chip.md +1 -1
  314. package/dist/packages/mcp/assets/kb/docs/docs-telegram-approve-one-tap-entries.md +50 -0
  315. package/dist/packages/mcp/assets/kb/docs/docs-telegram-control-the-commands.md +43 -0
  316. package/dist/packages/mcp/assets/kb/docs/docs-telegram-if-something-goes-wrong.md +30 -0
  317. package/dist/packages/mcp/assets/kb/docs/docs-telegram-notify-what-reaches-your-phone.md +41 -0
  318. package/dist/packages/mcp/assets/kb/docs/docs-telegram-set-it-up.md +47 -0
  319. package/dist/packages/mcp/assets/kb/docs/docs-telegram-the-record.md +26 -0
  320. package/dist/packages/mcp/assets/kb/docs/docs-telegram-what-it-is.md +33 -0
  321. package/dist/packages/mcp/assets/kb/docs/docs-telegram-what-it-will-not-do.md +31 -0
  322. package/dist/packages/mcp/assets/kb/docs/docs-telegram.md +23 -0
  323. package/dist/packages/mcp/assets/kb/docs/docs-troubleshooting-common-questions.md +1 -1
  324. package/dist/packages/mcp/assets/kb/docs/docs-troubleshooting-doctor-lines.md +4 -0
  325. package/dist/packages/mcp/assets/kb/docs/docs-voice-linux-and-windows.md +1 -1
  326. package/dist/packages/mcp/assets/kb/docs/docs-voice.md +1 -1
  327. package/dist/packages/mcp/assets/kb/docs/docs-yolo-1-replay-it-on-your-own-history.md +42 -0
  328. package/dist/packages/mcp/assets/kb/docs/docs-yolo-2-run-it-on-paper.md +34 -0
  329. package/dist/packages/mcp/assets/kb/docs/docs-yolo-3-watch-it-and-stop-it.md +32 -0
  330. package/dist/packages/mcp/assets/kb/docs/docs-yolo-the-rules.md +37 -0
  331. package/dist/packages/mcp/assets/kb/docs/docs-yolo-what-it-is.md +34 -0
  332. package/dist/packages/mcp/assets/kb/docs/docs-yolo-what-it-will-not-do.md +31 -0
  333. package/dist/packages/mcp/assets/kb/docs/docs-yolo.md +26 -0
  334. package/dist/packages/mcp/assets/kb/entries/autotrade.md +40 -0
  335. package/dist/packages/mcp/src/app-help.js +1 -1
  336. package/dist/packages/mcp/src/autotrade-tools.js +1107 -0
  337. package/dist/packages/mcp/src/backtest-requests.js +71 -0
  338. package/dist/packages/mcp/src/engine/config.js +159 -0
  339. package/dist/packages/mcp/src/engine/index.js +10 -0
  340. package/dist/packages/mcp/src/engine/loop.js +101 -0
  341. package/dist/packages/mcp/src/engine/mcp-client.js +123 -0
  342. package/dist/packages/mcp/src/engine/ollama.js +258 -0
  343. package/dist/packages/mcp/src/engine/probe.js +110 -0
  344. package/dist/packages/mcp/src/engine/reason.js +35 -0
  345. package/dist/packages/mcp/src/engine/restrictions.js +111 -0
  346. package/dist/packages/mcp/src/index.js +7 -1
  347. package/dist/packages/mcp/src/ledger-tools.js +494 -0
  348. package/dist/packages/mcp/src/paper-agent.js +2 -0
  349. package/dist/packages/mcp/src/server.js +138 -19
  350. package/dist/packages/packs/src/backtest.js +3 -1
  351. package/dist/packages/popup/src/pages/chart-lib.js +134 -21
  352. package/dist/packages/popup/src/pages/chart.css +9 -0
  353. package/dist/packages/popup/src/pages/chart.html +3 -1
  354. package/dist/packages/popup/src/pages/chart.js +104 -7
  355. package/dist/packages/popup/src/protocol.js +2 -0
  356. package/dist/packages/popup/src/server.js +4 -0
  357. package/dist/packages/recorder/src/index.js +2 -0
  358. package/dist/packages/recorder/src/recorder.js +63 -6
  359. package/dist/packages/recorder/src/retention.js +100 -0
  360. package/dist/packages/recorder/src/schema.js +34 -1
  361. package/dist/packages/recorder/src/ticks.js +237 -0
  362. package/dist/packages/tui/src/index.js +1 -0
  363. package/dist/packages/tui/src/keymap.js +28 -1
  364. package/dist/packages/tui/src/markers.js +219 -0
  365. package/dist/packages/tui/src/widgets.js +149 -2
  366. package/package.json +2 -1
  367. package/dist/packages/data/src/trade/caps.js +0 -323
  368. package/dist/packages/data/src/trade/executor.js +0 -933
  369. package/dist/packages/data/src/trade/plans/executor-live.js +0 -220
  370. package/dist/packages/data/src/trade/rpc-exec.js +0 -229
  371. package/dist/packages/data/src/trade/signer/client.js +0 -197
  372. package/dist/packages/data/src/trade/signer/fast-wallet.js +0 -154
  373. package/dist/packages/data/src/trade/signer/host.js +0 -97
  374. package/dist/packages/data/src/trade/signer/main.js +0 -121
  375. package/dist/packages/data/src/trade/signer/probe-builder.js +0 -85
  376. package/dist/packages/data/src/trade/signer/protocol.js +0 -92
  377. package/dist/packages/data/src/trade/signer/service.js +0 -400
  378. package/dist/packages/data/src/trade/signer/sol-usd-feed.js +0 -98
  379. package/dist/packages/data/src/trade/sol-usd.js +0 -86
  380. package/dist/packages/data/src/trade/swap-build.js +0 -108
  381. package/dist/packages/data/src/trade/token-delta.js +0 -201
  382. package/dist/packages/data/vendor/solana-web3/LICENSE +0 -20
  383. package/dist/packages/data/vendor/solana-web3/NOTICE.md +0 -13
  384. package/dist/packages/data/vendor/solana-web3/index.iife.min.js +0 -20
  385. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-a-live-ticket.md +0 -42
  386. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-before-you-press-size-vs-caps.md +0 -34
  387. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-devnet-signer-mainnet-token.md +0 -35
  388. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-jupiter-rate-limits.md +0 -33
  389. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-link-a-wallet.md +0 -32
  390. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-live-trading-devnet-first.md +0 -30
  391. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-mainnet.md +0 -31
  392. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-live-fire-path-devnet-the-fast-wallet.md +0 -41
  393. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-signer-process.md +0 -34
  394. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-what-the-live-path-keeps.md +0 -37
  395. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-your-first-live-trade.md +0 -41
@@ -0,0 +1,76 @@
1
+ // `dexterm autotrade stop` (task-1509 AT-7, AUTOTRADE-SPEC §6.3). PAPER ONLY.
2
+ //
3
+ // A soft stop of the running paper runner: no new entries, every session closed, pending orders dropped, and the
4
+ // mechanical exits (stops, take-profits, trails, rug exits) keep running until nothing is held; then the runner
5
+ // ends. It writes a request for that run into $DEXTERM_HOME/autotrade/control.json, which the runner re-reads on every
6
+ // step, and waits a few seconds for the runner to confirm through its rendezvous. A stop is final for the run.
7
+ // `dexterm wallet panic` is the harder switch: every paper desk and signer re-reads it, and only
8
+ // `dexterm wallet resume` on a real terminal lifts it. Nothing here touches a wallet, a key or the signer.
9
+ import { dextermHome } from '../../../custom/src/index.js';
10
+ import { activeRunner, requestControl } from '../../../autotrade/src/index.js';
11
+ import { parseArgs } from "./strategies.js";
12
+ export const STOP_USAGE = 'dexterm autotrade stop [--strategy ID] [--wait SEC] [--json]';
13
+ const tick = (ms) => new Promise((r) => setTimeout(r, ms));
14
+ /** True once the runner shows the request in its rendezvous (or is gone). */
15
+ function acknowledged(r, runId, action) {
16
+ if (!r || r.runId !== runId)
17
+ return true;
18
+ if (r.state === 'stopped')
19
+ return true;
20
+ return action === 'flatten' ? r.haltReason === 'flatten' : r.haltReason !== null && r.state === 'halted';
21
+ }
22
+ /** Send stop or flatten to the active runner and wait up to waitSec for it to confirm. */
23
+ export async function sendControl(io, action, waitSec, runner) {
24
+ const home = dextermHome(io.env);
25
+ const w = requestControl(home, runner.runId, action, 'cli');
26
+ if (!w.ok)
27
+ return { error: w.why };
28
+ const until = Date.now() + Math.max(0, waitSec) * 1000;
29
+ let cur = activeRunner(home);
30
+ while (!acknowledged(cur, runner.runId, action) && Date.now() < until) {
31
+ await tick(200);
32
+ cur = activeRunner(home);
33
+ }
34
+ const same = cur && cur.runId === runner.runId ? cur : null;
35
+ return { requested: true, runId: runner.runId, acknowledged: acknowledged(cur, runner.runId, action), already: w.already, positions: same ? same.positions : 0, sessions: same ? same.sessions : 0, ended: !same || same.state === 'stopped' };
36
+ }
37
+ export function waitArg(v) {
38
+ const n = typeof v === 'string' ? Number(v) : NaN;
39
+ return Number.isFinite(n) && n >= 0 ? Math.min(n, 120) : 10;
40
+ }
41
+ export async function stopCmd(argv, io) {
42
+ const { pos, opts } = parseArgs(argv, ['json']);
43
+ if (pos.length) {
44
+ io.stderr.write(`usage: ${STOP_USAGE}\n`);
45
+ return 2;
46
+ }
47
+ // task-1529: one strategy of a parallel run; the others keep running.
48
+ if (typeof opts.strategy === 'string')
49
+ return (await import("./strategy-control.js")).memberStopCmd(io, opts.strategy, 'stop', opts);
50
+ const home = dextermHome(io.env);
51
+ const r = activeRunner(home);
52
+ if (!r) {
53
+ if (opts.json)
54
+ io.stdout.write(`${JSON.stringify({ requested: false, runId: null, why: 'no autotrade runner is running' })}\n`);
55
+ else
56
+ io.stdout.write('no autotrade runner is running; nothing to stop. (`dexterm wallet panic` halts every paper desk and signer.)\n');
57
+ return 0;
58
+ }
59
+ const res = await sendControl(io, 'stop', waitArg(opts.wait), r);
60
+ if ('error' in res) {
61
+ io.stderr.write(`dexterm autotrade stop: ${res.error}\n`);
62
+ return 1;
63
+ }
64
+ if (opts.json) {
65
+ io.stdout.write(`${JSON.stringify(res)}\n`);
66
+ return 0;
67
+ }
68
+ io.stdout.write(`stop ${res.already ? 'was already requested' : 'requested'} for run ${r.runId} (pid ${r.pid})\n`);
69
+ if (!res.acknowledged)
70
+ io.stdout.write('the runner has not confirmed yet: it reads the request on its next tick. Watch the Q screen, or run this again.\n');
71
+ else if (res.ended)
72
+ io.stdout.write('✓ the runner stopped (nothing was held)\n');
73
+ else
74
+ io.stdout.write(`✓ halted: no new entries, sessions closed, orders dropped${res.positions ? `; ${res.positions} paper position${res.positions === 1 ? '' : 's'} keep${res.positions === 1 ? 's' : ''} its mechanical exits until closed (\`dexterm autotrade flatten\` sells now)` : ''}\n`);
75
+ return 0;
76
+ }
@@ -0,0 +1,198 @@
1
+ // `dexterm autotrade list|validate|new|import|remove|journal` (task-1503 AT-1): the strategy store from the CLI.
2
+ // Every write goes through @dexterm/autotrade StrategyStore (validated first, atomic, journaled with actor
3
+ // "user"); nothing here signs, arms or trades.
4
+ import { existsSync, readFileSync } from 'node:fs';
5
+ import { fmtIssue, StrategyStore, validateStrategy } from '../../../autotrade/src/index.js';
6
+ export function parseArgs(argv, booleans = []) {
7
+ const pos = [];
8
+ const opts = {};
9
+ for (let i = 0; i < argv.length; i++) {
10
+ const a = argv[i];
11
+ if (!a.startsWith('--')) {
12
+ pos.push(a);
13
+ continue;
14
+ }
15
+ const eq = a.indexOf('=');
16
+ if (eq > 0) {
17
+ opts[a.slice(2, eq)] = a.slice(eq + 1);
18
+ continue;
19
+ }
20
+ const k = a.slice(2);
21
+ const v = argv[i + 1];
22
+ if (!booleans.includes(k) && v !== undefined && !v.startsWith('--')) {
23
+ opts[k] = v;
24
+ i++;
25
+ }
26
+ else
27
+ opts[k] = true;
28
+ }
29
+ return { pos, opts };
30
+ }
31
+ export const storeFor = (io) => new StrategyStore({ env: io.env });
32
+ const looksLikeFile = (a) => a.endsWith('.json') || a.includes('/') || a.includes('\\');
33
+ /** Resolve `<id|file>`: an existing path (or anything that looks like one) is a file; otherwise the store, then the presets. */
34
+ export function resolveStrategyArg(arg, io) {
35
+ if (!arg)
36
+ return null;
37
+ if (looksLikeFile(arg) || existsSync(arg)) {
38
+ if (!existsSync(arg))
39
+ return { ok: false, errors: [{ path: '', msg: `no such file ${arg}` }], warnings: [], source: 'file' };
40
+ let doc;
41
+ try {
42
+ doc = JSON.parse(readFileSync(arg, 'utf8'));
43
+ }
44
+ catch (e) {
45
+ return { ok: false, errors: [{ path: '', msg: `not JSON: ${e.message}` }], warnings: [], source: 'file' };
46
+ }
47
+ return { ...validateStrategy(doc), source: 'file' };
48
+ }
49
+ try {
50
+ const g = storeFor(io).get(arg);
51
+ return g ? { ...g, source: g.source } : { ok: false, errors: [{ path: '', msg: `no strategy or preset named ${arg} (dexterm autotrade list)` }], warnings: [], source: 'store' };
52
+ }
53
+ catch (e) {
54
+ return { ok: false, errors: [{ path: '', msg: e.message }], warnings: [], source: 'store' };
55
+ }
56
+ }
57
+ const printIssues = (io, kind, xs, to = 'stdout') => { for (const x of xs)
58
+ io[to].write(`${kind} ${fmtIssue(x)}\n`); };
59
+ export function listCmd(argv, io) {
60
+ const { opts } = parseArgs(argv, ['json']);
61
+ const store = storeFor(io);
62
+ const rows = store.list();
63
+ if (opts.json) {
64
+ io.stdout.write(JSON.stringify({ dir: store.dir, strategies: rows }, null, 2) + '\n');
65
+ return 0;
66
+ }
67
+ io.stdout.write(`STRATEGIES · PAPER · ${store.dir}\n`);
68
+ const w = Math.max(4, ...rows.map((r) => r.id.length));
69
+ for (const r of rows) {
70
+ const bt = r.lastBacktest ? `last backtest ${r.lastBacktest.trades} trades ${r.lastBacktest.netUsd >= 0 ? '+' : '-'}$${Math.abs(r.lastBacktest.netUsd).toFixed(2)} (${r.lastBacktest.netPct}%), dd ${r.lastBacktest.maxDrawdownPct}%` : 'no backtest yet';
71
+ const head = ` ${r.id.padEnd(w)} ${(r.source + (r.shadowsPreset ? '*' : '')).padEnd(7)}`;
72
+ if (!r.ok) {
73
+ io.stdout.write(`${head} INVALID: ${(r.errors ?? []).slice(0, 2).map(fmtIssue).join('; ')}\n`);
74
+ continue;
75
+ }
76
+ io.stdout.write(`${head} v${r.version.padEnd(7)} ${r.hash} ${r.mode.padEnd(5)} profiles ${r.profiles.join(',')} · ${bt}${r.highRisk ? ' · ⚠ HIGH RISK' : ''}\n`);
77
+ }
78
+ if (rows.some((r) => r.shadowsPreset))
79
+ io.stdout.write(' * your file shadows the shipped preset of the same id\n');
80
+ return 0;
81
+ }
82
+ export function validateCmd(argv, io) {
83
+ const { pos, opts } = parseArgs(argv, ['json']);
84
+ const r = resolveStrategyArg(pos[0] ?? (typeof opts.strategy === 'string' ? opts.strategy : undefined), io);
85
+ if (!r) {
86
+ io.stderr.write('usage: dexterm autotrade validate <id|file> [--json]\n');
87
+ return 2;
88
+ }
89
+ if (opts.json) {
90
+ io.stdout.write(JSON.stringify(r.ok ? { ok: true, id: r.strategy.id, version: r.strategy.version, hash: r.strategy.hash, mode: r.strategy.mode, warnings: r.warnings } : { ok: false, errors: r.errors, warnings: r.warnings }, null, 2) + '\n');
91
+ return r.ok ? 0 : 2;
92
+ }
93
+ printIssues(io, 'warning', r.warnings);
94
+ if (!r.ok) {
95
+ printIssues(io, 'error', r.errors);
96
+ return 2;
97
+ }
98
+ const s = r.strategy;
99
+ io.stdout.write(`ok ${s.id} v${s.version} hash ${s.hash} mode ${s.mode}${s.mode === 'live' ? ' (does not run: dexterm runs strategies on paper only)' : ''} profiles ${Object.keys(s.exits.profiles).join(',')} (${r.source})\n`);
100
+ return 0;
101
+ }
102
+ export function newCmd(argv, io) {
103
+ const { pos, opts } = parseArgs(argv);
104
+ const id = pos[0];
105
+ const from = typeof opts.from === 'string' ? opts.from : undefined;
106
+ if (!id || !from) {
107
+ io.stderr.write('usage: dexterm autotrade new <new-id> --from <preset|id> [--name TEXT]\n');
108
+ return 2;
109
+ }
110
+ let r;
111
+ try {
112
+ r = storeFor(io).createFrom(from, id, { actor: 'user', name: typeof opts.name === 'string' ? opts.name : undefined });
113
+ }
114
+ catch (e) {
115
+ io.stderr.write(`dexterm autotrade: ${e.message}\n`);
116
+ return 2;
117
+ }
118
+ if (!r.ok) {
119
+ printIssues(io, 'error', r.errors, 'stderr');
120
+ return 2;
121
+ }
122
+ printIssues(io, 'warning', r.warnings);
123
+ io.stdout.write(`created ${id} v${r.strategy.version} (${r.strategy.hash}) from ${from} → ${storeFor(io).pathOf(id)}\n edit the file, then: dexterm autotrade validate ${id} · dexterm autotrade backtest ${id}\n`);
124
+ return 0;
125
+ }
126
+ export function importCmd(argv, io) {
127
+ const { pos, opts } = parseArgs(argv, ['replace']);
128
+ const file = pos[0];
129
+ if (!file || !existsSync(file)) {
130
+ io.stderr.write('usage: dexterm autotrade import <file> [--replace]\n');
131
+ return 2;
132
+ }
133
+ let doc;
134
+ try {
135
+ doc = JSON.parse(readFileSync(file, 'utf8'));
136
+ }
137
+ catch (e) {
138
+ io.stderr.write(`not JSON: ${e.message}\n`);
139
+ return 2;
140
+ }
141
+ // Spec §2c: an imported strategy is always paper, whatever the file says.
142
+ const forced = doc && typeof doc === 'object' && doc.mode !== 'paper';
143
+ if (forced)
144
+ doc = { ...doc, mode: 'paper' };
145
+ const store = storeFor(io);
146
+ const id = typeof doc.id === 'string' ? doc.id : '';
147
+ let r;
148
+ try {
149
+ r = opts.replace && id && store.has(id) ? store.update(id, doc, { actor: 'import', why: `import ${file}` }) : store.create(doc, { actor: 'import', why: `import ${file}` });
150
+ }
151
+ catch (e) {
152
+ io.stderr.write(`dexterm autotrade: ${e.message}\n`);
153
+ return 2;
154
+ }
155
+ if (!r.ok) {
156
+ printIssues(io, 'error', r.errors, 'stderr');
157
+ return 2;
158
+ }
159
+ printIssues(io, 'warning', r.warnings);
160
+ io.stdout.write(`imported ${r.strategy.id} v${r.strategy.version} (${r.strategy.hash})${forced ? ' · mode forced to paper' : ''}\n`);
161
+ return 0;
162
+ }
163
+ export function removeCmd(argv, io) {
164
+ const { pos } = parseArgs(argv);
165
+ if (!pos[0]) {
166
+ io.stderr.write('usage: dexterm autotrade remove <id>\n');
167
+ return 2;
168
+ }
169
+ let r;
170
+ try {
171
+ r = storeFor(io).remove(pos[0], { actor: 'user' });
172
+ }
173
+ catch (e) {
174
+ io.stderr.write(`dexterm autotrade: ${e.message}\n`);
175
+ return 2;
176
+ }
177
+ if (!r.ok) {
178
+ printIssues(io, 'error', r.errors, 'stderr');
179
+ return 2;
180
+ }
181
+ io.stdout.write(`removed ${pos[0]} → ${r.movedTo}\n`);
182
+ return 0;
183
+ }
184
+ export function journalCmd(argv, io) {
185
+ const { pos, opts } = parseArgs(argv, ['json']);
186
+ const j = storeFor(io).journal(pos[0]);
187
+ if (opts.json) {
188
+ io.stdout.write(JSON.stringify(j, null, 2) + '\n');
189
+ return 0;
190
+ }
191
+ if (!j.length) {
192
+ io.stdout.write('no strategy changes journaled yet\n');
193
+ return 0;
194
+ }
195
+ for (const x of j)
196
+ io.stdout.write(`${new Date(x.t).toISOString()} ${x.action.padEnd(6)} ${x.id.padEnd(20)} by ${x.actor.padEnd(8)} ${x.beforeHash ?? '—'} → ${x.afterHash ?? '—'}${x.version ? ` v${x.version}` : ''} ${x.ops.length} op(s)${x.why ? ` · ${x.why}` : ''}\n`);
197
+ return 0;
198
+ }
@@ -0,0 +1,174 @@
1
+ // `dexterm autotrade status [--all]`, `start <strategy>`, `pause | resume [--strategy ID]`, and the per-strategy
2
+ // `stop | flatten --strategy ID` (task-1529, parallel strategies). PAPER ONLY.
3
+ //
4
+ // Without --strategy, pause and resume act on the whole runner (control.json, like the Q screen's `p`), whether it
5
+ // runs one strategy or several. With --strategy they act on one strategy of `dexterm autotrade run --all` through its
6
+ // own control file (autotrade/fleet/<id>.control.json): another strategy never sees it. `start` starts a strategy of
7
+ // autotrade.json that is not running (paper, with its own config; nothing else can be changed from here).
8
+ // Nothing here touches a wallet, a key or the signer.
9
+ import { dextermHome } from '../../../custom/src/index.js';
10
+ import { accountTable, activeRunner, compareRows, compareTable, fleetTotals, readFleetStatus, requestControl, requestMemberControl, } from '../../../autotrade/src/index.js';
11
+ import { parseArgs } from "./strategies.js";
12
+ export const STATUS_USAGE = 'dexterm autotrade status [--all] [--json]';
13
+ export const START_USAGE = 'dexterm autotrade start <strategy> [--wait SEC] [--json]';
14
+ export const PAUSE_USAGE = 'dexterm autotrade pause [--strategy ID] [--json]';
15
+ export const RESUME_USAGE = 'dexterm autotrade resume [--strategy ID] [--json]';
16
+ const tick = (ms) => new Promise((r) => setTimeout(r, ms));
17
+ const waitSec = (v, dflt = 10) => { const n = typeof v === 'string' ? Number(v) : NaN; return Number.isFinite(n) && n >= 0 ? Math.min(n, 120) : dflt; };
18
+ function memberNow(home, id) {
19
+ const st = readFleetStatus(home);
20
+ return st.ok ? st.status.members.find((m) => m.id === id) ?? null : null;
21
+ }
22
+ /** True once the strategy's state shows the request (or the fleet is gone). */
23
+ function acknowledged(m, action, runId) {
24
+ if (!m)
25
+ return true;
26
+ switch (action) {
27
+ case 'start': return m.runId !== null && m.runId !== runId && m.state !== 'idle';
28
+ case 'stop': return m.runId !== runId || m.state === 'stopped' || m.state === 'halted';
29
+ case 'flatten': return m.runId !== runId || m.state === 'stopped' || m.haltReason === 'flatten';
30
+ case 'pause': return m.state === 'paused' || m.state === 'halted' || m.state === 'stopped';
31
+ case 'resume-entries': return m.state !== 'paused';
32
+ }
33
+ }
34
+ /** Write one strategy's request and wait up to `wait` seconds for its runner to show it. */
35
+ export async function sendMemberControl(io, id, action, wait) {
36
+ const home = dextermHome(io.env);
37
+ const before = memberNow(home, id);
38
+ const w = requestMemberControl(home, id, action, 'cli');
39
+ if (!w.ok)
40
+ return { error: w.why };
41
+ const prevRun = action === 'start' ? before?.runId ?? null : w.request.runId;
42
+ const until = Date.now() + wait * 1000;
43
+ let cur = memberNow(home, id);
44
+ while (!acknowledged(cur, action, prevRun) && Date.now() < until) {
45
+ await tick(200);
46
+ cur = memberNow(home, id);
47
+ }
48
+ return { strategy: id, action, requested: true, already: w.already, acknowledged: acknowledged(cur, action, prevRun), runId: cur?.runId ?? null, state: cur?.state ?? null };
49
+ }
50
+ const WORD = { start: 'start', stop: 'stop', flatten: 'flatten', pause: 'pause', 'resume-entries': 'resume' };
51
+ export function printMemberOutcome(io, res, json) {
52
+ if (json) {
53
+ io.stdout.write(`${JSON.stringify(res)}\n`);
54
+ return;
55
+ }
56
+ io.stdout.write(`${WORD[res.action]} ${res.already ? 'was already requested' : 'requested'} for strategy ${res.strategy} (the others are not touched)\n`);
57
+ if (!res.acknowledged)
58
+ io.stdout.write('the runner has not confirmed yet: it reads the request on its next tick. `dexterm autotrade status --all` shows each strategy.\n');
59
+ else
60
+ io.stdout.write(`✓ ${res.strategy}: ${res.state ?? 'gone'}${res.action === 'start' && res.runId ? ` (run ${res.runId})` : ''}\n`);
61
+ }
62
+ /** `dexterm autotrade stop | flatten --strategy ID` (called from stop.ts / flatten.ts). */
63
+ export async function memberStopCmd(io, id, action, opts) {
64
+ const res = await sendMemberControl(io, id, action, waitSec(opts.wait));
65
+ if ('error' in res) {
66
+ io.stderr.write(`dexterm autotrade ${action}: ${res.error}\n`);
67
+ return 1;
68
+ }
69
+ printMemberOutcome(io, res, !!opts.json);
70
+ return 0;
71
+ }
72
+ export async function startCmd(argv, io) {
73
+ const { pos, opts } = parseArgs(argv, ['json']);
74
+ const id = typeof opts.strategy === 'string' ? opts.strategy : pos[0];
75
+ if (!id || pos.length > 1) {
76
+ io.stderr.write(`usage: ${START_USAGE}\n (starts a strategy of autotrade.json in the running \`dexterm autotrade run --all --paper\`)\n`);
77
+ return 2;
78
+ }
79
+ const res = await sendMemberControl(io, id, 'start', waitSec(opts.wait));
80
+ if ('error' in res) {
81
+ io.stderr.write(`dexterm autotrade start: ${res.error}\n`);
82
+ return 1;
83
+ }
84
+ printMemberOutcome(io, res, !!opts.json);
85
+ return 0;
86
+ }
87
+ async function pauseResume(argv, io, action) {
88
+ const { pos, opts } = parseArgs(argv, ['json']);
89
+ const name = action === 'pause' ? 'pause' : 'resume';
90
+ if (pos.length) {
91
+ io.stderr.write(`usage: ${action === 'pause' ? PAUSE_USAGE : RESUME_USAGE}\n`);
92
+ return 2;
93
+ }
94
+ if (typeof opts.strategy === 'string') {
95
+ const res = await sendMemberControl(io, opts.strategy, action, waitSec(opts.wait, 5));
96
+ if ('error' in res) {
97
+ io.stderr.write(`dexterm autotrade ${name}: ${res.error}\n`);
98
+ return 1;
99
+ }
100
+ printMemberOutcome(io, res, !!opts.json);
101
+ return 0;
102
+ }
103
+ const home = dextermHome(io.env);
104
+ const r = activeRunner(home);
105
+ if (!r) {
106
+ io.stdout.write(opts.json ? `${JSON.stringify({ requested: false, why: 'no autotrade runner is running' })}\n` : `no autotrade runner is running; nothing to ${name}\n`);
107
+ return 0;
108
+ }
109
+ const w = requestControl(home, r.runId, action, 'cli');
110
+ if (!w.ok) {
111
+ io.stderr.write(`dexterm autotrade ${name}: ${w.why}\n`);
112
+ return 1;
113
+ }
114
+ if (opts.json) {
115
+ io.stdout.write(`${JSON.stringify({ requested: true, runId: r.runId, action })}\n`);
116
+ return 0;
117
+ }
118
+ io.stdout.write(action === 'pause'
119
+ ? `pause requested for run ${r.runId}: no new entries${r.runId.includes('-fleet-') ? ' in any strategy' : ''}; open positions keep their exits (\`dexterm autotrade resume\` lifts it)\n`
120
+ : `resume requested for run ${r.runId}: new entries allowed again\n`);
121
+ return 0;
122
+ }
123
+ export const pauseCmd = (argv, io) => pauseResume(argv, io, 'pause');
124
+ export const resumeCmd = (argv, io) => pauseResume(argv, io, 'resume-entries');
125
+ export function statusCmd(argv, io) {
126
+ const { pos, opts } = parseArgs(argv, ['all', 'json']);
127
+ if (pos.length) {
128
+ io.stderr.write(`usage: ${STATUS_USAGE}\n`);
129
+ return 2;
130
+ }
131
+ const home = dextermHome(io.env);
132
+ const r = activeRunner(home);
133
+ const fs = readFleetStatus(home);
134
+ const fleetCurrent = fs.ok && r?.runId === fs.status.fleetId;
135
+ if (opts.json) {
136
+ io.stdout.write(`${JSON.stringify({
137
+ paper: true, runner: r,
138
+ ...(fs.ok && (opts.all || fleetCurrent) ? { fleet: { fleetId: fs.status.fleetId, state: r?.runId === fs.status.fleetId ? fs.status.state : 'stopped', stale: fs.stale, global: fs.status.global, totals: fleetTotals(fs.status), strategies: compareRows(fs.status), ...(fs.status.accounts ? { accounts: fs.status.accounts } : {}) } } : {}),
139
+ }, null, 2)}\n`);
140
+ return 0;
141
+ }
142
+ if (!r)
143
+ io.stdout.write('no autotrade runner is running\n');
144
+ else
145
+ io.stdout.write(`paper runner ${r.runId} (pid ${r.pid}) · ${r.state ?? 'starting'}${r.haltReason ? ` (${r.haltReason})` : ''} · ${r.positions} open · ${r.sessions} sessions${r.heartbeatAt ? ` · heartbeat ${Math.round((Date.now() - r.heartbeatAt) / 1000)} s ago` : ''}\n`);
146
+ if (!opts.all && !fleetCurrent) {
147
+ if (r)
148
+ io.stdout.write('(one strategy; `dexterm autotrade run --all --paper` runs every strategy of autotrade.json at once)\n');
149
+ return 0;
150
+ }
151
+ if (!fs.ok) {
152
+ io.stdout.write(`parallel strategies: ${fs.why}\n`);
153
+ return 0;
154
+ }
155
+ const st = fs.status;
156
+ const running = r?.runId === st.fleetId;
157
+ io.stdout.write(`\nPARALLEL STRATEGIES · PAPER · fleet ${st.fleetId} · ${running ? st.state : 'ended'}${fs.stale && running ? ' (heartbeat stale)' : ''} · ${st.source}\n`);
158
+ const g = st.global;
159
+ io.stdout.write(`global: ${g.liveSessions}/${g.caps.maxConcurrentSessions} sessions open · $${g.today.modelUsd.toFixed(2)}/$${g.caps.modelUsdPerDay} model spend today · ${g.today.candidateSessions}/${g.caps.candidateSessionsPerDay} candidate sessions · load ${g.load.load1m ?? '—'}${g.load.paused ? ' (sessions paused: machine busy)' : ''}${g.blocked ? ` · blocked: ${g.blocked}` : ''}\n\n`);
160
+ for (const l of compareTable(compareRows(st)))
161
+ io.stdout.write(`${l}\n`);
162
+ const acct = accountTable(st);
163
+ if (acct.length)
164
+ io.stdout.write(`\npaper accounts (shared simulated wallets):\n${acct.join('\n')}\n`);
165
+ const tot = fleetTotals(st);
166
+ io.stdout.write(`\ntogether: ${tot.pnlUsd >= 0 ? '+' : '-'}$${Math.abs(tot.pnlUsd).toFixed(2)}${tot.pnlPct === null ? '' : ` (${tot.pnlPct >= 0 ? '+' : ''}${tot.pnlPct}%)`} on $${tot.startUsd.toFixed(2)} · ${tot.closed} closed · ${tot.open} open · $${tot.spendUsd.toFixed(4)} model spend. Paper, simulated fills; not financial advice.\n`);
167
+ const missed = st.members.flatMap((m) => m.stats.missedSample.map((x) => `${m.id}: ${x.symbol} ${x.x}x`));
168
+ if (missed.length)
169
+ io.stdout.write(`missed runners (seen, not entered, later >= 2x): ${missed.slice(0, 6).join(' · ')}\n`);
170
+ for (const m of st.members)
171
+ if (m.state === 'error')
172
+ io.stdout.write(`${m.id}: failed: ${m.error ?? 'unknown'}\n`);
173
+ return 0;
174
+ }
@@ -0,0 +1,101 @@
1
+ // The Telegram side of `dexterm autotrade run --paper` (task-1527, AUTOTRADE-SPEC §8). PAPER today.
2
+ //
3
+ // When `dexterm telegram setup` stored a token and a chat is paired, the runner starts the user's own bot in the
4
+ // same process: notify (the run ledger as it is written), control (/status /pause /kill …, through the same control
5
+ // file the CLI writes) and approve-to-trade (proposals with one-tap buttons; the order then goes through the paper
6
+ // port, which wraps the runner's paper executor and spends a single-use proof per approved order). A /use switch
7
+ // takes effect when the run has closed out its positions: the host starts the next run with the new strategy.
8
+ // The PnL card of a closed trade is the app's card renderer over the position's ledger fills (USD book, priced in
9
+ // SOL with the coin's own DexScreener SOL quote at the close; no image when there is none).
10
+ // task-1571: the bot is the user's OWN bot and the port is always the paper port. dexterm holds no key and places no
11
+ // live order; an approval only ever releases a PAPER order.
12
+ import { PaperPort, TelegramConnector, TelegramService, loadConnectors, secretStore, } from '../../../autotrade/src/index.js';
13
+ /** Why a Telegram approval is refused for a strategy that is not paper (dexterm places no live order). */
14
+ export const LIVE_APPROVALS_REFUSED = 'live-approval-port-not-installed';
15
+ export class TelegramHost {
16
+ service;
17
+ port;
18
+ runId = null;
19
+ strategy = null;
20
+ state = null;
21
+ next = null;
22
+ execRef;
23
+ /** SOL/USD near a coin for the card, set per run (a /use switch starts a new data layer). */
24
+ solUsdFor;
25
+ constructor(o, connector, knownToken = null) {
26
+ this.execRef = { exec: o.exec };
27
+ this.solUsdFor = o.solUsdFor ?? null;
28
+ const exec = { name: o.exec.name, buy: (k, usd, ctx) => this.execRef.exec.buy(k, usd, ctx), sell: (k, t, r) => this.execRef.exec.sell(k, t, r) };
29
+ // A Telegram approval is a paper proof: every approval for a strategy that is not mode "paper" is refused here
30
+ // (notify and /kill keep working).
31
+ this.port = new PaperPort(exec, { now: o.now, entryBlock: () => (this.strategy && this.strategy.mode !== 'paper' ? LIVE_APPROVALS_REFUSED : null) });
32
+ this.service = new TelegramService({
33
+ home: o.home, connector, port: this.port, now: o.now, timers: o.timers, knownToken: () => knownToken,
34
+ runId: () => this.runId, state: () => this.state, strategy: () => this.strategy,
35
+ onSwitch: (s) => { this.next = s; o.say(`telegram: switch to ${s.id} v${s.version} confirmed; it starts once nothing is held`); },
36
+ alert: (line) => o.say(`! ${line}`),
37
+ card: (t) => (this.solUsdFor ? autotradeCardPng(t, this.solUsdFor) : Promise.resolve(null)), // the card is a paper card
38
+ });
39
+ }
40
+ /** Point the host at the run that is starting (a /use switch starts a new one in the same process). */
41
+ attach(runId, s, exec, solUsdFor) {
42
+ this.runId = runId;
43
+ this.strategy = s;
44
+ this.state = null;
45
+ this.next = null;
46
+ this.execRef.exec = exec;
47
+ if (solUsdFor)
48
+ this.solUsdFor = solUsdFor;
49
+ }
50
+ onLedger = (e) => this.service.onLedger(e);
51
+ onState = (st) => { this.state = st; this.service.onState(st); };
52
+ /** The strategy a confirmed /use asked for, once (null when none). */
53
+ takeSwitch() { const n = this.next; this.next = null; return n; }
54
+ async stop() { await this.service.stop(); }
55
+ }
56
+ /** Start the bot for a run when it is set up and paired; `quiet` = it is simply not set up (say nothing). */
57
+ export async function startTelegramHost(o) {
58
+ const r = loadConnectors(o.home);
59
+ if (!r.ok)
60
+ return { ok: false, why: r.error, quiet: false };
61
+ const t = r.config.telegram;
62
+ if (!t.enabled || !t.allow.length)
63
+ return { ok: false, why: 'telegram is not set up (dexterm telegram setup)', quiet: !t.enabled && !r.exists };
64
+ let token = null;
65
+ let connector = o.connector;
66
+ if (!connector) {
67
+ const store = o.store ?? (t.secretStore ? secretStore(t.secretStore, o.home) : null);
68
+ token = store?.get() ?? null;
69
+ if (!token)
70
+ return { ok: false, why: 'the bot token is missing from the secret store (dexterm telegram setup)', quiet: false };
71
+ const tk = token;
72
+ connector = new TelegramConnector({ token: () => tk, onLog: (l) => o.say(`telegram: ${l}`) });
73
+ }
74
+ const host = new TelegramHost(o, connector, token);
75
+ await host.service.start();
76
+ return { ok: true, host };
77
+ }
78
+ /** The PnL card PNG of an autotrade paper trade (pnl-card.ts over the position's fills), or null. */
79
+ export async function autotradeCardPng(t, solUsdFor) {
80
+ const fills = t.fills ?? [];
81
+ if (!fills.some((f) => f.side === 'buy'))
82
+ return null;
83
+ const solUsd = await solUsdFor(t.mint).catch(() => null);
84
+ if (!solUsd || !(solUsd > 0))
85
+ return null;
86
+ const card = await import("../pnl-card.js");
87
+ const DEC = 6;
88
+ const input = {
89
+ source: 'paper', mint: t.mint, symbol: t.symbol, name: null, decimals: DEC,
90
+ fills: fills.map((f) => ({ t: f.t, side: f.side, solDelta: (f.side === 'buy' ? -1 : 1) * (f.usd / solUsd), tokenDelta: BigInt(Math.round(f.tokens * 10 ** DEC)) * (f.side === 'buy' ? 1n : -1n), feeSol: null, sig: null })),
91
+ ledger: `dexterm autotrade paper run (USD book, SOL at $${solUsd.toFixed(2)})`, wallet: null, mark: null,
92
+ excluded: [], fees: 'modelled fee, slippage and price impact included',
93
+ };
94
+ try {
95
+ const stats = card.computeCard(input, t.closedAt);
96
+ return new Uint8Array(card.cardPng(stats, { aspect: 'wide' }));
97
+ }
98
+ catch {
99
+ return null;
100
+ }
101
+ }