dexterm-cli 0.1.3 → 0.1.5

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 (259) hide show
  1. package/dist/packages/cli/assets/claude/analyst-system.md +2 -1
  2. package/dist/packages/cli/src/agent-paper.js +60 -0
  3. package/dist/packages/cli/src/analyst/backend.js +183 -0
  4. package/dist/packages/cli/src/analyst/codex.js +301 -0
  5. package/dist/packages/cli/src/analyst/session.js +9 -2
  6. package/dist/packages/cli/src/app-help-gen.js +18 -9
  7. package/dist/packages/cli/src/docs-kb-gen.js +228 -0
  8. package/dist/packages/cli/src/doctor.js +80 -9
  9. package/dist/packages/cli/src/index.js +1 -1
  10. package/dist/packages/cli/src/kb-skill-cmd.js +3 -0
  11. package/dist/packages/cli/src/larp-detected.js +209 -0
  12. package/dist/packages/cli/src/live/dev-history.js +99 -0
  13. package/dist/packages/cli/src/live/newpairs.js +12 -0
  14. package/dist/packages/cli/src/live/screens/token-live.js +11 -1
  15. package/dist/packages/cli/src/live/token.js +39 -1
  16. package/dist/packages/cli/src/main.js +260 -7
  17. package/dist/packages/cli/src/mcp-follow.js +255 -0
  18. package/dist/packages/cli/src/record-cmd.js +2 -0
  19. package/dist/packages/cli/src/rules.js +25 -2
  20. package/dist/packages/cli/src/screens/analyst-session.js +5 -3
  21. package/dist/packages/cli/src/screens/analyst.js +4 -3
  22. package/dist/packages/cli/src/spectate-cmd.js +14 -3
  23. package/dist/packages/cli/src/version.js +1 -1
  24. package/dist/packages/cli/src/x-cmd.js +11 -5
  25. package/dist/packages/custom/src/rules.js +2 -2
  26. package/dist/packages/custom/src/schema.js +5 -1
  27. package/dist/packages/data/src/fixtures.js +28 -6
  28. package/dist/packages/data/src/index.js +3 -0
  29. package/dist/packages/data/src/sources/jupiter.js +1 -0
  30. package/dist/packages/data/src/trade/agent/paper-desk.js +336 -0
  31. package/dist/packages/data/src/trade/agent/rendezvous.js +161 -0
  32. package/dist/packages/mcp/assets/kb/app-help/agent-paper-trade.md +38 -0
  33. package/dist/packages/mcp/assets/kb/app-help/ask-the-analyst.md +1 -1
  34. package/dist/packages/mcp/assets/kb/app-help/connect-an-agent.md +1 -1
  35. package/dist/packages/mcp/assets/kb/app-help/dev-history.md +32 -0
  36. package/dist/packages/mcp/assets/kb/app-help/paper-trade.md +1 -1
  37. package/dist/packages/mcp/assets/kb/app-help/screen-positions.md +4 -1
  38. package/dist/packages/mcp/assets/kb/app-help/screen-token.md +1 -0
  39. package/dist/packages/mcp/assets/kb/app-help/spectate-an-agent.md +4 -1
  40. package/dist/packages/mcp/assets/kb/app-help/use-codex-analyst.md +31 -0
  41. package/dist/packages/mcp/assets/kb/docs/docs-agents-agent-paper-trading.md +50 -0
  42. package/dist/packages/mcp/assets/kb/docs/docs-agents-capability-tiers-enforced-server-side.md +38 -0
  43. package/dist/packages/mcp/assets/kb/docs/docs-agents-directory-metadata-prepared-not-submitted.md +36 -0
  44. package/dist/packages/mcp/assets/kb/docs/docs-agents-install-in-one-command.md +51 -0
  45. package/dist/packages/mcp/assets/kb/docs/docs-agents-per-agent-mandates.md +35 -0
  46. package/dist/packages/mcp/assets/kb/docs/docs-agents-recipes.md +43 -0
  47. package/dist/packages/mcp/assets/kb/docs/docs-agents-red-team-coverage.md +30 -0
  48. package/dist/packages/mcp/assets/kb/docs/docs-agents-two-ways-to-connect.md +37 -0
  49. package/dist/packages/mcp/assets/kb/docs/docs-agents-untrusted-by-default.md +36 -0
  50. package/dist/packages/mcp/assets/kb/docs/docs-agents-watch-an-agent-work-spectator-view.md +35 -0
  51. package/dist/packages/mcp/assets/kb/docs/docs-agents.md +26 -0
  52. package/dist/packages/mcp/assets/kb/docs/docs-analyst-answer-style.md +35 -0
  53. package/dist/packages/mcp/assets/kb/docs/docs-analyst-if-claude-is-missing.md +25 -0
  54. package/dist/packages/mcp/assets/kb/docs/docs-analyst-it-knows-the-app.md +33 -0
  55. package/dist/packages/mcp/assets/kb/docs/docs-analyst-mcp-tools.md +33 -0
  56. package/dist/packages/mcp/assets/kb/docs/docs-analyst-plain-language-filters.md +25 -0
  57. package/dist/packages/mcp/assets/kb/docs/docs-analyst-skills.md +31 -0
  58. package/dist/packages/mcp/assets/kb/docs/docs-analyst-starting-a-run.md +33 -0
  59. package/dist/packages/mcp/assets/kb/docs/docs-analyst-use-codex-instead-of-claude.md +35 -0
  60. package/dist/packages/mcp/assets/kb/docs/docs-analyst-what-it-can-change-three-tiers.md +33 -0
  61. package/dist/packages/mcp/assets/kb/docs/docs-analyst-what-it-sees.md +26 -0
  62. package/dist/packages/mcp/assets/kb/docs/docs-analyst-what-the-analyst-can-never-do.md +31 -0
  63. package/dist/packages/mcp/assets/kb/docs/docs-analyst.md +23 -0
  64. package/dist/packages/mcp/assets/kb/docs/docs-beginners-1-start-dexterm.md +35 -0
  65. package/dist/packages/mcp/assets/kb/docs/docs-beginners-2-open-a-real-coin-by-contract-address.md +43 -0
  66. package/dist/packages/mcp/assets/kb/docs/docs-beginners-3-read-the-safety-panel.md +40 -0
  67. package/dist/packages/mcp/assets/kb/docs/docs-beginners-4-read-the-holder-panel.md +35 -0
  68. package/dist/packages/mcp/assets/kb/docs/docs-beginners-5-optionally-ask-the-analyst.md +39 -0
  69. package/dist/packages/mcp/assets/kb/docs/docs-beginners-6-export-or-share-what-you-see.md +34 -0
  70. package/dist/packages/mcp/assets/kb/docs/docs-beginners-7-quit-safely.md +34 -0
  71. package/dist/packages/mcp/assets/kb/docs/docs-beginners-before-any-experimental-trading.md +33 -0
  72. package/dist/packages/mcp/assets/kb/docs/docs-beginners-check-the-installation-with-doctor.md +38 -0
  73. package/dist/packages/mcp/assets/kb/docs/docs-beginners-choose-a-setup-path.md +30 -0
  74. package/dist/packages/mcp/assets/kb/docs/docs-beginners-common-mistakes-and-recovery.md +30 -0
  75. package/dist/packages/mcp/assets/kb/docs/docs-beginners-copy-and-paste-without-surprises.md +39 -0
  76. package/dist/packages/mcp/assets/kb/docs/docs-beginners-if-data-says-unavailable-stale-or-rate-limited.md +35 -0
  77. package/dist/packages/mcp/assets/kb/docs/docs-beginners-if-dexterm-says-command-not-found.md +36 -0
  78. package/dist/packages/mcp/assets/kb/docs/docs-beginners-if-optional-help-is-unavailable.md +33 -0
  79. package/dist/packages/mcp/assets/kb/docs/docs-beginners-if-paste-does-nothing-or-pastes-twice.md +35 -0
  80. package/dist/packages/mcp/assets/kb/docs/docs-beginners-if-the-screen-looks-broken.md +33 -0
  81. package/dist/packages/mcp/assets/kb/docs/docs-beginners-if-you-typed-the-wrong-thing.md +33 -0
  82. package/dist/packages/mcp/assets/kb/docs/docs-beginners-install-node-js-first.md +36 -0
  83. package/dist/packages/mcp/assets/kb/docs/docs-beginners-linux.md +30 -0
  84. package/dist/packages/mcp/assets/kb/docs/docs-beginners-macos-homebrew.md +46 -0
  85. package/dist/packages/mcp/assets/kb/docs/docs-beginners-macos-or-linux-npm.md +39 -0
  86. package/dist/packages/mcp/assets/kb/docs/docs-beginners-macos.md +30 -0
  87. package/dist/packages/mcp/assets/kb/docs/docs-beginners-open-the-terminal.md +29 -0
  88. package/dist/packages/mcp/assets/kb/docs/docs-beginners-reopen-dexterm-later.md +36 -0
  89. package/dist/packages/mcp/assets/kb/docs/docs-beginners-ten-minute-first-win.md +30 -0
  90. package/dist/packages/mcp/assets/kb/docs/docs-beginners-terminal-shell-prompt-command-output-and-path.md +40 -0
  91. package/dist/packages/mcp/assets/kb/docs/docs-beginners-where-to-go-next.md +32 -0
  92. package/dist/packages/mcp/assets/kb/docs/docs-beginners-windows-expectations.md +29 -0
  93. package/dist/packages/mcp/assets/kb/docs/docs-beginners-windows-powershell-experimental.md +39 -0
  94. package/dist/packages/mcp/assets/kb/docs/docs-beginners-windows.md +30 -0
  95. package/dist/packages/mcp/assets/kb/docs/docs-beginners.md +29 -0
  96. package/dist/packages/mcp/assets/kb/docs/docs-cli-dexterm-help.md +31 -0
  97. package/dist/packages/mcp/assets/kb/docs/docs-cli-filter-grammar.md +37 -0
  98. package/dist/packages/mcp/assets/kb/docs/docs-cli-flags.md +27 -0
  99. package/dist/packages/mcp/assets/kb/docs/docs-cli-invocations.md +43 -0
  100. package/dist/packages/mcp/assets/kb/docs/docs-cli-presets.md +26 -0
  101. package/dist/packages/mcp/assets/kb/docs/docs-cli-scan-commands.md +26 -0
  102. package/dist/packages/mcp/assets/kb/docs/docs-cli-sort-keys.md +27 -0
  103. package/dist/packages/mcp/assets/kb/docs/docs-cli-subcommands.md +26 -0
  104. package/dist/packages/mcp/assets/kb/docs/docs-cli.md +25 -0
  105. package/dist/packages/mcp/assets/kb/docs/docs-configuration-environment-variables.md +47 -0
  106. package/dist/packages/mcp/assets/kb/docs/docs-configuration-files-on-disk.md +41 -0
  107. package/dist/packages/mcp/assets/kb/docs/docs-configuration-headless-recorder-dexterm-record.md +44 -0
  108. package/dist/packages/mcp/assets/kb/docs/docs-configuration-history-recorder.md +33 -0
  109. package/dist/packages/mcp/assets/kb/docs/docs-configuration-packs.md +38 -0
  110. package/dist/packages/mcp/assets/kb/docs/docs-configuration-price-display-mode.md +35 -0
  111. package/dist/packages/mcp/assets/kb/docs/docs-configuration-push-alerts-and-dexterm-watch.md +45 -0
  112. package/dist/packages/mcp/assets/kb/docs/docs-configuration-rules-engine.md +37 -0
  113. package/dist/packages/mcp/assets/kb/docs/docs-configuration-the-analyst-s-launch.md +29 -0
  114. package/dist/packages/mcp/assets/kb/docs/docs-configuration-the-optional-free-rpc-key.md +42 -0
  115. package/dist/packages/mcp/assets/kb/docs/docs-configuration-themes-and-keymaps.md +29 -0
  116. package/dist/packages/mcp/assets/kb/docs/docs-configuration-themes-and-look.md +27 -0
  117. package/dist/packages/mcp/assets/kb/docs/docs-configuration-widgets.md +31 -0
  118. package/dist/packages/mcp/assets/kb/docs/docs-configuration-workspaces.md +30 -0
  119. package/dist/packages/mcp/assets/kb/docs/docs-configuration.md +25 -0
  120. package/dist/packages/mcp/assets/kb/docs/docs-copy-trading-stage-1-follow-a-wallet-see-what-it-does.md +51 -0
  121. package/dist/packages/mcp/assets/kb/docs/docs-copy-trading-stage-2-the-one-key-mirror-ticket-a-proposal.md +56 -0
  122. package/dist/packages/mcp/assets/kb/docs/docs-copy-trading-stage-3-capped-auto-mirror-default-off-less.md +47 -0
  123. package/dist/packages/mcp/assets/kb/docs/docs-copy-trading-what-is-proven-what-is-not.md +36 -0
  124. package/dist/packages/mcp/assets/kb/docs/docs-copy-trading.md +31 -0
  125. package/dist/packages/mcp/assets/kb/docs/docs-data-sources-cache.md +32 -0
  126. package/dist/packages/mcp/assets/kb/docs/docs-data-sources-health-registry.md +29 -0
  127. package/dist/packages/mcp/assets/kb/docs/docs-data-sources-rate-limits-and-pacing.md +32 -0
  128. package/dist/packages/mcp/assets/kb/docs/docs-data-sources-request-budget-meter.md +30 -0
  129. package/dist/packages/mcp/assets/kb/docs/docs-data-sources-sources.md +47 -0
  130. package/dist/packages/mcp/assets/kb/docs/docs-data-sources-the-helius-credit-meter.md +30 -0
  131. package/dist/packages/mcp/assets/kb/docs/docs-data-sources.md +27 -0
  132. package/dist/packages/mcp/assets/kb/docs/docs-getting-started-dexterm-doctor.md +33 -0
  133. package/dist/packages/mcp/assets/kb/docs/docs-getting-started-first-run.md +34 -0
  134. package/dist/packages/mcp/assets/kb/docs/docs-getting-started-install.md +81 -0
  135. package/dist/packages/mcp/assets/kb/docs/docs-getting-started-next.md +32 -0
  136. package/dist/packages/mcp/assets/kb/docs/docs-getting-started-requirements.md +35 -0
  137. package/dist/packages/mcp/assets/kb/docs/docs-getting-started-running-the-tests.md +34 -0
  138. package/dist/packages/mcp/assets/kb/docs/docs-getting-started-supported-platforms.md +44 -0
  139. package/dist/packages/mcp/assets/kb/docs/docs-getting-started-updating.md +28 -0
  140. package/dist/packages/mcp/assets/kb/docs/docs-getting-started.md +27 -0
  141. package/dist/packages/mcp/assets/kb/docs/docs-keyboard-global-keys.md +26 -0
  142. package/dist/packages/mcp/assets/kb/docs/docs-keyboard-keys-handled-by-the-loop.md +29 -0
  143. package/dist/packages/mcp/assets/kb/docs/docs-keyboard-per-screen-keys.md +26 -0
  144. package/dist/packages/mcp/assets/kb/docs/docs-keyboard-what-shows.md +27 -0
  145. package/dist/packages/mcp/assets/kb/docs/docs-keyboard.md +26 -0
  146. package/dist/packages/mcp/assets/kb/docs/docs-larp-measured-accuracy.md +53 -0
  147. package/dist/packages/mcp/assets/kb/docs/docs-larp-open-link-keys.md +26 -0
  148. package/dist/packages/mcp/assets/kb/docs/docs-larp-paste-a-coin-on-the-web.md +35 -0
  149. package/dist/packages/mcp/assets/kb/docs/docs-larp-the-verdict.md +29 -0
  150. package/dist/packages/mcp/assets/kb/docs/docs-larp-timestamped-follow-up-drafts.md +35 -0
  151. package/dist/packages/mcp/assets/kb/docs/docs-larp-what-it-looks-at.md +33 -0
  152. package/dist/packages/mcp/assets/kb/docs/docs-larp.md +24 -0
  153. package/dist/packages/mcp/assets/kb/docs/docs-login-with-x-degraded-states-you-will-see.md +36 -0
  154. package/dist/packages/mcp/assets/kb/docs/docs-login-with-x-free-vs-paid-x-api-tiers-your-bill-your-limits.md +37 -0
  155. package/dist/packages/mcp/assets/kb/docs/docs-login-with-x-kol-lists-and-the-per-handle-filter.md +28 -0
  156. package/dist/packages/mcp/assets/kb/docs/docs-login-with-x-tests.md +25 -0
  157. package/dist/packages/mcp/assets/kb/docs/docs-login-with-x-what-is-read-and-when.md +35 -0
  158. package/dist/packages/mcp/assets/kb/docs/docs-login-with-x-what-you-set-up-once.md +40 -0
  159. package/dist/packages/mcp/assets/kb/docs/docs-login-with-x-where-the-tokens-live.md +27 -0
  160. package/dist/packages/mcp/assets/kb/docs/docs-login-with-x.md +26 -0
  161. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-a-live-ticket.md +42 -0
  162. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-before-you-press-size-vs-caps.md +34 -0
  163. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-devnet-signer-mainnet-token.md +35 -0
  164. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-jupiter-rate-limits.md +33 -0
  165. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-letting-an-agent-paper-trade-experimental.md +32 -0
  166. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-link-a-wallet.md +32 -0
  167. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-live-trading-devnet-first.md +30 -0
  168. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-mainnet.md +31 -0
  169. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-order-plans-and-standing-mandates.md +44 -0
  170. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-panic.md +31 -0
  171. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-pnl-cards.md +37 -0
  172. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-live-fire-path-devnet-the-fast-wallet.md +41 -0
  173. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-signer-process.md +34 -0
  174. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-ticket.md +31 -0
  175. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-wallet.md +34 -0
  176. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-trade-moments.md +32 -0
  177. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-what-the-live-path-keeps.md +37 -0
  178. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-your-first-live-trade.md +41 -0
  179. package/dist/packages/mcp/assets/kb/docs/docs-paper-trading.md +32 -0
  180. package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-bubble-map-popup.md +27 -0
  181. package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-build-the-native-window.md +33 -0
  182. package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-config-dexterm-popup-json.md +38 -0
  183. package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-docking-macos.md +27 -0
  184. package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-keys-in-the-popup.md +30 -0
  185. package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-market-cap-axis.md +28 -0
  186. package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-security-model.md +33 -0
  187. package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-token-and-feeds-popups.md +38 -0
  188. package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-what-it-shows.md +30 -0
  189. package/dist/packages/mcp/assets/kb/docs/docs-popup-chart.md +27 -0
  190. package/dist/packages/mcp/assets/kb/docs/docs-scan-cost-control.md +28 -0
  191. package/dist/packages/mcp/assets/kb/docs/docs-scan-keys-flag-command.md +34 -0
  192. package/dist/packages/mcp/assets/kb/docs/docs-scan-safety-four-layers.md +32 -0
  193. package/dist/packages/mcp/assets/kb/docs/docs-scan-states.md +27 -0
  194. package/dist/packages/mcp/assets/kb/docs/docs-scan-the-read.md +25 -0
  195. package/dist/packages/mcp/assets/kb/docs/docs-scan-triggers-and-score.md +37 -0
  196. package/dist/packages/mcp/assets/kb/docs/docs-scan.md +24 -0
  197. package/dist/packages/mcp/assets/kb/docs/docs-scorecard-frozen-canary.md +30 -0
  198. package/dist/packages/mcp/assets/kb/docs/docs-scorecard-frozen-task-1401-evaluation.md +35 -0
  199. package/dist/packages/mcp/assets/kb/docs/docs-scorecard-latest-skill-care-run.md +33 -0
  200. package/dist/packages/mcp/assets/kb/docs/docs-scorecard-links-only-larp-baseline-where-it-is-weak.md +35 -0
  201. package/dist/packages/mcp/assets/kb/docs/docs-scorecard-not-measured.md +29 -0
  202. package/dist/packages/mcp/assets/kb/docs/docs-scorecard-rug-verdict-rules.md +33 -0
  203. package/dist/packages/mcp/assets/kb/docs/docs-scorecard-source-and-rebuild.md +31 -0
  204. package/dist/packages/mcp/assets/kb/docs/docs-scorecard.md +27 -0
  205. package/dist/packages/mcp/assets/kb/docs/docs-screens-1-screener.md +35 -0
  206. package/dist/packages/mcp/assets/kb/docs/docs-screens-2-new-pairs.md +28 -0
  207. package/dist/packages/mcp/assets/kb/docs/docs-screens-3-watchlist.md +27 -0
  208. package/dist/packages/mcp/assets/kb/docs/docs-screens-4-analyst-tab.md +28 -0
  209. package/dist/packages/mcp/assets/kb/docs/docs-screens-bubble-map.md +32 -0
  210. package/dist/packages/mcp/assets/kb/docs/docs-screens-coin-images.md +32 -0
  211. package/dist/packages/mcp/assets/kb/docs/docs-screens-dev-history.md +44 -0
  212. package/dist/packages/mcp/assets/kb/docs/docs-screens-how-well-it-predicts-measured-held-out.md +46 -0
  213. package/dist/packages/mcp/assets/kb/docs/docs-screens-live-holder-and-rug-signals.md +51 -0
  214. package/dist/packages/mcp/assets/kb/docs/docs-screens-order-plans.md +26 -0
  215. package/dist/packages/mcp/assets/kb/docs/docs-screens-paper-ticket-and-positions.md +29 -0
  216. package/dist/packages/mcp/assets/kb/docs/docs-screens-the-look.md +29 -0
  217. package/dist/packages/mcp/assets/kb/docs/docs-screens-token-screen.md +36 -0
  218. package/dist/packages/mcp/assets/kb/docs/docs-screens-trending-social-and-kol-lists.md +34 -0
  219. package/dist/packages/mcp/assets/kb/docs/docs-screens.md +26 -0
  220. package/dist/packages/mcp/assets/kb/docs/docs-spectator-1-the-agent-activity-window-follow-mode.md +56 -0
  221. package/dist/packages/mcp/assets/kb/docs/docs-spectator-2-the-read-only-stream-spectate.md +42 -0
  222. package/dist/packages/mcp/assets/kb/docs/docs-spectator-3-save-and-replay-record-file-dexterm-spectate.md +41 -0
  223. package/dist/packages/mcp/assets/kb/docs/docs-spectator-follow-over-mcp-in-the-running-terminal.md +39 -0
  224. package/dist/packages/mcp/assets/kb/docs/docs-spectator-limits.md +36 -0
  225. package/dist/packages/mcp/assets/kb/docs/docs-spectator-quick-start.md +37 -0
  226. package/dist/packages/mcp/assets/kb/docs/docs-spectator-security-model.md +35 -0
  227. package/dist/packages/mcp/assets/kb/docs/docs-spectator-see-also.md +29 -0
  228. package/dist/packages/mcp/assets/kb/docs/docs-spectator-streaming-it.md +32 -0
  229. package/dist/packages/mcp/assets/kb/docs/docs-spectator-the-three-surfaces.md +37 -0
  230. package/dist/packages/mcp/assets/kb/docs/docs-spectator-what-is-redacted.md +35 -0
  231. package/dist/packages/mcp/assets/kb/docs/docs-spectator.md +29 -0
  232. package/dist/packages/mcp/assets/kb/docs/docs-troubleshooting-common-questions.md +33 -0
  233. package/dist/packages/mcp/assets/kb/docs/docs-troubleshooting-doctor-lines.md +38 -0
  234. package/dist/packages/mcp/assets/kb/docs/docs-troubleshooting-in-app-messages.md +42 -0
  235. package/dist/packages/mcp/assets/kb/docs/docs-troubleshooting-reporting-a-problem.md +25 -0
  236. package/dist/packages/mcp/assets/kb/docs/docs-troubleshooting.md +23 -0
  237. package/dist/packages/mcp/assets/kb/docs/docs-voice-doctor.md +26 -0
  238. package/dist/packages/mcp/assets/kb/docs/docs-voice-it-clarifies-it-never-guesses.md +36 -0
  239. package/dist/packages/mcp/assets/kb/docs/docs-voice-latency.md +38 -0
  240. package/dist/packages/mcp/assets/kb/docs/docs-voice-linux-and-windows.md +32 -0
  241. package/dist/packages/mcp/assets/kb/docs/docs-voice-privacy.md +26 -0
  242. package/dist/packages/mcp/assets/kb/docs/docs-voice-still-unverified.md +27 -0
  243. package/dist/packages/mcp/assets/kb/docs/docs-voice-the-voice-neural-by-default.md +48 -0
  244. package/dist/packages/mcp/assets/kb/docs/docs-voice-what-it-can-never-do.md +27 -0
  245. package/dist/packages/mcp/assets/kb/docs/docs-voice-what-you-can-say.md +38 -0
  246. package/dist/packages/mcp/assets/kb/docs/docs-voice.md +25 -0
  247. package/dist/packages/mcp/src/app-help.js +123 -0
  248. package/dist/packages/mcp/src/firewall.js +2 -2
  249. package/dist/packages/mcp/src/index.js +8 -4
  250. package/dist/packages/mcp/src/paper-agent.js +92 -0
  251. package/dist/packages/mcp/src/server.js +261 -29
  252. package/dist/packages/mcp/src/spectator-sink.js +146 -5
  253. package/dist/packages/mcp/src/user-content.js +1 -0
  254. package/dist/packages/recorder/src/dev-history.js +129 -0
  255. package/dist/packages/recorder/src/index.js +1 -0
  256. package/dist/packages/recorder/src/recorder.js +23 -0
  257. package/dist/packages/recorder/src/schema.js +11 -0
  258. package/dist/packages/voice/src/stt/whisper.js +4 -2
  259. package/package.json +6 -5
