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
@@ -2,7 +2,7 @@ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
2
2
  import { fileURLToPath } from 'node:url';
3
3
  import { defaultDbPath, LINK_RUBRIC_V0, DEFAULT_LINK_RUBRIC } from '../../data/src/index.js';
4
4
  import { exportRecorded, openHistoryReadOnly, readLarpJoin } from '../../recorder/src/index.js';
5
- import { runBacktest, h1Model, larpEval, renderLarpEvalText, skillBacktest, renderSkillBacktestText, tuneLinkRubric, tuneRugRules, RUG_RULES_V0, RUG_RULES_V1, SKILL_EVAL_SCHEMA, } from '../../packs/src/index.js';
5
+ import { runBacktest, h1Model, larpEval, renderLarpEvalText, skillBacktest, renderSkillBacktestText, tuneLinkRubric, tuneRugRules, larpScoreBacktest, renderLarpScoreBacktestText, RUG_RULES_V0, RUG_RULES_V1, SKILL_EVAL_SCHEMA, } from '../../packs/src/index.js';
6
6
  import { buildSkillEvalSet } from "./skill-eval-build.js";
7
7
  /** task-1401: the committed eval set the skill backtest reads by default. */
8
8
  export const DEFAULT_SKILL_EVAL = fileURLToPath(new URL('../../packs/eval/skills-eval.json', import.meta.url));
@@ -11,6 +11,7 @@ export const BACKTEST_HELP = `dexterm backtest: score the rug model against reco
11
11
 
12
12
  dexterm backtest [--subject heuristic|pack_verdicts|larp] [--horizon SEC] [--db PATH] [--json]
13
13
  dexterm backtest --subject skills [--eval FILE] [--tune] [--report FILE] [--json]
14
+ dexterm backtest --subject larp-score [--eval FILE] [--report FILE] [--json]
14
15
  dexterm backtest --build-eval FILE [--db PATH] [--horizon SEC] [--max-lag SEC]
15
16
 
16
17
  --subject heuristic (default, the pre-registered H1 rug model), pack_verdicts (recorded pack rug_p), or
@@ -20,6 +21,9 @@ export const BACKTEST_HELP = `dexterm backtest: score the rug model against reco
20
21
  check's links-only baseline, the rug-check verdict rules), per-grade precision/recall on a train
21
22
  and a held-out TEST split. Default eval: packages/packs/eval/skills-eval.json. --tune re-tunes on
22
23
  the train split only and prints before (v0) vs tuned; --report writes the JSON report.
24
+ larp-score task-1471: the 0-100 LARP score's link-shape points fitted on the same eval set's train split,
25
+ with AUROC and P(bad) per band on train and the held-out TEST split. Page, domain, GitHub and
26
+ X-account points are pre-registered priors (not replayable on history) and are listed as such.
23
27
  --build-eval build that eval set from a recorder DB (read-only; no network; no URLs or names written).
24
28
  --horizon outcome horizon in seconds: ${HORIZONS.join(', ')} (default 3600 = 1h).
25
29
  --json print the full result object instead of the human table.
@@ -98,7 +102,7 @@ export function backtestCommand(argv, io) {
98
102
  io.stdout.write(BACKTEST_HELP + '\n');
99
103
  return 0;
100
104
  }
101
- if (opts.subject === 'skills')
105
+ if (opts.subject === 'skills' || opts.subject === 'larp-score')
102
106
  return skillsCommand(opts, io);
103
107
  const path = typeof opts.db === 'string' ? opts.db : (io.env.DEXTERM_DB_PATH || defaultDbPath(io.env));
