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,182 @@
1
+ // dexterm — the AUTOTRADE screen's key handling (`Q`, task-1508). The loop calls autotradeKey() first while the
2
+ // screen captures typed keys (an id / file line, a field value, the flatten confirm), and autotradeAction() for
3
+ // every resolved action while the screen is open. Both only change this screen's state and the user's own
4
+ // strategy files; nothing here reaches a wallet, a key, a mandate or the signer.
5
+ import { INPUT_MAX, backtestSubject, beginFieldEdit, beginImport, beginNew, commitInput, commitTyping, confirmKey, exportSelected, nextView, openEditor, reloadList, refreshRunner, revalidateTyping, runnerVerb, saveEditor, selectedEntry, startBacktest, startCompareBacktest, startSweep, toggleMark, undoEditor, } from "./autotrade-ui.js";
6
+ import { openReview, reviewKey } from "./autotrade-proposals.js";
7
+ import { journeyForward, journeyPromote, journeyStopForward, openJourney, refreshJourney } from "./autotrade-journey.js";
8
+ const PRINTABLE = (k) => (k.name === 'space' ? ' ' : k.name === 'char' && k.ch && !k.ctrl && !k.alt && !/[\u0000-\u001f\u007f]/.test(k.ch) ? k.ch : null);
9
+ /** A captured key (input line, field value or confirm). Returns true when the key was consumed. */
10
+ export function autotradeKey(ui, key) {
11
+ // task-1507: a chat proposal's review card owns the keyboard (y applies, a LOOSER edit needs a second y, n dismisses)
12
+ if (ui.review) {
13
+ ui.notice = reviewKey(ui, key);
14
+ if (!ui.review)
15
+ reloadList(ui);
16
+ return true;
17
+ }
18
+ if (ui.confirm) {
19
+ ui.notice = confirmKey(ui, key.name === 'char' && key.ch === 'y' && !key.ctrl && !key.alt);
20
+ return true;
21
+ }
22
+ if (ui.input) {
23
+ const inp = ui.input;
24
+ if (key.name === 'esc') {
25
+ ui.input = null;
26
+ ui.notice = null;
27
+ return true;
28
+ }
29
+ if (key.name === 'enter') {
30
+ ui.notice = commitInput(ui);
31
+ return true;
32
+ }
33
+ if (key.name === 'backspace') {
34
+ inp.text = inp.text.slice(0, -1);
35
+ return true;
36
+ }
37
+ if (key.ctrl && key.ch === 'u') {
38
+ inp.text = '';
39
+ return true;
40
+ }
41
+ const ch = PRINTABLE(key);
42
+ // an id is lowercase letters, digits and dashes only, so it can never carry a path
43
+ if (ch && (inp.kind === 'import' ? inp.text.length < INPUT_MAX : /^[a-z0-9-]$/.test(ch) && inp.text.length < 32))
44
+ inp.text += ch;
45
+ return true;
46
+ }
47
+ const ty = ui.view === 'editor' ? ui.editor?.typing : null;
48
+ if (ty) {
49
+ if (key.name === 'esc') {
50
+ ui.editor.typing = null;
51
+ ui.notice = null;
52
+ return true;
53
+ }
54
+ if (key.name === 'enter') {
55
+ ui.notice = commitTyping(ui);
56
+ return true;
57
+ }
58
+ if (key.name === 'backspace')
59
+ ty.text = ty.text.slice(0, -1);
60
+ else if (key.ctrl && key.ch === 'u')
61
+ ty.text = '';
62
+ else {
63
+ const ch = PRINTABLE(key);
64
+ if (ch && ty.text.length < INPUT_MAX)
65
+ ty.text += ch;
66
+ else
67
+ return true;
68
+ }
69
+ revalidateTyping(ui);
70
+ return true;
71
+ }
72
+ return false;
73
+ }
74
+ function move(ui, delta) {
75
+ if (ui.view === 'list')
76
+ ui.selected = Math.max(0, Math.min(ui.entries.length - 1, ui.selected + delta));
77
+ else if (ui.view === 'editor' && ui.editor)
78
+ ui.editor.selected = Math.max(0, Math.min(ui.editor.fields.length - 1, ui.editor.selected + delta));
79
+ else if (ui.view === 'compare' && ui.compare)
80
+ ui.compare.scroll = Math.max(0, ui.compare.scroll + delta);
81
+ }
82
+ const PAGE = 10;
83
+ /**
84
+ * One resolved action on the AUTOTRADE screen. Returns true when it was handled here (the loop then does
85
+ * nothing else with it); false lets the loop's own handling run (esc on the list pops the screen stack, `q`
86
+ * quits, the global screen keys still navigate away).
87
+ */
88
+ export function autotradeAction(ui, action) {
89
+ const say = (s) => { ui.notice = s ?? null; return true; };
90
+ const e = selectedEntry(ui);
91
+ switch (action) {
92
+ case 'move.down':
93
+ move(ui, 1);
94
+ return true;
95
+ case 'move.up':
96
+ move(ui, -1);
97
+ return true;
98
+ case 'move.pagedown':
99
+ move(ui, PAGE);
100
+ return true;
101
+ case 'move.pageup':
102
+ move(ui, -PAGE);
103
+ return true;
104
+ case 'move.top':
105
+ move(ui, -1e9);
106
+ return true;
107
+ case 'move.bottom':
108
+ move(ui, 1e9);
109
+ return true;
110
+ case 'back':
111
+ if (ui.view === 'list')
112
+ return false;
113
+ ui.view = 'list';
114
+ return say(null);
115
+ case 'autotrade.view':
116
+ nextView(ui);
117
+ if (ui.view === 'runner')
118
+ refreshRunner(ui);
119
+ return say(null);
120
+ case 'open':
121
+ case 'autotrade.edit':
122
+ if (ui.view === 'editor')
123
+ return say(beginFieldEdit(ui));
124
+ if (ui.view !== 'list')
125
+ return action === 'open' ? true : say('e edits from the strategies list');
126
+ return say(e ? openEditor(ui, e.id) : 'no strategy selected');
127
+ case 'autotrade.new': return say(ui.view === 'list' ? beginNew(ui, false) : 'n works on the strategies list (esc)');
128
+ case 'autotrade.dup': return say(ui.view === 'list' ? beginNew(ui, true) : 'd works on the strategies list (esc)');
129
+ case 'autotrade.import':
130
+ if (ui.view !== 'list')
131
+ return say('i works on the strategies list (esc)');
132
+ beginImport(ui);
133
+ return say(null);
134
+ case 'autotrade.export': return say(ui.view === 'list' ? exportSelected(ui) : 'x works on the strategies list (esc)');
135
+ case 'autotrade.compare': return say(ui.view === 'list' ? toggleMark(ui) : 'c marks strategies on the list (esc)');
136
+ case 'autotrade.save': return say(ui.view === 'editor' ? saveEditor(ui) : 's saves in the editor');
137
+ case 'autotrade.undo': return say(ui.view === 'editor' ? undoEditor(ui) : 'u undoes in the editor');
138
+ case 'autotrade.backtest': {
139
+ if (ui.view === 'journey' && ui.journey)
140
+ return say(startBacktest(ui, ui.journey.id));
141
+ if (ui.view === 'compare')
142
+ return say(startCompareBacktest(ui));
143
+ if (ui.view === 'editor' && ui.editor)
144
+ return say(`${startBacktest(ui, ui.editor.id)}${ui.editor.edits.length ? ' (the saved version; s saves your edits first)' : ''}`);
145
+ if (ui.view === 'backtest') {
146
+ const s = backtestSubject(ui);
147
+ return say(s ? startBacktest(ui, s.id) : 'no strategy selected');
148
+ }
149
+ return say(e ? startBacktest(ui, e.id) : 'no strategy selected');
150
+ }
151
+ case 'autotrade.sweep': {
152
+ const id = ui.view === 'editor' && ui.editor ? ui.editor.id : ui.view === 'backtest' ? backtestSubject(ui)?.id : e?.id;
153
+ return say(id ? startSweep(ui, id) : 'no strategy selected');
154
+ }
155
+ case 'autotrade.proposal': return say(ui.view === 'list' ? openReview(ui) || null : 'o reviews chat proposals on the strategies list (esc)');
156
+ // task-1647: the journey view
157
+ case 'autotrade.journey':
158
+ if (ui.view === 'journey') {
159
+ refreshJourney(ui, true);
160
+ return say(null);
161
+ }
162
+ return say(openJourney(ui, ui.view === 'editor' ? ui.editor?.id : ui.view === 'backtest' ? backtestSubject(ui)?.id : e?.id));
163
+ case 'autotrade.forward': return say(ui.view === 'journey' ? journeyForward(ui) : 'F starts a forward test on the journey view (J)');
164
+ case 'autotrade.forwardstop': return say(ui.view === 'journey' ? journeyStopForward(ui) : 'X stops a forward test on the journey view (J)');
165
+ case 'autotrade.promote': return say(ui.view === 'journey' ? journeyPromote(ui) : 'A reviews a promotion on the journey view (J)');
166
+ case 'autotrade.run':
167
+ ui.view = 'runner';
168
+ refreshRunner(ui);
169
+ reloadList(ui);
170
+ return say('starting and stopping a paper run ships with the runner (not in this build yet) · this view shows a runner as soon as one writes its status file');
171
+ case 'autotrade.kill':
172
+ refreshRunner(ui);
173
+ return say(runnerVerb(ui, 'kill'));
174
+ case 'autotrade.pause':
175
+ refreshRunner(ui);
176
+ return say(runnerVerb(ui, 'pause'));
177
+ case 'autotrade.flatten':
178
+ refreshRunner(ui);
179
+ return say(runnerVerb(ui, 'flatten'));
180
+ default: return false;
181
+ }
182
+ }
@@ -0,0 +1,123 @@
1
+ // dexterm — chat proposals on the AUTOTRADE screen (task-1507 AT-5, AUTOTRADE-SPEC §2a). PAPER ONLY.
2
+ //
3
+ // The analyst (or any MCP agent) can only PROPOSE a strategy edit: `strategy_propose_edit/new` write a proposal file
4
+ // and nothing else. This module is the ONLY path that applies one, and it runs only on the user's physical keys:
5
+ //
6
+ // o on the strategies list opens the diff card of the newest pending proposal (the selected strategy's first)
7
+ // y applies a tighter or neutral edit
8
+ // y on a LOOSER edit opens the "less safe" popup (every less-safe field named) and a SECOND y applies it
9
+ // n dismisses the proposal · esc (or any other key) closes the card and leaves it pending
10
+ //
11
+ // Applying re-checks everything from scratch (`checkProposal`: the base hash, the model deny-list on the result,
12
+ // the validator and a fresh risk delta: the stored riskDelta is never trusted), then writes through StrategyStore
13
+ // (a new version, one `.journal.jsonl` line naming the proposer, the proposal id, the ops and both hashes).
14
+ // The key loop feeds `reviewKey` decoded keyboard keys only; no voice, pipe or agent path reaches it.
15
+ import { applyOps, dextermHome } from '../../../custom/src/index.js';
16
+ import * as engine from '../../../autotrade/src/index.js';
17
+ import { ProposalFiles, checkProposal, proposalCardView } from '../../../mcp/src/index.js';
18
+ const ENGINE = { at: engine, applyOps };
19
+ /** Pending proposals as display cards, re-read at most once a second (the list view asks every frame). */
20
+ export function proposalSource(files, now = Date.now) {
21
+ let at = -Infinity;
22
+ let recs = [];
23
+ const pending = () => {
24
+ const t = now();
25
+ if (t - at >= 1000) {
26
+ try {
27
+ recs = files.list({ status: 'pending' });
28
+ }
29
+ catch {
30
+ recs = [];
31
+ }
32
+ at = t;
33
+ }
34
+ return recs;
35
+ };
36
+ return { pending, cards: () => pending().map(proposalCardView), invalidate: () => { at = -Infinity; } };
37
+ }
38
+ export const proposalFilesFor = (env = process.env) => new ProposalFiles(dextermHome(env));
39
+ const inputOf = (r) => ({ kind: r.kind, id: r.id, ops: r.ops, from: r.from, name: r.name, why: r.why });
40
+ /** Re-check a stored proposal against the strategy as it is NOW (stale when the strategy changed since). */
41
+ export function recheck(store, rec) {
42
+ const c = checkProposal(ENGINE, store, inputOf(rec));
43
+ if (c.ok && c.before.hash !== rec.beforeHash) {
44
+ return { ok: false, stage: 'input', errors: [{ path: `/${rec.id}`, msg: `${rec.id} changed since this proposal (it was made on ${rec.beforeHash}, it is ${c.before.hash} now): dismiss it with n and ask again` }], warnings: [] };
45
+ }
46
+ return c;
47
+ }
48
+ /** The keys a proposal needs: one for a tighter or neutral edit, two (the less-safe popup) for a looser one. */
49
+ export const keysNeeded = (c) => (c.ok && c.riskDelta === 'looser' ? 2 : 1);
50
+ /**
51
+ * Apply a proposal. `keys` must be the physical keys the user pressed on its card (`reviewKey` collects them);
52
+ * a looser edit needs two. Returns the toast line. Nothing else in the app calls the store with a proposal id.
53
+ */
54
+ export function applyProposal(store, files, rec, keys, now = Date.now()) {
55
+ if (rec.status !== 'pending')
56
+ return { ok: false, message: `proposal ${rec.proposalId} is already ${rec.status}` };
57
+ const c = recheck(store, rec);
58
+ if (!c.ok)
59
+ return { ok: false, message: `not applied: ${c.errors.map(engine.fmtIssue).join('; ')}` };
60
+ const yes = keys.filter((k) => k === 'y').length;
61
+ const need = keysNeeded(c);
62
+ if (yes < need)
63
+ return { ok: false, message: `not applied: a LOOSER edit needs a second keypress (${yes} of ${need})` };
64
+ const why = `${rec.why} · applied by keypress${need === 2 ? ' after the less-safe popup' : ''}`.slice(0, 300);
65
+ const w = rec.kind === 'edit'
66
+ ? store.patch(rec.id, c.effectiveOps, { actor: rec.actor, why, proposalId: rec.proposalId })
67
+ : store.create(c.afterRaw, { actor: rec.actor, why, from: rec.from, proposalId: rec.proposalId });
68
+ if (!w.ok)
69
+ return { ok: false, message: `not applied: ${w.errors.map(engine.fmtIssue).join('; ')}` };
70
+ if (w.strategy.hash !== c.after.hash)
71
+ return { ok: false, message: `applied, but the stored hash ${w.strategy.hash} differs from the proposal's ${c.after.hash}: check the journal` };
72
+ files.resolve(rec.proposalId, 'applied', { appliedVersion: w.strategy.version, keys: [...keys] }, now);
73
+ return { ok: true, message: `${rec.kind === 'new' ? 'created' : 'applied'} ${rec.id} v${w.strategy.version} (${c.riskDelta}) · journaled with ${rec.proposalId}` };
74
+ }
75
+ // ───────────────────────────── the card's keys (AutotradeUi) ─────────────────────────────
76
+ /** `o`: open the newest pending proposal (the selected strategy's first). Returns the notice. */
77
+ export function openReview(ui) {
78
+ const src = ui.deps.proposalSource;
79
+ if (!src)
80
+ return 'chat proposals are not available on this run';
81
+ src.invalidate();
82
+ const pending = src.pending();
83
+ if (!pending.length)
84
+ return 'no chat proposals · ask the analyst (a) to change a strategy; its diff card shows up here';
85
+ const sel = ui.entries[ui.selected]?.id;
86
+ const rec = pending.find((p) => p.id === sel) ?? pending[0];
87
+ ui.review = { rec, check: recheck(ui.deps.store, rec), stage: 'card', keys: [] };
88
+ return '';
89
+ }
90
+ /** A key while the card is open. Returns the notice (null keeps the card's own text). */
91
+ export function reviewKey(ui, key) {
92
+ const rv = ui.review;
93
+ if (!rv)
94
+ return null;
95
+ const ch = key.name === 'char' && !key.ctrl && !key.alt ? key.ch : null;
96
+ const src = ui.deps.proposalSource;
97
+ const files = ui.deps.proposalFiles;
98
+ if (ch === 'n' && files) {
99
+ files.resolve(rv.rec.proposalId, 'dismissed', {}, ui.deps.now());
100
+ ui.review = null;
101
+ src?.invalidate();
102
+ return `dismissed ${rv.rec.proposalId} (${rv.rec.id} unchanged)`;
103
+ }
104
+ if (ch !== 'y') {
105
+ ui.review = null;
106
+ return 'proposal left pending (o reopens it)';
107
+ }
108
+ if (!rv.check.ok)
109
+ return `cannot apply: ${rv.check.errors.map(engine.fmtIssue).join('; ')} · n dismisses it`;
110
+ rv.keys.push('y');
111
+ if (rv.check.riskDelta === 'looser' && rv.stage === 'card') {
112
+ rv.stage = 'less-safe';
113
+ return 'LESS SAFE: y again applies it · any other key cancels';
114
+ }
115
+ if (!files) {
116
+ ui.review = null;
117
+ return 'chat proposals are not available on this run';
118
+ }
119
+ const r = applyProposal(ui.deps.store, files, rv.rec, rv.keys, ui.deps.now());
120
+ ui.review = null;
121
+ src?.invalidate();
122
+ return r.message;
123
+ }