@@ -0,0 +1,27 @@
1
+ ---
2
+ id: docs-voice-still-unverified
3
+ title: Jarvis voice mode › Still unverified
4
+ kind: docs
5
+ page: voice
6
+ page_title: Jarvis voice mode
7
+ heading: Still unverified
8
+ anchor: still-unverified
9
+ url: https://dexterm.xyz/docs/voice#still-unverified
10
+ tags:
11
+ - docs
12
+ - voice
13
+ - still
14
+ - unverified
15
+ - jarvis
16
+ - mode
17
+ confidence: high
18
+ owner: maintainers
19
+ origin: docs-generated
20
+ reviewed_by: generated@2026-10-16
21
+ generated_from: dexterm/site content/docs (task-1420)
22
+ sources:
23
+ - site/content/docs/voice.md
24
+ date: 2026-10-16
25
+ ---
26
+
27
+ The real-microphone path has been exercised headlessly (scripted speech engines, the real key loop) and the engines have been measured on synthetic audio. A person has not yet run the first-launch Microphone and Speech prompts and spoken to it end to end; see the changelog (https://dexterm.xyz/changelog/).
@@ -0,0 +1,48 @@
1
+ ---
2
+ id: docs-voice-the-voice-neural-by-default
3
+ title: Jarvis voice mode › The voice: neural by default
4
+ kind: docs
5
+ page: voice
6
+ page_title: Jarvis voice mode
7
+ heading: The voice: neural by default
8
+ anchor: the-voice-neural-by-default
9
+ url: https://dexterm.xyz/docs/voice#the-voice-neural-by-default
10
+ tags:
11
+ - docs
12
+ - voice
13
+ - neural
14
+ - default
15
+ - jarvis
16
+ - mode
17
+ confidence: high
18
+ owner: maintainers
19
+ origin: docs-generated
20
+ reviewed_by: generated@2026-10-16
21
+ generated_from: dexterm/site content/docs (task-1420)
22
+ sources:
23
+ - site/content/docs/voice.md
24
+ date: 2026-10-16
25
+ ---
26
+
27
+ dexterm speaks with a **neural British voice** (Piper, `en_GB-alan-medium`) — the one chosen as the default. It is free, local and keyless, and sounds markedly more natural than the built-in system voices. It is the default speaking voice everywhere it is installed, on macOS as well as Linux, with the system `say` voice as the fallback.
28
+
29
+ On macOS, run `dexterm voice setup` once to install it. The prebuilt macOS Piper binary from upstream is broken (it needs a system library it does not bundle), so dexterm instead builds its own private Python environment under `~/.dexterm/piper/` and installs Piper into it, then downloads the ~61 MB voice from the official source and checks it against a pinned checksum. It asks before it does any of this, needs Python 3.9+ (the doctor prints the exact install line if it is missing), runs fully offline afterwards, and ships no key. `dexterm voice uninstall` removes the runtime and keeps the downloaded voice model (add `--purge-model` to delete that too); the fallback `say` voice takes over again. Off macOS, install the prebuilt Piper binary and run `dexterm voice download piper-voice`.
30
+
31
+ ```sh
32
+ $ dexterm voice setup # macOS: private runtime + checksum-verified voice (asks first)
33
+ $ dexterm voice status # which engines and models this machine has
34
+ $ dexterm voice uninstall # remove the runtime (add --purge-model to drop the voice too)
35
+ ```
36
+
37
+ Once Piper is installed it is used automatically — no config change. The model is kept pre-warmed while voice is on, so the first word of a reply starts in about a fifth of a second. `voice.rate` still maps to its speaking speed; a `voice.pitch` setting does not apply to Piper (its pitch is fixed by the model) and is ignored.
38
+
39
+ **The fallback chain.** dexterm picks the first engine that can speak on this machine, and never a novelty voice or the machine's own system voice:
40
+
41
+ | platform | 1st | 2nd | then |
42
+ | --- | --- | --- | --- |
43
+ | macOS | Piper `en_GB-alan-medium` (after `dexterm voice setup`) | `say` with a deep British male voice (Eddy, then Daniel, then the next installed one on that list) | text only: the analyst still answers on screen |
44
+ | Linux (beta) | Piper (prebuilt binary + `dexterm voice download piper-voice`) | `espeak-ng` with a British male voice | text only |
45
+
46
+ Set `DEXTERM_VOICE_TTS` to `piper`, `say`, `espeak` or `none` to pin one engine. An explicit `say` never switches to Piper.
47
+
48
+ **Speed and delivery.** `<` slows the spoken reply and `>` speeds it up, 15 words a minute per press between 120 and 320 (the default is 205). The new rate is saved to `voice.rate` in `config.json`. Numbers are read the way a trader says them: a sub-cent price is spoken as the coin's market cap when the line includes one, and otherwise as "a tiny price". Years and SOL amounts are read as written. On the screener, "this one", "this coin" or "it" means the highlighted row.
@@ -0,0 +1,27 @@
1
+ ---
2
+ id: docs-voice-what-it-can-never-do
3
+ title: Jarvis voice mode › What it can never do
4
+ kind: docs
5
+ page: voice
6
+ page_title: Jarvis voice mode
7
+ heading: What it can never do
8
+ anchor: what-it-can-never-do
9
+ url: https://dexterm.xyz/docs/voice#what-it-can-never-do
10
+ tags:
11
+ - docs
12
+ - voice
13
+ - can
14
+ - never
15
+ - jarvis
16
+ - mode
17
+ confidence: high
18
+ owner: maintainers
19
+ origin: docs-generated
20
+ reviewed_by: generated@2026-10-16
21
+ generated_from: dexterm/site content/docs (task-1420)
22
+ sources:
23
+ - site/content/docs/voice.md
24
+ date: 2026-10-16
25
+ ---
26
+
27
+ Voice creates proposals only. The ticket it opens is PAPER, in its editing phase, and the keypress gate stands: your `⏎` then `y` (plus the typed-back size above the threshold) is the only way to a fill. Spoken "confirm", "send it", "y", "sign it", "go live", "arm it", "raise my cap", "panic" and "/wallet …" are routed as questions or ignored; they cannot flip the ticket to LIVE, arm a plan, touch the signer's caps, run a wallet command or press anything. The router's output is a closed set of decision kinds, a guard rejects any decision that carries a mode, live, arm, caps, confirm, sign or send field, and an in-app test drives the real key loop with the executor, the confirm paths, the LIVE flip and the wallet commands booby-trapped: twenty-one hostile utterances, zero touches.
@@ -0,0 +1,38 @@
1
+ ---
2
+ id: docs-voice-what-you-can-say
3
+ title: Jarvis voice mode › What you can say
4
+ kind: docs
5
+ page: voice
6
+ page_title: Jarvis voice mode
7
+ heading: What you can say
8
+ anchor: what-you-can-say
9
+ url: https://dexterm.xyz/docs/voice#what-you-can-say
10
+ tags:
11
+ - docs
12
+ - voice
13
+ - can
14
+ - say
15
+ - jarvis
16
+ - mode
17
+ confidence: high
18
+ owner: maintainers
19
+ origin: docs-generated
20
+ reviewed_by: generated@2026-10-16
21
+ generated_from: dexterm/site content/docs (task-1420)
22
+ sources:
23
+ - site/content/docs/voice.md
24
+ date: 2026-10-16
25
+ ---
26
+
27
+ | you say | what happens | path |
28
+ |---|---|---|
29
+ | "show me the runners", "go to new pairs", "open my watchlist", "positions" | switches the screen | instant, no model |
30
+ | "open bonk", "pull up wif" | opens that coin's token screen | instant |
31
+ | "filter liquidity over 50k", "only show age under 10 minutes" | sets the screener filter | instant |
32
+ | "watch this one", "add bonk to my watchlist" | adds to the watchlist | instant |
33
+ | "show the chart", "close the chart" | opens or closes the chart popup for the open coin through the popup host | instant |
34
+ | "buy bonk", "sell half of wif", "ape into this one" | opens a **PAPER ticket in its editing phase** for the spoken coin and says so | instant |
35
+ | "is this a rug?", "what do you think about wif", "tell me about the holders" | asks the analyst; the first two sentences of the answer are read aloud | Claude |
36
+ | "buy this if it dips to 300k, sell half at 600k, and leave a moon bag", "buy bonk if it drops to 250k, stop at 150k" | drafts an **order-plan proposal** (entry trigger, take-profit ladder, moon bag, stop) for the named or highlighted coin; it is inert until you arm it with a held keypress on the `O` screen or `dexterm plan arm` | instant, no model |
37
+
38
+ `m` mutes the replies, `,` cycles the macOS `say` voice (the fallback; Piper itself has one fixed voice), `<` / `>` make it slower or faster, `esc` stops a reply or cancels the mic. Only the keyboard changes the voice: the analyst can explain these keys but has no action that sets them. Any other key pressed while the mic is live closes it first and then does its normal job, and the mic auto-closes after 15 s if you walk away. On the ticket screen the voice keys are off, so nothing spoken can reach the confirm gate.
@@ -0,0 +1,25 @@
1
+ ---
2
+ id: docs-voice
3
+ title: Jarvis voice mode
4
+ kind: docs
5
+ page: voice
6
+ page_title: Jarvis voice mode
7
+ url: https://dexterm.xyz/docs/voice
8
+ tags:
9
+ - docs
10
+ - voice
11
+ - jarvis
12
+ - mode
13
+ confidence: high
14
+ owner: maintainers
15
+ origin: docs-generated
16
+ reviewed_by: generated@2026-10-16
17
+ generated_from: dexterm/site content/docs (task-1420)
18
+ sources:
19
+ - site/content/docs/voice.md
20
+ date: 2026-10-16
21
+ ---
22
+
23
+ Push-to-talk on v, an instant local command path, Claude for analysis, spoken replies, popups. Voice only ever proposes; it can never confirm, sign, flip LIVE or raise a cap.
24
+
25
+ `v` is push-to-talk. Press it once and the mic opens (a red `● LISTENING` badge sits on the band under the header the whole time it is live); say what you want; press `v` again to send. The first press enables voice for the run and asks macOS for Microphone and Speech permission. Everything is free and local: speech-out is the neural Piper voice once it is set up (otherwise the built-in `say`), speech-in is on-device Apple Speech (compiled once with `swiftc`) or a local whisper.cpp `base.en` model, and the only model in the loop is your own `claude` login, for analysis questions. No paid speech API exists in the code, no key is read, nothing is recorded to disk.
@@ -133,3 +133,126 @@ export function searchAppHelp(query, limit = 5, entries = loadAppHelp()) {
133
133
  export function getAppHelp(id, entries = loadAppHelp()) {
134
134
  return entries.find((e) => e.id === id) ?? null;
135
135
  }
136
+ // ---------------------------------------------------------------------------------------- docs (task-1420)
137
+ // A THIRD bundled set: every page of the site docs (dexterm.xyz/docs), chunked by heading. GENERATED from the
138
+ // site by `packages/cli/src/docs-kb-gen.ts` (committed; a regenerate-and-diff test runs when the site checkout
139
+ // is present). The app-help entries stay the authority for an exact key or command; a docs entry carries the
140
+ // explanation and the URL to cite, and NEVER structured keys/commands/flags/tools. Its text is reference DATA:
141
+ // the app_help tool hands it to a model firewalled (`<untrusted kind="docs">`), so an instruction written into
142
+ // a docs page reads as quoted text, never as an order.
143
+ /** The shipped docs KB directory (read-only; generated from the site docs). */
144
+ export const DOCS_KB_DIR = path.resolve(HERE, '..', 'assets', 'kb', 'docs');
145
+ function toDocs(e) {
146
+ return {
147
+ id: e.id,
148
+ title: String(e.meta.title ?? e.id),
149
+ page: String(e.meta.page ?? ''),
150
+ pageTitle: String(e.meta.page_title ?? ''),
151
+ heading: String(e.meta.heading ?? ''),
152
+ anchor: String(e.meta.anchor ?? ''),
153
+ url: String(e.meta.url ?? ''),
154
+ tags: list(e.meta.tags),
155
+ body: e.body,
156
+ bytes: e.bytes,
157
+ };
158
+ }
159
+ /** Load every docs entry (bundled-only; deterministic order by id). */
160
+ export function loadDocsKb(dir = DOCS_KB_DIR) {
161
+ const entries = loadBundled([{ dir, layout: 'flat' }]).map(toDocs);
162
+ entries.sort((a, b) => a.id.localeCompare(b.id));
163
+ return entries;
164
+ }
165
+ /**
166
+ * A light, deterministic stemmer for the docs set only (prose, unlike the app-help titles): "answers"/"answer",
167
+ * "cached"/"cache", "clarifies"/"clarify", "streaming"/"stream" meet. Short words are left alone.
168
+ */
169
+ function stem(w) {
170
+ if (w.length < 4 || w.includes('-'))
171
+ return w;
172
+ let s = w;
173
+ if (s.endsWith('ies') && s.length > 4)
174
+ s = s.slice(0, -3) + 'y';
175
+ else if (s.endsWith('ing') && s.length > 5)
176
+ s = s.slice(0, -3);
177
+ else if (s.endsWith('ed') && s.length > 4)
178
+ s = s.slice(0, -2);
179
+ else if (/(?:ss|sh|ch|x|z)es$/.test(s))
180
+ s = s.slice(0, -2);
181
+ else if (s.endsWith('s') && !s.endsWith('ss'))
182
+ s = s.slice(0, -1);
183
+ if (s.endsWith('e') && s.length > 3)
184
+ s = s.slice(0, -1);
185
+ return s;
186
+ }
187
+ /**
188
+ * Deterministic keyword retrieval over the docs set (no model), same word-boundary matching as app-help.
189
+ * The section heading and tags score strongest, the page title less (every section of a page shares it),
190
+ * the body is the weak tail.
191
+ */
192
+ export function searchDocs(query, limit = 5, entries = loadDocsKb()) {
193
+ const terms = [...new Set(expand(tokenise(query)).map(stem))];
194
+ const scored = entries.map((e) => {
195
+ const strong = new Set(words(`${e.heading} ${e.tags.filter((t) => t !== 'docs').join(' ')}`).map(stem));
196
+ const page = new Set(words(`${e.pageTitle} ${e.page}`).map(stem));
197
+ const bodyWords = words(e.body).map(stem);
198
+ let score = 0;
199
+ for (const t of terms) {
200
+ if (strong.has(t))
201
+ score += 4;
202
+ else if (page.has(t))
203
+ score += 2;
204
+ let n = 0;
205
+ for (const w of bodyWords)
206
+ if (w === t)
207
+ n++;
208
+ score += Math.min(n, 3);
209
+ }
210
+ // A question that names a section's own heading words is about that section: +3 per heading word
211
+ // matched (+2 more when it names all of them), so "what is redacted in the spectator view" lands on "What is redacted",
212
+ // not on the page's other sections that merely share the page title.
213
+ const head = new Set(tokenise(e.heading).map(stem));
214
+ let hit = 0;
215
+ for (const w of head)
216
+ if (terms.includes(w))
217
+ hit++;
218
+ if (hit >= 1 && head.size > 0)
219
+ score += 3 * hit + (hit === head.size ? 2 : 0);
220
+ return { e, score };
221
+ }).filter((x) => x.score > 0)
222
+ .sort((a, b) => (b.score - a.score) || a.e.id.localeCompare(b.e.id))
223
+ .slice(0, limit);
224
+ return scored.map(({ e, score }) => ({ ...e, score }));
225
+ }
226
+ /** Fetch one docs entry by id. */
227
+ export function getDocs(id, entries = loadDocsKb()) {
228
+ return entries.find((e) => e.id === id) ?? null;
229
+ }
230
+ /** Words that make a question about an exact key or command: app-help answers it. */
231
+ const KEY_OR_COMMAND = /\b(?:key|keys|keybind\w*|press|pressing|shortcut|shortcuts|hotkey|hotkeys|command|commands|subcommand|subcommands|flag|flags|cli)\b/i;
232
+ /** "how do I …" / "how to …": a how-to, answered by an app-help topic. */
233
+ const HOW_TO = /^\s*how\s+(?:do|can|could|would|should)\s+(?:i|you|we)\b|^\s*how\s+to\b/i;
234
+ /** A conceptual question opens with a question word ("what is …", "does it …", "how does …", "how long …"). */
235
+ const CONCEPT = /^\s*(?:what|whats|what's|why|is|are|does|do|did|can|could|will|would|should|where|when|which|who|how)\b/i;
236
+ /** About a screen ("what does the token screen show") or the coin on it ("is this coin a rug"): an app-help topic/tool. */
237
+ const APP_SUBJECT = /\b(?:screen|screener)\b|\bthis\s+(?:[a-z-]+\s+){0,2}(?:coin|token|project)\b/i;
238
+ /** The question's shape: 'key' (exact key/command, a how-to, an imperative, a screen/this-coin question) or 'concept'. */
239
+ export function helpIntent(query) {
240
+ if (KEY_OR_COMMAND.test(query) || HOW_TO.test(query) || APP_SUBJECT.test(query))
241
+ return 'key';
242
+ return CONCEPT.test(query) ? 'concept' : 'key';
243
+ }
244
+ /**
245
+ * The analyst's help search (task-1420): app-help AND the docs, merged by the question's shape.
246
+ * - a key/command question, a how-to or an imperative ("export the view", "how do I sort"): app-help ranks
247
+ * first (it carries the exact key/command), the docs after it;
248
+ * - a conceptual question ("what is redacted in the spectator view", "does voice work on linux"): the docs rank
249
+ * first (nothing ranks above them), the app-help after.
250
+ * Either way the answer keeps both sets in view: up to 3 hits of the leading set, then up to 2 of the other,
251
+ * then the rest. A set with no hits simply yields to the other (a docs-only answer beats no answer).
252
+ */
253
+ export function searchHelp(query, limit = 5, sets = {}) {
254
+ const app = searchAppHelp(query, limit, sets.appHelp ?? loadAppHelp()).map((e) => ({ ...e, origin: 'app-help' }));
255
+ const docs = searchDocs(query, limit, sets.docs ?? loadDocsKb()).map((e) => ({ ...e, origin: 'docs' }));
256
+ const [lead, other] = helpIntent(query) === 'concept' ? [docs, app] : [app, docs];
257
+ return [...lead.slice(0, 3), ...other.slice(0, 2), ...lead.slice(3), ...other.slice(2)].slice(0, limit);
258
+ }
@@ -1,7 +1,7 @@
1
1
  // Prompt firewall (CL-06), spec'd in SPEC §5.3. Kept tiny and total. Every untrusted string — token text,
2
2
  // web pages, RugCheck risks, and (task-1377) user- or pack-edited KB entries and skills — passes through
3
- // here before a model sees it.
4
- export const LIMITS = { name: 64, symbol: 16, description: 512, risk: 160, kb: 4000, page: 1600, link: 40, skill: 8000 };
3
+ // here before a model sees it. (task-1420) The generated docs KB sections pass through as kind `docs`.
4
+ export const LIMITS = { name: 64, symbol: 16, description: 512, risk: 160, kb: 4000, page: 1600, link: 40, skill: 8000, docs: 6000 };
5
5
  export function firewall(text, source, kind = 'description', opts = {}) {
6
6
  if (text === null || text === undefined)
7
7
  return null;
@@ -1,12 +1,15 @@
1
1
  // @dexterm/mcp — read-only MCP server over stdio (SPEC §5, D-09 / task-1302).
2
2
  // Every tool is read-only and schema-described; nothing in this package may build,
3
3
  // sign or send a transaction (SPEC §5.2, §6.3).
4
- export { runStdioServer, selfTest, McpTools, TOOLS, READ_ONLY_TOOLS, firewall, listPrompts, getPrompt, resourceList, resourceRead, overlayCounts, userSkillPreamble, BUNDLED_KB_DIR, BUNDLED_SKILLS_DIR } from "./server.js";
4
+ export { runStdioServer, selfTest, McpTools, TOOLS, READ_ONLY_TOOLS, PAPER_WRITE_TOOLS, PAPER_READ_TOOLS, appHelpAnswer, firewall, listPrompts, getPrompt, resourceList, resourceRead, overlayCounts, userSkillPreamble, BUNDLED_KB_DIR, BUNDLED_SKILLS_DIR } from "./server.js";
5
+ // task-1443: resolve the paper agent desk from the running app's rendezvous (null when agent paper trading is off).
6
+ export { resolvePaperAgentDesk, paperAgentDeskDb } from "./paper-agent.js";
5
7
  export { OverlayStore, mergeOverlay, loadBundled, checkKb, checkSkill, moneyToolMentions, isMoneyToolName, parseFrontmatter, dextermHome, userKbDir, userSkillsDir, userDir, contentJournalPath, journalContent, writeOverlayFile, resetOverlayFile, templateFor, KB_LIMITS, SKILL_LIMITS, KB_ID, SKILL_NAME, KB_RULE, MONEY_TOOLS, } from "./user-content.js";
6
8
  export { buildDossier } from "./dossier.js";
7
- // task-1406: the spectator sink the tool-call path writes to when launched with a spectator channel.
8
- export { recordForToolCall, maxAgeSec, fileSpectatorSinkFromEnv } from "./spectator-sink.js";
9
- export { loadAppHelp, searchAppHelp, getAppHelp, APP_HELP_DIR } from "./app-help.js";
9
+ // task-1406 + task-1421: the spectator sink the tool-call path writes to when a spectator surface is open
10
+ // (via DEXTERM_SPECTATOR_FILE, or the ~/.dexterm rendezvous an external `dexterm mcp` client uses).
11
+ export { recordForToolCall, maxAgeSec, fileSpectatorSinkFromEnv, resolveSpectatorSink, rendezvousPath, MCP_SPECTATOR_RENDEZVOUS, MCP_FOLLOW_SCREEN, FOLLOW_NAV_ACTIONS, followScreenPath, readFollowScreen, writeFollowScreen, clearFollowScreen, } from "./spectator-sink.js";
12
+ export { loadAppHelp, searchAppHelp, getAppHelp, APP_HELP_DIR, loadDocsKb, searchDocs, getDocs, searchHelp, DOCS_KB_DIR, helpIntent } from "./app-help.js";
10
13
  /** Tool names served in v1 (SPEC §5.2 core + the task-1293 KB/case tools + the task-1314 dossier). */
11
14
  export const PLANNED_TOOLS = [
12
15
  'screen_state',
@@ -19,6 +22,7 @@ export const PLANNED_TOOLS = [
19
22
  'get_candles',
20
23
  'rugcheck',
21
24
  'get_dev_history',
25
+ 'dev_history',
22
26
  'kb_lookup',
23
27
  'kb_search',
24
28
  'case_lookup',
@@ -0,0 +1,92 @@
1
+ // task-1443 — the MCP side of agent paper trading. When the running dexterm has the spectator view open and the
2
+ // user named an armed mandate for agent paper trading, it writes a rendezvous under ~/.dexterm; this resolves it
3
+ // into a PaperAgentDesk the paper tools dispatch to. When the rendezvous is absent the resolver returns null and
4
+ // the tools refuse — so agent paper trading is OFF by default and nothing here ever signs, sends or touches a
5
+ // wallet/key.
6
+ //
7
+ // The desk books into the SAME paper wallet SQLite file the app uses (WAL, concurrent-safe). Its caps are
8
+ // REPLAYED from the app's hash-chained plans journal (never read from the rendezvous), re-checked on every call
9
+ // (mtime-cached), so a revoke or panic in the app halts the agent. It prices the mandate's USD caps from a
10
+ // keyless SOL/USD read (fail-closed when older than 60 s), reads the control file on every mutating call
11
+ // (pause / take-over / stop), and journals every call to its own hash chain. The only trade op it can reach is
12
+ // the keyless swap-QUOTE + the PAPER executor (see paper-desk.ts).
13
+ import { PaperAgentDesk, PaperWallet, PaperExecutor, SharedJournal, systemClock, readPaperAgentRendezvous, readDeskControl, rendezvousMtimeMs, fileMtimeMs, loadMandateFromJournal, plansJournalPathFor, paperAgentJournalPath, withPriority, } from '../../data/src/index.js';
14
+ const WSOL = 'So11111111111111111111111111111111111111112';
15
+ /** A SOL/USD read older than this prices no cap (same freshness rule as the signer's resolveSolUsd). */
16
+ export const PAPER_SOL_USD_MAX_AGE_MS = 60_000;
17
+ const SOL_USD_REFRESH_MS = 20_000;
18
+ let cache = null;
19
+ let sol = null;
20
+ let mandateCache = null;
21
+ function teardown() {
22
+ if (cache) {
23
+ try {
24
+ cache.wallet.close();
25
+ }
26
+ catch { /* ignore */ }
27
+ cache = null;
28
+ }
29
+ mandateCache = null;
30
+ }
31
+ /** Replay the mandate from the plans journal, re-read whenever the journal changes (revoke / panic / expiry). */
32
+ function currentMandate(env, id) {
33
+ const path = plansJournalPathFor(env);
34
+ const mtimeMs = fileMtimeMs(path);
35
+ if (mandateCache && mandateCache.id === id && mandateCache.mtimeMs === mtimeMs)
36
+ return mandateCache.m;
37
+ const r = loadMandateFromJournal(path, id, systemClock);
38
+ mandateCache = { id, mtimeMs, m: r.mandate };
39
+ return r.mandate;
40
+ }
41
+ /** Keep the SOL/USD read fresh enough to price the USD caps; a failed read leaves the old one to age out. */
42
+ async function refreshSolUsd(data) {
43
+ const now = Date.now();
44
+ if (sol && now - sol.at < SOL_USD_REFRESH_MS)
45
+ return;
46
+ try {
47
+ const p = (await data.jupiter.price([WSOL])).get(WSOL)?.usdPrice;
48
+ if (typeof p === 'number' && Number.isFinite(p) && p > 0)
49
+ sol = { price: p, at: Date.now() };
50
+ }
51
+ catch { /* keep the last value; it ages out */ }
52
+ }
53
+ /**
54
+ * Resolve the paper agent desk for this `dexterm mcp` process, or null when agent paper trading is disabled.
55
+ * Re-reads the rendezvous (mtime-cached) so enabling/disabling in the running app is picked up; the mandate
56
+ * and the control state are re-read inside the desk on every call, not cached across journal changes.
57
+ */
58
+ export async function resolvePaperAgentDesk(data, env = process.env) {
59
+ const mtimeMs = rendezvousMtimeMs(env);
60
+ if (mtimeMs === 0) {
61
+ teardown();
62
+ return null;
63
+ } // not enabled
64
+ const rv = readPaperAgentRendezvous(env);
65
+ if (!rv) {
66
+ teardown();
67
+ return null;
68
+ } // present but unreadable → off (fail closed)
69
+ await refreshSolUsd(data);
70
+ if (cache && cache.mtimeMs === mtimeMs && cache.db === rv.db && cache.mandateId === rv.mandateId)
71
+ return cache.desk;
72
+ // The rendezvous changed (or first use): rebuild on the current wallet + mandate.
73
+ teardown();
74
+ const wallet = new PaperWallet({ path: rv.db, clock: systemClock });
75
+ const executor = new PaperExecutor(wallet, { clock: systemClock });
76
+ const desk = new PaperAgentDesk({
77
+ mandate: () => currentMandate(env, rv.mandateId),
78
+ wallet,
79
+ executor,
80
+ // 'high', like the human ticket (task-1387): a paper exit must not queue behind the agent's own read polling on
81
+ // the shared keyless `jupiter` bucket (task-1443 live run: a scale-out was refused on a 429 mid-poll).
82
+ quote: (req, signal) => withPriority('high', () => data.jupiterSwap.quote(req, signal)),
83
+ solUsd: () => (sol && Date.now() - sol.at <= PAPER_SOL_USD_MAX_AGE_MS ? sol.price : null),
84
+ control: () => readDeskControl(env),
85
+ journal: new SharedJournal(paperAgentJournalPath(env), systemClock),
86
+ agent: rv.agent ?? 'mcp-agent',
87
+ });
88
+ cache = { mtimeMs, db: rv.db, mandateId: rv.mandateId, wallet, desk };
89
+ return desk;
90
+ }
91
+ /** Exported for tests: the current cached rendezvous db, if any. */
92
+ export function paperAgentDeskDb() { return cache?.db ?? null; }