104
108
  if (path === ':memory:') {
@@ -191,6 +195,13 @@ function skillsCommand(opts, io) {
191
195
  io.stderr.write(`dexterm backtest: ${file} is not a ${SKILL_EVAL_SCHEMA} file\n`);
192
196
  return 2;
193
197
  }
198
+ if (opts.subject === 'larp-score') {
199
+ const r = larpScoreBacktest(set);
200
+ if (typeof opts.report === 'string')
201
+ writeFileSync(opts.report, JSON.stringify(r, null, 1) + '\n');
202
+ io.stdout.write(opts.json ? JSON.stringify(r, null, 2) + '\n' : renderLarpScoreBacktestText(r));
203
+ return 0;
204
+ }
194
205
  let larpAfter = DEFAULT_LINK_RUBRIC, rugAfter = RUG_RULES_V1, tuned = null;
195
206
  if (opts.tune) {
196
207
  const train = set.rows.filter((r) => r.split === 'train');
@@ -1,4 +1,5 @@
1
- // dexterm — the price display mode (task-1366): show USD price or MARKET CAP on every screen and both charts.
1
+ // dexterm — the price display mode (task-1366): show USD price or MARKET CAP on every screen; task-1472: the chart
2
+ // Y axis (both charts) is its own setting, `display.chartAxis`, default MARKET CAP, toggled with `A`.
2
3
  //
3
4
  // A DISPLAY mode only. Market cap = price × supply, where the supply is what the data layer already reports
4
5
  // (the row's mcap / price at the latest tick: the "supply ratio"). Historical candles are scaled by the CURRENT
@@ -7,13 +8,16 @@
7
8
  // missing / zero), the screen falls back to price and SAYS so; it never invents a number.
8
9
  //
9
10
  // No network calls, nothing here is read by the signer, the caps, tickets, plans or the confirm gate.
10
- import { fmtMcap, fmtMcapBare, fmtPrice } from '../../tui/src/index.js';
11
- import { applyAndJournal, configPath, dextermHome, loadConfig, DEFAULT_PRICE_MODE, PRICE_MODES } from '../../custom/src/index.js';
12
- export { PRICE_MODES, DEFAULT_PRICE_MODE };
11
+ import { fmtMcap, fmtCompact, fmtPrice } from '../../tui/src/index.js';
12
+ import { applyAndJournal, configPath, dextermHome, loadConfig, DEFAULT_PRICE_MODE, PRICE_MODES, CHART_AXES, DEFAULT_CHART_AXIS, CHART_MARKERS, DEFAULT_CHART_MARKERS } from '../../custom/src/index.js';
13
+ import { knownSupply, pickBasis, PRICE_BASIS_ENV } from '../../data/src/basis.js';
14
+ export { PRICE_MODES, DEFAULT_PRICE_MODE, CHART_AXES, DEFAULT_CHART_AXIS, CHART_MARKERS, DEFAULT_CHART_MARKERS };
13
15
  /** Axis / caption label for an mcap chart: the history is scaled by today's supply, and says so. */
14
16
  export const MCAP_AXIS_LABEL = 'mcap (current supply)';
15
17
  /** Shown wherever mcap mode is on but a token's supply is unknown, so the number on screen is a price. */
16
18
  export const MCAP_FALLBACK_NOTE = 'supply unknown · showing price';
19
+ /** task-1472: the chart title when the Y axis wants market cap but the token's supply is unknown (it plots price). */
20
+ export const MCAP_UNAVAILABLE_LABEL = 'price (mcap unavailable)';
17
21
  /** Short per-cell marker for a price shown in an MCAP column (fallback). */
18
22
  export const FALLBACK_MARK = 'ᵖ';
19
23
  export function isPriceMode(v) { return PRICE_MODES.includes(v); }
@@ -78,14 +82,24 @@ export function fallbackCount(rows, get) {
78
82
  export function fallbackCaption(n) {
79
83
  return n > 0 ? `${FALLBACK_MARK} ${n} price${n > 1 ? 's' : ''} (supply unknown)` : null;
80
84
  }
81
- /** The chart scale for a token: mcap mode with a known supply scales by the CURRENT supply ratio, else prices (+ a note). */
85
+ /**
86
+ * The chart scale for a token: an mcap axis with a known supply scales by the CURRENT supply ratio (labels in the shared
87
+ * compact k/M/B formatter), else prices (+ `price (mcap unavailable)`). task-1472: the charts pass the chart axis
88
+ * (chartAxisOf, default mcap); the token header still passes the table price mode.
89
+ */
82
90
  export function chartMode(mode, price, mcap) {
83
91
  if (mode !== 'mcap')
84
92
  return { scale: null, axisFmt: undefined, kind: 'price', label: null };
85
93
  const ratio = supplyRatio(price, mcap);
86
94
  if (ratio === null)
87
- return { scale: null, axisFmt: undefined, kind: 'price', label: MCAP_FALLBACK_NOTE };
88
- return { scale: ratio, axisFmt: fmtMcapBare, kind: 'mcap', label: MCAP_AXIS_LABEL };
95
+ return { scale: null, axisFmt: undefined, kind: 'price', label: MCAP_UNAVAILABLE_LABEL };
96
+ return { scale: ratio, axisFmt: fmtCompact, kind: 'mcap', label: MCAP_AXIS_LABEL };
97
+ }
98
+ /** task-1472: the chart box title: `WIF · MCAP (current supply) · 1h`, `WIF/USD · 1h`, or `WIF/USD · price (mcap unavailable) · 1h`. */
99
+ export function chartTitle(symbol, interval, cm, quote = 'USD') {
100
+ if (cm.kind === 'mcap')
101
+ return `${symbol} · MCAP ${MCAP_AXIS_LABEL.replace(/^mcap /, '')} · ${interval}`;
102
+ return cm.label ? `${symbol}/${quote} · ${cm.label} · ${interval}` : `${symbol}/${quote} · ${interval}`;
89
103
  }
90
104
  /**
91
105
  * One plan level with BOTH numbers, in the order the mode prefers: mcap mode `mc ≤ $300K ($0.0003)`, price mode
@@ -129,29 +143,65 @@ export function positionPriceCells(mode, supply, avgUsd, priceUsd, avgText, pric
129
143
  const mark = mode === 'mcap' ? FALLBACK_MARK : '';
130
144
  return { avg: { label: 'AVG ENTRY', value: avgText === '—' ? avgText : avgText + mark }, price: { label: 'PRICE', value: priceText === '—' ? priceText : priceText + mark } };
131
145
  }
132
- /** The mode in effect: the state's (set from config, a workspace or `$`), default price. */
146
+ /**
147
+ * task-1537: the known supply for a coin the app is showing: the open token view's (mcap ÷ price at its latest tick),
148
+ * else its screener row's, else pump.fun's fixed 1B (the PnL card's rule, @dexterm/data/basis knownSupply). Never
149
+ * guessed: null means the caller shows the price and marks it.
150
+ */
151
+ export function supplyForMint(state, mint) {
152
+ if (!mint)
153
+ return null;
154
+ const v = state.live?.token?.view;
155
+ if (v && v.mint === mint) {
156
+ const r = supplyRatio(v.price, v.mcap);
157
+ if (r !== null)
158
+ return r;
159
+ }
160
+ const row = state.screener?.rows.find((x) => x.mint === mint);
161
+ if (row) {
162
+ const r = supplyRatio(row.price, row.mcap);
163
+ if (r !== null)
164
+ return r;
165
+ }
166
+ return knownSupply({ mint, launchpad: row?.launchpad ?? (v && v.mint === mint ? v.launchpad : null) })?.tokens ?? null;
167
+ }
168
+ /**
169
+ * task-1537: one more price LEVEL in a row (a stop, a target, a fill, a tape trade): its market cap at the given supply
170
+ * in mcap mode, else the price (marked ᵖ when mcap mode had no supply). Display only.
171
+ */
172
+ export function levelCell(mode, supply, usd) {
173
+ if (usd === null || usd === undefined || !Number.isFinite(usd))
174
+ return '—';
175
+ if (mode === 'mcap' && supply != null && supply > 0)
176
+ return fmtMcap(usd * supply);
177
+ return fmtPrice(usd) + (mode === 'mcap' ? FALLBACK_MARK : '');
178
+ }
179
+ /** The mode in effect: the state's (set from config, a workspace, `$` or a one-run override), default MARKET CAP (task-1537). */
133
180
  export function priceModeOf(state) {
134
- return state?.priceMode === 'mcap' ? 'mcap' : 'price';
181
+ return state?.priceMode === 'price' ? 'price' : 'mcap';
135
182
  }
136
- /** The mode a run starts in: config.display.priceMode, else price. */
137
- export function configPriceMode(cfg) {
138
- const m = cfg?.display?.priceMode;
139
- return isPriceMode(m) ? m : DEFAULT_PRICE_MODE;
183
+ /**
184
+ * The mode a run starts in: the one-run override (`DEXTERM_PRICE_BASIS=price|mcap`, which `--price` / `--mcap` /
185
+ * `--price-mode` also set), else config.display.priceMode, else market cap (task-1537: @dexterm/data/basis pickBasis).
186
+ */
187
+ export function configPriceMode(cfg, env) {
188
+ return pickBasis(cfg?.display?.priceMode, env);
140
189
  }
141
190
  /**
142
- * `$`: flip the mode and persist it to config.display.priceMode through the journal (actor user, so `undo` works).
143
- * Returns the notice for the toast. Persistence failure keeps the new mode for this run and says why.
191
+ * `$` (and `/display mcap|price` in the chat box, task-1537): set the mode (`next` absent = flip) and persist it to
192
+ * config.display.priceMode through the journal (actor user, so `undo` works). Returns the notice for the toast.
193
+ * Persistence failure keeps the new mode for this run and says why.
144
194
  */
145
- export function togglePriceMode(state) {
146
- const next = priceModeOf(state) === 'mcap' ? 'price' : 'mcap';
147
- state.priceMode = next;
148
- const what = next === 'mcap' ? `showing MARKET CAP · charts: ${MCAP_AXIS_LABEL}` : 'showing USD PRICE';
195
+ export function setPriceMode(state, next, why = '$') {
196
+ const mode = next ?? (priceModeOf(state) === 'mcap' ? 'price' : 'mcap');
197
+ state.priceMode = mode;
198
+ const what = mode === 'mcap' ? 'showing MARKET CAP' : 'showing USD PRICE'; // task-1472: the charts follow A, not $
149
199
  const ui = state.custom;
150
200
  if (!ui)
151
201
  return `${what} (not saved: no config on this run)`;
152
202
  try {
153
- const op = ui.config.display ? { op: 'add', path: '/display/priceMode', value: next } : { op: 'add', path: '/display', value: { priceMode: next } };
154
- const { config } = applyAndJournal(ui.home, [op], { actor: 'user', why: `$ price mode ${next}`, now: state.now.getTime() });
203
+ const op = ui.config.display ? { op: 'add', path: '/display/priceMode', value: mode } : { op: 'add', path: '/display', value: { priceMode: mode } };
204
+ const { config } = applyAndJournal(ui.home, [op], { actor: 'user', why: `${why} price mode ${mode}`, now: state.now.getTime() });
155
205
  ui.config = config;
156
206
  return `${what} · saved ($ to switch back)`;
157
207
  }
@@ -159,7 +209,112 @@ export function togglePriceMode(state) {
159
209
  return `${what} (not saved: ${e.message})`;
160
210
  }
161
211
  }
162
- export const DISPLAY_USAGE = 'usage: dexterm display [price|mcap] show or set display.priceMode in ~/.dexterm/config.json ($ in the app toggles it)';
212
+ /** `$`: flip the mode and persist it (see setPriceMode). */
213
+ export function togglePriceMode(state) { return setPriceMode(state); }
214
+ /**
215
+ * task-1537: the chat box command for the price basis, never sent to a model: `/display` (show), `/display mcap|price`,
216
+ * `/basis mcap|price`, `/set basis mcap|price` (also `/set priceMode …`). null = not this command.
217
+ */
218
+ export function parseDisplayCommand(q) {
219
+ const w = q.trim().replace(/^\//, '').split(/\s+/).filter(Boolean).map((x) => x.toLowerCase());
220
+ let arg;
221
+ if (w[0] === 'display' || w[0] === 'basis') {
222
+ if (w[1] === 'markers')
223
+ return null;
224
+ arg = w[1];
225
+ }
226
+ else if (w[0] === 'set' && (w[1] === 'basis' || w[1] === 'pricemode' || w[1] === 'price-basis' || w[1] === 'display.pricemode'))
227
+ arg = w[2];
228
+ else
229
+ return null;
230
+ if (arg === undefined)
231
+ return { show: true };
232
+ return isPriceMode(arg) ? { mode: arg } : { error: `/display expects mcap or price, got ${JSON.stringify(arg.slice(0, 20))}` };
233
+ }
234
+ /** The toast for `/display` with no argument. */
235
+ export function priceModeNotice(state) {
236
+ return priceModeOf(state) === 'mcap'
237
+ ? 'price basis: MARKET CAP (default) · coins with no known supply show price ᵖ · /display price or $ to switch'
238
+ : 'price basis: USD PRICE · /display mcap or $ to switch back to market cap';
239
+ }
240
+ /**
241
+ * task-1537: the one-run basis flags, accepted before any subcommand (`dexterm --price positions`, `dexterm autotrade
242
+ * list --mcap`): `--price` / `--mcap` are removed from argv and set DEXTERM_PRICE_BASIS in `env` for this process (so
243
+ * child agents and every CLI text follow it); nothing is saved. Returns argv without them.
244
+ */
245
+ export function takeBasisFlags(argv, env) {
246
+ const out = [];
247
+ for (const a of argv) {
248
+ if (a === '--price' || a === '--mcap')
249
+ env[PRICE_BASIS_ENV] = a.slice(2);
250
+ else
251
+ out.push(a);
252
+ }
253
+ return out;
254
+ }
255
+ export function isChartAxis(v) { return CHART_AXES.includes(v); }
256
+ /** task-1472: the chart Y axis in effect: the state's (from config or `A`), default MARKET CAP. */
257
+ export function chartAxisOf(state) {
258
+ return state?.chartAxis === 'price' ? 'price' : 'mcap';
259
+ }
260
+ /** task-1472: the chart axis a run starts with: config.display.chartAxis, else mcap (also for configs written before it). */
261
+ export function configChartAxis(cfg) {
262
+ const a = cfg?.display?.chartAxis;
263
+ return isChartAxis(a) ? a : DEFAULT_CHART_AXIS;
264
+ }
265
+ /**
266
+ * task-1472: set the chart Y axis (both chart surfaces) and persist it to config.display.chartAxis through the journal
267
+ * (actor user, so `undo` works). `next` absent = flip. Returns the toast text; a save failure keeps it for this run.
268
+ */
269
+ export function setChartAxis(state, next) {
270
+ const axis = next ?? (chartAxisOf(state) === 'mcap' ? 'price' : 'mcap');
271
+ state.chartAxis = axis;
272
+ const what = axis === 'mcap' ? 'chart Y axis: MARKET CAP' : 'chart Y axis: PRICE';
273
+ const ui = state.custom;
274
+ if (!ui)
275
+ return `${what} (not saved: no config on this run)`;
276
+ try {
277
+ const op = ui.config.display ? { op: 'add', path: '/display/chartAxis', value: axis } : { op: 'add', path: '/display', value: { chartAxis: axis } };
278
+ const { config } = applyAndJournal(ui.home, [op], { actor: 'user', why: `A chart axis ${axis}`, now: state.now.getTime() });
279
+ ui.config = config;
280
+ return `${what} · saved (A to switch)`;
281
+ }
282
+ catch (e) {
283
+ return `${what} (not saved: ${e.message})`;
284
+ }
285
+ }
286
+ export function isChartMarkers(v) { return CHART_MARKERS.includes(v); }
287
+ /** task-1483: are the BUY / SELL markers on (both charts)? Default on; only an explicit 'off' hides them. */
288
+ export function chartMarkersOn(state) {
289
+ return state?.chartMarkers !== 'off';
290
+ }
291
+ /** task-1483: the markers setting a run starts with: config.display.chartMarkers, else on. */
292
+ export function configChartMarkers(cfg) {
293
+ const m = cfg?.display?.chartMarkers;
294
+ return isChartMarkers(m) ? m : DEFAULT_CHART_MARKERS;
295
+ }
296
+ /**
297
+ * task-1483: show / hide the chart BUY / SELL markers (both chart surfaces) and persist config.display.chartMarkers through
298
+ * the journal (actor user, so `undo` works). `next` absent = flip. Returns the toast text. Display only.
299
+ */
300
+ export function setChartMarkers(state, next) {
301
+ const v = next ?? (chartMarkersOn(state) ? 'off' : 'on');
302
+ state.chartMarkers = v;
303
+ const what = v === 'on' ? 'chart BUY/SELL markers: ON' : 'chart BUY/SELL markers: OFF';
304
+ const ui = state.custom;
305
+ if (!ui)
306
+ return `${what} (not saved: no config on this run)`;
307
+ try {
308
+ const op = ui.config.display ? { op: 'add', path: '/display/chartMarkers', value: v } : { op: 'add', path: '/display', value: { chartMarkers: v } };
309
+ const { config } = applyAndJournal(ui.home, [op], { actor: 'user', why: `chart markers ${v}`, now: state.now.getTime() });
310
+ ui.config = config;
311
+ return `${what} · saved`;
312
+ }
313
+ catch (e) {
314
+ return `${what} (not saved: ${e.message})`;
315
+ }
316
+ }
317
+ export const DISPLAY_USAGE = 'usage: dexterm display [price|mcap] show or set display.priceMode in ~/.dexterm/config.json ($ in the app toggles it)\n dexterm display markers [on|off] show or set display.chartMarkers (BUY/SELL markers on both charts)';
163
318
  /** `dexterm display [price|mcap]`: print the saved price display mode, or set it (journaled, actor user). No network. */
164
319
  export function displayCommand(argv, io) {
165
320
  const home = dextermHome(io.env);
@@ -171,7 +326,37 @@ export function displayCommand(argv, io) {
171
326
  return 1;
172
327
  }
173
328
  const m = configPriceMode(loaded.config);
174
- io.stdout.write(`display.priceMode = ${m}${m === 'mcap' ? ` (tables show MCAP; charts: ${MCAP_AXIS_LABEL}; tokens without a supply fall back to price)` : ' (USD price per token)'}\n`);
329
+ io.stdout.write(`display.priceMode = ${m}${m === 'mcap' ? ' (tables show MCAP; tokens without a supply fall back to price)' : ' (USD price per token)'}\n`);
330
+ const a = configChartAxis(loaded.config);
331
+ io.stdout.write(`display.chartAxis = ${a}${a === 'mcap' ? ` (charts: ${MCAP_AXIS_LABEL}; A switches)` : ' (charts plot USD price; A switches)'}\n`);
332
+ const mk = configChartMarkers(loaded.config);
333
+ io.stdout.write(`display.chartMarkers = ${mk}${mk === 'on' ? ' (charts mark your paper and live fills; dexterm display markers off hides them)' : ' (no fill markers on the charts)'}\n`);
334
+ return 0;
335
+ }
336
+ // task-1483: `dexterm display markers [on|off]`
337
+ if (arg === 'markers') {
338
+ const v = argv[1];
339
+ if (v === undefined) {
340
+ if (!loaded.ok) {
341
+ io.stderr.write(`dexterm display: ${loaded.errors[0]}\n`);
342
+ return 1;
343
+ }
344
+ io.stdout.write(`display.chartMarkers = ${configChartMarkers(loaded.config)}\n`);
345
+ return 0;
346
+ }
347
+ if (!isChartMarkers(v)) {
348
+ io.stderr.write(`dexterm display markers: expected on or off, got ${JSON.stringify(v.slice(0, 20))}\n${DISPLAY_USAGE}\n`);
349
+ return 2;
350
+ }
351
+ try {
352
+ const op = loaded.config.display ? { op: 'add', path: '/display/chartMarkers', value: v } : { op: 'add', path: '/display', value: { chartMarkers: v } };
353
+ applyAndJournal(home, [op], { actor: 'user', why: `dexterm display markers ${v}` });
354
+ }
355
+ catch (e) {
356
+ io.stderr.write(`dexterm display: ${e.message}\n`);
357
+ return 1;
358
+ }
359
+ io.stdout.write(`display.chartMarkers = ${v} (saved to ${configPath(home)})\n`);
175
360
  return 0;
176
361
  }
177
362
  if (!isPriceMode(arg)) {
@@ -18,6 +18,7 @@ import { SayTts, voiceDoctor, resolveVoice, WHISPER_MODEL, resolvePiperRuntime,
18
18
  import { loadConfig, dextermHome } from '../../custom/src/index.js';
19
19
  import { kbStore, skillStore } from "./kb-skill-cmd.js";
20
20
  import { analystCliOnPath, CODEX_MIN_VERSION, parseEngineChoice, resolveEngine, versionAtLeast } from "./analyst/codex.js";
21
+ import { OllamaClient, SUGGESTED_MODELS, SURFACES, belowBar, effectiveRestriction, engineChoiceFor, loadAiConfig, ollamaSettings, pickModel, probeModel, remoteHostWarning } from '../../mcp/src/engine/index.js';
21
22
  /** The minimum Node that runs dexterm (type-stripping of the .ts entry needs 22.18). */
22
23
  export const MIN_NODE = [22, 18, 0];
23
24
  /** Cheap PATH lookup (no spawn). Windows (task-1423): PATH is `;`-separated and commands carry an extension
@@ -142,6 +143,18 @@ export async function claudeProbe(timeoutMs = 4000, platform = process.platform,
142
143
  }
143
144
  });
144
145
  }
146
+ /** Default Ollama facts: ai.json + a short probe of the configured host (127.0.0.1 by default). Never throws. */
147
+ export async function ollamaFacts(env = process.env) {
148
+ const c = loadAiConfig(env).config;
149
+ const set = ollamaSettings(c, env);
150
+ const client = new OllamaClient({ host: set.host, metaTimeoutMs: 2500 });
151
+ const probe = await probeModel(client, set.model, { numCtx: set.numCtx });
152
+ if (!probe.model && probe.models.length)
153
+ probe.model = null;
154
+ const surfaces = SURFACES.filter((sf) => engineChoiceFor(sf, c, env) === 'ollama');
155
+ const eff = effectiveRestriction(c, set.model ?? pickModel(probe.models), env);
156
+ return { probe, setUp: !!set.model || surfaces.length > 0, surfaces, level: eff.level, note: eff.note, hostWarning: remoteHostWarning(set.host) };
157
+ }
145
158
  /**
146
159
  * Default codex probe (0.1.5): PATH (spawnable form only), then `codex --version` and `codex login status`. The
147
160
  * status command is the user's own CLI reporting on its own login; dexterm never reads the credential itself.
@@ -190,6 +203,7 @@ export function defaultDeps(env = process.env, isTTY = process.stdout.isTTY ===
190
203
  platform: process.platform,
191
204
  claude: () => claudeProbe(),
192
205
  codex: () => codexProbe(4000, env),
206
+ ollama: () => ollamaFacts(env),
193
207
  analystEngine: env.DEXTERM_ANALYST_ENGINE ?? loadConfig(dextermHome(env)).config.analyst?.engine ?? null,
194
208
  probe: (url) => livingProbe(url),
195
209
  checkWritable: writableProbe,
@@ -262,7 +276,16 @@ export async function runDoctor(deps) {
262
276
  // 0.1.5: codex is the optional second engine; a missing claude is fine when codex can run the analyst.
263
277
  const codex = deps.codex ? await deps.codex() : null;
264
278
  const codexUsable = codex?.state === 'present';
265
- if (claude === 'missing' && codexUsable) {
279
+ // task-1543: a reachable Ollama with a pulled model can run the analyst too (a free local engine).
280
+ const ol = deps.ollama ? await deps.ollama().catch(() => null) : null;
281
+ const ollamaUsable = !!ol && ol.probe.reachable && (ol.probe.model ? ol.probe.present : ol.probe.models.length > 0);
282
+ if (claude === 'missing' && !codexUsable && ollamaUsable) {
283
+ checks.push({
284
+ name: 'Claude CLI', status: 'pass',
285
+ detail: 'not found on PATH (optional now): the analyst runs on your local Ollama model instead',
286
+ });
287
+ }
288
+ else if (claude === 'missing' && codexUsable) {
266
289
  checks.push({
267
290
  name: 'Claude CLI', status: 'pass',
268
291
  detail: 'not found on PATH (optional now): the analyst runs on your codex CLI instead',
@@ -272,7 +295,7 @@ export async function runDoctor(deps) {
272
295
  checks.push({
273
296
  name: 'Claude CLI', status: 'warn',
274
297
  detail: 'not found on PATH; the analyst (a) is disabled, the rest of dexterm works',
275
- fix: 'Install Claude Code (https://claude.com/claude-code) and run `claude` once to log in, or use Codex: `npm i -g @openai/codex && codex login`.',
298
+ fix: 'Set up an AI backend: install Claude Code (https://claude.com/claude-code) and run `claude` once to log in, or Codex (`npm i -g @openai/codex && codex login`), or a free local model (install Ollama from https://ollama.com/download, `ollama pull qwen3:8b`, `dexterm ai engine ollama`).',
276
299
  });
277
300
  }
278
301
  else {
@@ -284,7 +307,7 @@ export async function runDoctor(deps) {
284
307
  // 3b. Codex CLI (0.1.5): optional second analyst engine, the user's own codex login. Read-only lock needs >= CODEX_MIN_VERSION.
285
308
  if (codex) {
286
309
  const choice = parseEngineChoice(deps.analystEngine) ?? 'auto';
287
- const engine = resolveEngine(choice, (b) => b === 'claude' ? claude !== 'missing' : codexUsable);
310
+ const engine = resolveEngine(choice, (b) => b === 'claude' ? claude !== 'missing' : b === 'codex' ? codexUsable : ollamaUsable && !!ol?.setUp);
288
311
  const eng = `analyst engine: ${engine}${choice === 'auto' ? ' (auto)' : ''}`;
289
312
  if (codex.state === 'missing') {
290
313
  checks.push({ name: 'Codex CLI', status: engine === 'codex' ? 'warn' : 'pass', detail: `not installed (optional second analyst engine) · ${eng}`, ...(engine === 'codex' ? { fix: 'npm i -g @openai/codex && codex login, or set analyst.engine to claude' } : {}) });
@@ -299,6 +322,9 @@ export async function runDoctor(deps) {
299
322
  checks.push({ name: 'Codex CLI', status: 'pass', detail: `found${codex.version ? ` (codex-cli ${codex.version})` : ''}${codex.loggedIn ? ', logged in' : ''}; runs the analyst read-only on your own codex login (/engine codex) · ${eng}` });
300
323
  }
301
324
  }
325
+ // 3c. Local engine (task-1543): the user's own Ollama on this machine, the model, tool calling, context, profile.
326
+ if (ol)
327
+ checks.push(ollamaCheck(ol, claude !== 'missing' || codexUsable));
302
328
  // 4b. Login with X (optional, task-1357): the user's own X app + login unlock X posts in the SOCIAL panel / TRENDING.
303
329
  {
304
330
  const xs = new XTokenStore({ env: deps.env });
@@ -445,3 +471,36 @@ export function renderDoctor(result, opts = {}) {
445
471
  lines.push(paint(`${fails} check${fails === 1 ? '' : 's'} failed — fix the ✗ lines above, then re-run \`dexterm doctor\`.`, color ? ANSI.fail : ''));
446
472
  return lines.join('\n');
447
473
  }
474
+ /**
475
+ * The Ollama line (task-1543). Optional while claude/codex can run the analyst; a warning with the 2-minute
476
+ * setup when nothing can, or when the user chose ollama and it is not ready.
477
+ */
478
+ export function ollamaCheck(o, otherEngine) {
479
+ const p = o.probe;
480
+ const pull = `ollama pull ${SUGGESTED_MODELS[0].name}`;
481
+ const setup = `Install Ollama (https://ollama.com/download) and open it, then \`${pull}\` and \`dexterm ai engine ollama\` (\`dexterm ai model ${SUGGESTED_MODELS[0].name}\`).`;
482
+ const used = o.surfaces.length ? ` · runs: ${o.surfaces.join(', ')}` : '';
483
+ const prof = ` · profile ${o.level}${o.note ? ` (${o.note})` : ''}`;
484
+ const remote = o.hostWarning ? ` · WARNING ${o.hostWarning}` : '';
485
+ if (!p.reachable) {
486
+ // task-1551: a redirect is refused before anything is sent on; say so, whatever the setup state.
487
+ if (p.redirect)
488
+ return { name: 'Ollama (local AI)', status: 'warn', detail: `${p.host} answered with a redirect: refused, nothing was sent on${used}${remote}`, fix: 'dexterm never follows a redirect for the local engine (it would send your prompt to another host). Point it at the Ollama server itself with `dexterm ai host <host:port>` (or DEXTERM_OLLAMA_HOST), then re-run `dexterm doctor`.' };
489
+ if (!o.setUp)
490
+ return otherEngine
491
+ ? { name: 'Ollama (local AI)', status: 'pass', detail: 'not set up (optional free local engine; no login, no key, nothing leaves this machine)' }
492
+ : { name: 'Ollama (local AI)', status: 'warn', detail: 'no AI engine on this machine yet: a free local model works without any login or key', fix: setup };
493
+ return { name: 'Ollama (local AI)', status: 'warn', detail: `not reachable at ${p.host}${used}${remote}`, fix: `Start Ollama (open the app, or run \`ollama serve\`), then re-run \`dexterm doctor\`. Not installed? ${setup}` };
494
+ }
495
+ if (!p.model) {
496
+ const pick = pickModel(p.models);
497
+ return { name: 'Ollama (local AI)', status: o.setUp || !otherEngine ? 'warn' : 'pass', detail: `Ollama ${p.version ?? ''} running · pulled: ${p.models.slice(0, 5).join(', ') || 'none'} · no model chosen${used}${remote}`, ...(o.setUp || !otherEngine ? { fix: pick ? `dexterm ai model ${pick}` : `${pull} && dexterm ai model ${SUGGESTED_MODELS[0].name}` } : {}) };
498
+ }
499
+ if (!p.present)
500
+ return { name: 'Ollama (local AI)', status: 'warn', detail: `${p.model} is not pulled on ${p.host}${used}${remote}`, fix: `ollama pull ${p.model}` };
501
+ const warns = belowBar(o.level, p);
502
+ const facts = `${p.model} · tools ${p.tools === null ? '?' : p.tools ? 'yes' : 'no'} · context ${p.contextLength ?? '?'}`;
503
+ if (warns.length || o.hostWarning)
504
+ return { name: 'Ollama (local AI)', status: 'warn', detail: `${facts}${used}${prof}${remote}${warns.length ? ` · ${warns[0]}` : ''}`, fix: warns.length ? `\`dexterm ai probe --json\` checks it in detail; pull a stronger tool-capable model (e.g. ${pull}) or lower the profile (\`dexterm ai restrictions observe\`).` : 'Point dexterm at this machine: dexterm ai host 127.0.0.1' };
505
+ return { name: 'Ollama (local AI)', status: 'pass', detail: `${facts} · ${p.local ? 'local' : 'remote'} · $0${used}${prof}` };
506
+ }
@@ -12,6 +12,7 @@ import { mkdirSync, writeFileSync } from 'node:fs';
12
12
  import { join } from 'node:path';
13
13
  import { Canvas, rasterizeCanvas, fmtUsd, fmtPrice, fmtPct } from '../../tui/src/index.js';
14
14
  import { encodePng } from '../../data/src/index.js';
15
+ import { priceModeOf } from "./display.js";
15
16
  import { dextermHome } from "./boot-state.js";
16
17
  import { cleanText } from "./screener/rows.js";
17
18
  import { rugP, fmtRugP, RUG_MODEL_LABEL } from "./screener/rug.js";
@@ -152,8 +153,15 @@ const yesNo = (b) => (b === null ? 'unknown' : b ? 'ENABLED' : 'revoked');
152
153
  export function tokenReport(state, v, now) {
153
154
  const L = [];
154
155
  L.push(`coin $${cleanText(v.symbol, 16)}${v.name ? ` · ${cleanText(v.name, 40)}` : ''} · ${v.launchpad}`);
155
- L.push(`price ${fmtPrice(v.price)} 5m ${fmtPct(v.chg.m5)} 1h ${fmtPct(v.chg.h1)} 6h ${fmtPct(v.chg.h6)} 24h ${fmtPct(v.chg.h24)}`);
156
- L.push(`market cap ${fmtUsd(v.mcap)}${v.mcapFlagged ? ' (flagged)' : ''} liquidity ${fmtUsd(v.liq)} vol 24h ${fmtUsd(v.vol24)}`);
156
+ const moves = `5m ${fmtPct(v.chg.m5)} 1h ${fmtPct(v.chg.h1)} 6h ${fmtPct(v.chg.h6)} 24h ${fmtPct(v.chg.h24)}`;
157
+ if (priceModeOf(state) === 'mcap' && v.mcap !== null) { // task-1537: the market cap leads by default; both numbers stay
158
+ L.push(`market cap ${fmtUsd(v.mcap)}${v.mcapFlagged ? ' (flagged)' : ''} price ${fmtPrice(v.price)} ${moves}`);
159
+ L.push(`liquidity ${fmtUsd(v.liq)} vol 24h ${fmtUsd(v.vol24)}`);
160
+ }
161
+ else {
162
+ L.push(`price ${fmtPrice(v.price)} ${moves}`);
163
+ L.push(`market cap ${fmtUsd(v.mcap)}${v.mcapFlagged ? ' (flagged)' : ''} liquidity ${fmtUsd(v.liq)} vol 24h ${fmtUsd(v.vol24)}`);
164
+ }
157
165
  L.push(`holders ${v.holders ?? '—'} top-10 ${v.top10 === null ? '—' : `${v.top10.toFixed(1)}%`} dev ${v.dev === null ? '—' : `${v.dev.toFixed(1)}%`}${v.holdersSample ? ` (${v.holdersSample})` : ''}`);
158
166
  L.push(`age ${v.ageMin === null ? '—' : fmtAge(v.ageMin * 60)}`);
159
167
  L.push(`authorities mint ${yesNo(v.mintAuth)} · freeze ${yesNo(v.freezeAuth)}${v.riskyExtensions.length ? ` · risky extensions: ${v.riskyExtensions.join(', ')}` : ''}`);
@@ -19,7 +19,7 @@ export { renderAnalyst, renderContextRail, renderCoinList } from "./screens/anal
19
19
  export { renderTicket } from "./screens/ticket.js";
20
20
  export { renderPositions } from "./screens/positions.js";
21
21
  export * from "./trade.js";
22
- export { TradeTicketLive, PositionsLive, LivePositions, CombinedPositions, POSITIONS_REFRESH_MS } from "./live/trade.js";
22
+ export { TradeTicketLive, PositionsLive, POSITIONS_REFRESH_MS } from "./live/trade.js";
23
23
  export { parseWalletCommand, WALLET_HELP } from "./wallet-command.js";
24
24
  export * from "./screener/filter.js";
25
25
  export * from "./screener/sort.js";