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,209 @@
1
+ // Local-only LARP/high-risk follow-up draft pipeline (task-1433). History mode reads the recorder
2
+ // without network access, scores only the point-in-time t0 row, joins only later outcome labels, and
3
+ // writes drafts/cards for human review. Live mode performs one read-only enrichment for one mint.
4
+ // Nothing here has X credentials, opens a composer, schedules work, trades, arms, signs or posts.
5
+ import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
6
+ import { join, resolve } from 'node:path';
7
+ import { createDataLayer, defaultDbPath } from '../../data/src/index.js';
8
+ import { openHistoryReadOnly, exportRecorded } from '../../recorder/src/index.js';
9
+ import { h1Model, rugFeaturesFromRecord, rugFeaturesFromToken } from '../../packs/src/index.js';
10
+ import { Canvas, THEMES } from '../../tui/src/index.js';
11
+ import { writeExport, fmtAge } from "./export.js";
12
+ export const LARP_DRAFT_MIN_SAMPLE = 50;
13
+ export const LARP_DRAFT_HORIZON = 259_200;
14
+ export const LARP_DRAFT_THRESHOLD = 0.5;
15
+ const isoMinute = (t) => new Date(t).toISOString().replace(/:\d\d\.\d{3}Z$/, 'Z');
16
+ const shortMint = (mint) => `${mint.slice(0, 4)}...${mint.slice(-4)}`;
17
+ const pct = (n, d) => `${d ? ((n / d) * 100).toFixed(1) : '0.0'}%`;
18
+ /** One point-in-time flag per mint: earliest flagged t0 with an observed outcome at this horizon. */
19
+ export function buildFollowUpDataset(records, horizonSec = LARP_DRAFT_HORIZON, threshold = LARP_DRAFT_THRESHOLD) {
20
+ const model = h1Model();
21
+ const byMint = new Map();
22
+ for (const r of records) {
23
+ const outcome = r.outcomes[`${horizonSec}`];
24
+ if (!outcome || byMint.has(r.mint))
25
+ continue;
26
+ const score = model.score(rugFeaturesFromRecord(r.features));
27
+ if (score < threshold)
28
+ continue;
29
+ byMint.set(r.mint, { mint: r.mint, t0: r.t0, score, model: model.id, outcome });
30
+ }
31
+ const flagged = [...byMint.values()];
32
+ const collapsed = flagged.filter((r) => r.outcome.positive);
33
+ return { horizonSec, threshold, flagged, collapsed, didNotCollapse: flagged.length - collapsed.length };
34
+ }
35
+ function outcomeText(o) {
36
+ if (o.label === 'rug')
37
+ return 'recorder label: liquidity-pull condition';
38
+ if (o.label === 'dead')
39
+ return 'recorder label: inactive at follow-up';
40
+ return `recorder label: ${o.label}`;
41
+ }
42
+ function datasetLine(d) {
43
+ return `Same-dataset follow-up: ${d.collapsed.length}/${d.flagged.length} met the condition (${pct(d.collapsed.length, d.flagged.length)}); ${d.didNotCollapse}/${d.flagged.length} did not.`;
44
+ }
45
+ function cardCanvas(row, d, now) {
46
+ const c = new Canvas(92, 25, THEMES.cyberspace);
47
+ const t = c.theme;
48
+ c.fill(0, 0, c.w, c.h, ' ', { bg: t.bg });
49
+ c.fill(0, 0, c.w, 3, ' ', { bg: t.headBg });
50
+ c.text(3, 1, 'LARP DETECTED · RECORDED FOLLOW-UP', { fg: t.warn, bg: t.headBg, b: true });
51
+ c.textR(0, 1, c.w - 3, shortMint(row.mint), { fg: t.muted, bg: t.headBg });
52
+ c.text(4, 5, 'AT THE RECORDED MOMENT', { fg: t.muted, b: true });
53
+ c.text(4, 7, `HIGH RISK ${Math.round(row.score * 100)}/100`, { fg: t.down, b: true });
54
+ c.text(4, 9, `${row.model} heuristic · model output · risk flag, not a certificate`, { fg: t.text });
55
+ c.text(4, 10, `${isoMinute(row.t0)} · local recorder · t0 evidence age ${fmtAge((now - row.t0) / 1000)}`, { fg: t.muted });
56
+ c.text(4, 13, 'LATER OBSERVED', { fg: t.muted, b: true });
57
+ c.text(4, 15, outcomeText(row.outcome).toUpperCase(), { fg: t.warn, b: true });
58
+ c.text(4, 17, `${fmtAge(d.horizonSec)} follow-up · ${row.outcome.tier} · labeler evidence`, { fg: t.text });
59
+ c.text(4, 20, datasetLine(d), { fg: t.muted }, c.w - 8);
60
+ c.text(4, 22, 'Sources: local dexterm recorder · DexScreener + Jupiter · draft only', { fg: t.muted }, c.w - 8);
61
+ c.text(4, 23, 'Not financial advice.', { fg: t.muted });
62
+ return c;
63
+ }
64
+ function historyDraft(row, d, now) {
65
+ return [
66
+ 'LARP DETECTED — recorded follow-up',
67
+ '',
68
+ `Here is what the data showed: graded HIGH RISK ${Math.round(row.score * 100)}/100 at ${isoMinute(row.t0)} by ${row.model} (heuristic model output); ${outcomeText(row.outcome)} at the ${fmtAge(d.horizonSec)} follow-up.`,
69
+ '',
70
+ datasetLine(d),
71
+ '',
72
+ `Evidence: local dexterm recorder; DexScreener + Jupiter; t0 data age ${fmtAge((now - row.t0) / 1000)} at export; ${row.outcome.tier}; coin ${shortMint(row.mint)}.`,
73
+ '',
74
+ 'A risk flag is not a certificate. Draft only; a human decides whether to post. Not financial advice.',
75
+ ].join('\n') + '\n';
76
+ }
77
+ export function renderHistoryDrafts(d, opts) {
78
+ const now = opts.now ?? Date.now();
79
+ const min = opts.minSample ?? LARP_DRAFT_MIN_SAMPLE;
80
+ if (d.flagged.length < min)
81
+ return { drafts: [], cards: [] };
82
+ mkdirSync(opts.outDir, { recursive: true, mode: 0o700 });
83
+ const rows = [...d.collapsed].sort((a, b) => b.t0 - a.t0).slice(0, opts.limit ?? 3);
84
+ const drafts = [], cards = [];
85
+ for (let i = 0; i < rows.length; i++) {
86
+ const row = rows[i];
87
+ const stem = `${String(i + 1).padStart(2, '0')}-${row.mint.slice(0, 4)}-${row.mint.slice(-4)}`;
88
+ const draft = join(opts.outDir, `${stem}.md`);
89
+ writeFileSync(draft, historyDraft(row, d, now), { mode: 0o600 });
90
+ drafts.push(draft);
91
+ const view = {
92
+ kind: 'larp-detected', title: `RECORDED FOLLOW-UP · ${shortMint(row.mint)}`, label: 'replay', canvas: cardCanvas(row, d, now),
93
+ ages: [
94
+ { name: 't0 evidence', source: 'local recorder · DexScreener + Jupiter', ageSec: (now - row.t0) / 1000 },
95
+ { name: 'follow-up', source: `${row.outcome.tier} recorder outcome`, ageSec: d.horizonSec },
96
+ ],
97
+ report: historyDraft(row, d, now).trimEnd().split('\n'),
98
+ };
99
+ const saved = writeExport(view, { dir: opts.outDir, now: now + i, subject: stem });
100
+ cards.push(saved.png);
101
+ }
102
+ return { drafts, cards };
103
+ }
104
+ function parse(argv) {
105
+ const out = {};
106
+ for (let i = 0; i < argv.length; i++) {
107
+ const a = argv[i];
108
+ if (!a.startsWith('--'))
109
+ continue;
110
+ const value = argv[i + 1];
111
+ if (value !== undefined && !value.startsWith('--')) {
112
+ out[a.slice(2)] = value;
113
+ i++;
114
+ }
115
+ else
116
+ out[a.slice(2)] = true;
117
+ }
118
+ return out;
119
+ }
120
+ export const LARP_DETECTED_HELP = `dexterm larp-detected: local draft/card pipeline; never posts or schedules
121
+
122
+ dexterm larp-detected --out DIR [--db PATH] [--horizon SEC] [--limit 3]
123
+ dexterm larp-detected --live MINT --out DIR
124
+
125
+ History mode is cron-ready and offline: it reads recorder t0 rows plus later labels, requires at least
126
+ ${LARP_DRAFT_MIN_SAMPLE} unique flagged coins, and otherwise writes no drafts. Live mode performs one read-only
127
+ keyless lookup and writes a graded-now card. All output is for human review.`;
128
+ function liveFeatures(row) {
129
+ return rugFeaturesFromToken({
130
+ liquidity_usd: row.pair.liquidityUsd, mcap: row.mcap?.value ?? row.pair.mcap, age_sec: row.token.createdAt === null ? null : Math.max(0, (Date.now() - row.token.createdAt) / 1000),
131
+ top10_pct: row.audit?.top10Pct ?? null, dev_pct: row.audit?.devPct ?? null, organic_score: row.stats?.organicScore ?? null,
132
+ holder_count: row.stats?.holderCount ?? null, mint_authority: row.audit?.mintAuthority ?? null, freeze_authority: row.audit?.freezeAuthority ?? null,
133
+ });
134
+ }
135
+ async function liveCard(mint, outDir, dbPath, io) {
136
+ if (!/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(mint)) {
137
+ io.stderr.write('dexterm larp-detected: --live needs a Solana mint\n');
138
+ return 2;
139
+ }
140
+ const dl = createDataLayer({ dbPath });
141
+ try {
142
+ const result = await dl.store.enrich([mint]);
143
+ const row = result.rows[0];
144
+ if (!row) {
145
+ io.stderr.write('dexterm larp-detected: no current market record found for that mint\n');
146
+ return 2;
147
+ }
148
+ const now = Date.now(), model = h1Model(), score = model.score(liveFeatures(row));
149
+ const c = new Canvas(92, 20, THEMES.cyberspace), t = c.theme;
150
+ c.fill(0, 0, c.w, c.h, ' ', { bg: t.bg });
151
+ c.fill(0, 0, c.w, 3, ' ', { bg: t.headBg });
152
+ c.text(3, 1, 'LARP CHECK · GRADED NOW', { fg: t.warn, bg: t.headBg, b: true });
153
+ c.textR(0, 1, c.w - 3, shortMint(mint), { fg: t.muted, bg: t.headBg });
154
+ c.text(4, 6, `${score >= LARP_DRAFT_THRESHOLD ? 'HIGH RISK' : 'BELOW HIGH-RISK LINE'} ${Math.round(score * 100)}/100`, { fg: score >= LARP_DRAFT_THRESHOLD ? t.down : t.up, b: true });
155
+ c.text(4, 9, `${model.id} heuristic · model output · risk flag, not a certificate`, { fg: t.text });
156
+ c.text(4, 11, `${isoMinute(now)} · LIVE DATA · DexScreener + Jupiter`, { fg: t.muted });
157
+ c.text(4, 14, 'No later outcome yet. No person, project or wallet is identified.', { fg: t.text });
158
+ c.text(4, 17, 'Draft only · human review · not financial advice', { fg: t.muted });
159
+ const view = { kind: 'larp-now', title: `GRADED NOW · ${shortMint(mint)}`, label: 'live', canvas: c,
160
+ ages: [{ name: 'market', source: 'DexScreener + Jupiter', ageSec: Math.max(0, (now - Math.max(row.token.fetchedAt, row.pair.fetchedAt)) / 1000) }],
161
+ report: [`coin ${shortMint(mint)}`, `graded now ${Math.round(score * 100)}/100 · ${model.id} heuristic model output`, 'No later outcome yet. Risk flag, not a certificate. Draft only.'],
162
+ };
163
+ const saved = writeExport(view, { dir: outDir, now, subject: `${mint.slice(0, 4)}-${mint.slice(-4)}` });
164
+ io.stdout.write(`graded-now card: ${saved.png}\n`);
165
+ return 0;
166
+ }
167
+ finally {
168
+ dl.close();
169
+ }
170
+ }
171
+ export async function larpDetectedCommand(argv, io) {
172
+ const o = parse(argv);
173
+ if (o.help || o.h) {
174
+ io.stdout.write(LARP_DETECTED_HELP + '\n');
175
+ return 0;
176
+ }
177
+ const dbPath = typeof o.db === 'string' ? resolve(o.db) : (io.env.DEXTERM_DB_PATH || defaultDbPath(io.env));
178
+ const outDir = typeof o.out === 'string' ? resolve(o.out) : resolve('marketing', 'larp-detected', new Date().toISOString().slice(0, 10));
179
+ if (typeof o.live === 'string')
180
+ return liveCard(o.live, outDir, dbPath, io);
181
+ if (!existsSync(dbPath)) {
182
+ io.stderr.write(`dexterm larp-detected: no recorder history at ${dbPath}\n`);
183
+ return 2;
184
+ }
185
+ const horizon = typeof o.horizon === 'string' ? Number(o.horizon) : LARP_DRAFT_HORIZON;
186
+ if (!Number.isFinite(horizon) || horizon <= 0) {
187
+ io.stderr.write('dexterm larp-detected: --horizon must be positive seconds\n');
188
+ return 2;
189
+ }
190
+ const db = openHistoryReadOnly(dbPath);
191
+ if (!db) {
192
+ io.stderr.write('dexterm larp-detected: recorder database could not be opened read-only\n');
193
+ return 2;
194
+ }
195
+ try {
196
+ const dataset = buildFollowUpDataset(exportRecorded(db, { labelledOnly: true }).records, horizon);
197
+ if (dataset.flagged.length < LARP_DRAFT_MIN_SAMPLE) {
198
+ io.stdout.write(`thin sample: ${dataset.flagged.length} unique flagged coins (< ${LARP_DRAFT_MIN_SAMPLE}); wrote no drafts\n`);
199
+ return 0;
200
+ }
201
+ const limit = typeof o.limit === 'string' ? Math.max(0, Math.floor(Number(o.limit))) : 3;
202
+ const saved = renderHistoryDrafts(dataset, { outDir, limit: Number.isFinite(limit) ? limit : 3 });
203
+ io.stdout.write(`${datasetLine(dataset)}\nwrote ${saved.drafts.length} draft(s) and ${saved.cards.length} card(s) to ${outDir}\n`);
204
+ return 0;
205
+ }
206
+ finally {
207
+ db.close();
208
+ }
209
+ }
@@ -0,0 +1,99 @@
1
+ import { creatorOf, devHistoryLine, queryDevHistory } from '../../../recorder/src/index.js';
2
+ export const DEV_TTL_MS = 60_000;
3
+ /** Short creator/funder address for the panel (never a full address in a 40-column cell). */
4
+ export const shortAddr = (a) => (a ? `${a.slice(0, 4)}…${a.slice(-4)}` : '—');
5
+ export class DevHistoryBook {
6
+ cache = new Map();
7
+ db;
8
+ now;
9
+ ttlMs;
10
+ constructor(db, now = () => Date.now(), ttlMs = DEV_TTL_MS) {
11
+ this.db = db;
12
+ this.now = now;
13
+ this.ttlMs = ttlMs;
14
+ }
15
+ /**
16
+ * The entry for `mint` (cached for `ttlMs`). `creatorHint` is the dev wallet a source named on screen (Jupiter
17
+ * `dev`) for a coin the recorder has not linked yet; `intel` is the coin's settled wallet-intel scan, if any.
18
+ */
19
+ forMint(mint, creatorHint, intel) {
20
+ const now = this.now();
21
+ const hit = this.cache.get(mint);
22
+ if (hit && now - hit.at < this.ttlMs && (hit.creator || !creatorHint) && (hit.linked || !intel))
23
+ return hit;
24
+ const db = this.db() ?? null;
25
+ let creator = db ? creatorOf(db, mint) : null;
26
+ if (!creator && creatorHint && /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(creatorHint))
27
+ creator = { mint, creator: creatorHint, source: 'jupiter-tokens', firstT: now, createdAt: null };
28
+ let report = null;
29
+ let linked = null;
30
+ if (creator && db) {
31
+ try {
32
+ report = queryDevHistory(db, { creator: creator.creator, mint, asOf: now });
33
+ }
34
+ catch {
35
+ report = null;
36
+ }
37
+ }
38
+ if (creator && intel)
39
+ linked = linkedFrom(intel, creator.creator, db);
40
+ const line = !db ? 'unknown: the history recorder is off (--no-recorder / DEXTERM_RECORDER=0)'
41
+ : !creator ? 'unknown: no source named the creator yet'
42
+ : report ? devHistoryLine(report) : 'unknown: dev history unreadable';
43
+ const e = { mint, creator, report, linked, line, at: now };
44
+ this.cache.set(mint, e);
45
+ if (this.cache.size > 2000)
46
+ this.cache.delete(this.cache.keys().next().value);
47
+ return e;
48
+ }
49
+ /** The `devrugs` rule field: labelled prior rugs by this coin's creator; null = unknown (clauses on it are false). */
50
+ rugsFor(mint) {
51
+ const e = this.forMint(mint);
52
+ return e.report && e.report.labelled.n > 0 ? e.report.labelled.rug : null;
53
+ }
54
+ }
55
+ /** Linked wallets from a settled wallet-intel scan: the creator's funder and any multi-wallet cluster it sits in. */
56
+ export function linkedFrom(a, creator, db) {
57
+ const h = a.holders.find((x) => x.owner === creator);
58
+ const fundedBy = h?.funder?.address ?? a.funding[creator]?.funder ?? null;
59
+ const c = a.clusters.find((x) => x.members.includes(creator) && x.members.length > 1) ?? null;
60
+ let linkedCreators = 0, linkedRugs = 0;
61
+ if (c && db) {
62
+ try {
63
+ const others = c.members.filter((m) => m !== creator).slice(0, 50);
64
+ const launched = db.prepare('SELECT COUNT(*) AS n FROM creators WHERE creator = ?');
65
+ for (const w of others) {
66
+ if (Number(launched.get(w).n) <= 0)
67
+ continue;
68
+ linkedCreators++;
69
+ linkedRugs += queryDevHistory(db, { creator: w, devExit: false }).labelled.rug;
70
+ }
71
+ }
72
+ catch { /* an old DB without the table: nothing linked */ }
73
+ }
74
+ return { fundedBy, cluster: c ? { name: c.name, kind: c.kind, members: c.members.length, pct: c.pct } : null, linkedCreators, linkedRugs, source: h || c || a.funding[creator] ? 'wallet-intel scan' : null };
75
+ }
76
+ /** Rows for the token screen's DEV block: [label, value, level]. Every value names its source/sample/age or says unknown. */
77
+ export function devRows(e) {
78
+ const rows = [];
79
+ const r = e.report;
80
+ const rugLevel = () => !r || r.labelled.n === 0 ? 'na' : r.serialRugger ? 'bad' : r.labelled.rug > 0 || (r.badRate ?? 0) >= 0.5 ? 'warn' : 'ok';
81
+ rows.push(['Dev rugs (recorded)', r && r.labelled.n ? `${r.labelled.rug}/${r.labelled.n} · n=${r.labelled.n}` : 'unknown', rugLevel()]);
82
+ rows.push(['Dev launches seen', r && r.status === 'ok' ? `${r.launches.n} prior · ${e.creator?.source === 'jupiter-tokens' ? 'jup' : e.creator?.source ?? ''}` : 'unknown', 'na']);
83
+ if (r && r.devExit.n)
84
+ rows.push(['Dev sold its bag', `median ${Math.round(r.devExit.medianMin)}m · n=${r.devExit.n}`, r.devExit.medianMin <= 60 ? 'warn' : 'ok']);
85
+ const l = e.linked;
86
+ if (l && (l.fundedBy || l.cluster))
87
+ rows.push(['Dev linked', l.cluster ? `${l.cluster.kind} ${l.cluster.members}w${l.linkedCreators ? ` · ${l.linkedCreators} devs ${l.linkedRugs} rugs` : ''}` : `funded by ${shortAddr(l.fundedBy)}`, l.linkedRugs > 0 ? 'bad' : 'na']);
88
+ return rows;
89
+ }
90
+ /** The app's one book (created on first use), reading the live recorder's DB. Null when there is no recorder. */
91
+ export function devBookOf(state) {
92
+ if (!state.live?.recorder)
93
+ return null;
94
+ if (!state.devBook) {
95
+ const live = state.live;
96
+ state.devBook = new DevHistoryBook(() => live?.recorder?.database ?? null);
97
+ }
98
+ return state.devBook;
99
+ }
@@ -20,6 +20,8 @@ export class NewPairsLive {
20
20
  dl;
21
21
  now;
22
22
  onChange;
23
+ /** 0.1.5 dev history: called once per row when its creator becomes known (the recorder stores the link). */
24
+ onCreator;
23
25
  limit;
24
26
  polls;
25
27
  rows = new Map();
@@ -84,6 +86,12 @@ export class NewPairsLive {
84
86
  this.mode = 'replay';
85
87
  return this.client.replay(rec, speed);
86
88
  }
89
+ tellCreator(mint, creator, source, createdAt) {
90
+ try {
91
+ this.onCreator?.(mint, creator, source, createdAt);
92
+ }
93
+ catch { /* the recorder must never break the feed */ }
94
+ }
87
95
  addCreate(c) {
88
96
  const rowAt = this.now();
89
97
  const existing = this.rows.get(c.mint);
@@ -105,6 +113,8 @@ export class NewPairsLive {
105
113
  }
106
114
  else {
107
115
  this.rows.set(c.mint, row);
116
+ if (row.creator)
117
+ this.tellCreator(c.mint, row.creator, c.creator ? 'pumpportal' : 'rugcheck', row.createdAt);
108
118
  this.latencies.push(row.latencyMs);
109
119
  if (this.latencies.length > 500)
110
120
  this.latencies.shift();
@@ -227,6 +237,8 @@ export class NewPairsLive {
227
237
  const row = this.rows.get(t.mint);
228
238
  if (!row)
229
239
  continue;
240
+ if (!row.creator && t.creator)
241
+ this.tellCreator(t.mint, t.creator, 'rugcheck', row.createdAt);
230
242
  row.creator = row.creator ?? t.creator;
231
243
  if (t.mintAuthority !== null)
232
244
  row.mintAuth = t.mintAuthority;
@@ -15,6 +15,7 @@ import { drawCoin, imagesOn } from "../../screens/coin.js";
15
15
  import { COIN_HERO_W, COIN_HERO_H } from '../../../../tui/src/index.js';
16
16
  import { renderSocialPanel } from "../../screens/social-panel.js";
17
17
  import { launchIntelCells, holderTags } from "../intel.js";
18
+ import { devBookOf, devRows } from "../dev-history.js";
18
19
  import { EX_POOL_TAGS } from '../../../../data/src/index.js';
19
20
  import { layoutFor } from "../../custom.js";
20
21
  import { chartMode, priceModeOf, mcapAt, positionPriceCells } from "../../display.js";
@@ -178,6 +179,12 @@ export function renderTokenLive(c, state, v) {
178
179
  const top10Rows = tags.top10
179
180
  ? [['Top 10 ex-pool', `${tags.top10.exPool.toFixed(1)}%`, t10lvl(tags.top10.exPool)], ['Top 10 raw', `${tags.top10.raw.toFixed(1)}%`, 'na']]
180
181
  : [['Top 10 holders', ...(v.top10 === null ? na(v.panels.holders.state === 'needs-key' ? 'needs key' : dash) : [`${v.top10.toFixed(1)}%${v.panels.holders.state === 'ok' ? '' : ' (jup)'}`, t10lvl(v.top10)])]];
182
+ // 0.1.5 dev history (task-1425): the creator's recorded track record from the local recorder (keyless). The rugs
183
+ // row sits with the other rug signals; launches / bag-exit / linked wallets follow the safety list.
184
+ const book = devBookOf(state);
185
+ const devAll = book ? devRows(book.forMint(v.mint, v.devAddress ?? null, state.live?.intel?.analysis(v.mint) ?? null)) : [];
186
+ const devHead = devAll.slice(0, 1);
187
+ const devTail = devAll.slice(1);
181
188
  const sniperRow = [cells.snipers.text, cells.snipers.level];
182
189
  const bundleRow = [cells.bundle.text, cells.bundle.level];
183
190
  const rows = [
@@ -189,8 +196,10 @@ export function renderTokenLive(c, state, v) {
189
196
  ['Mint authority', ...(v.mintAuth === null ? na(dash) : [v.mintAuth ? 'ENABLED' : 'revoked', v.mintAuth ? 'bad' : 'ok'])],
190
197
  ['Freeze authority', ...(v.freezeAuth === null ? na(dash) : [v.freezeAuth ? 'ENABLED' : 'revoked', v.freezeAuth ? 'bad' : 'ok'])],
191
198
  ['Dev history', ...(v.devMints === null ? needsHistory : [`${v.devMints} mints by dev (jup)`, v.devMints > 3 ? 'warn' : 'ok'])],
199
+ ...devHead,
192
200
  ['RugCheck score', ...(v.rug === null || v.rug.score === null ? na(v.panels.rugcheck.state === 'error' ? `unavailable: ${v.panels.rugcheck.reason ?? ''}`.trim() : dash) : [`${Math.round(v.rug.score)}/100`, v.rug.score < 30 ? 'ok' : v.rug.score < 60 ? 'warn' : 'bad'])],
193
201
  ['GoPlus', ...goplusRow(v)],
202
+ ...devTail,
194
203
  ];
195
204
  for (const [label, val0, lvl] of rows) {
196
205
  if (sy >= sb.y + sb.h)
@@ -435,7 +444,8 @@ function analystPlaceholder(c, x, y, w, h, v, state) {
435
444
  // task-1311 (QA M5): the pre-run state. Opening a token no longer spends a paid dossier; this panel
436
445
  // waits until you ask for one with `a` (dossier) or type a question with `i`. No fake verdicts.
437
446
  const t = c.theme;
438
- const box = c.box(x, y, w, h, { title: '✦ ANALYST · claude', titleFg: t.ai, caption: 'read-only · local claude · on demand', captionFg: t.dim, border: mix(t.border, t.ai, 0.35) });
447
+ const eng = state.analystEngine ?? 'claude'; // 0.1.5: the user's own CLI that will answer
448
+ const box = c.box(x, y, w, h, { title: `✦ ANALYST · ${eng}`, titleFg: t.ai, caption: `read-only · local ${eng} · on demand`, captionFg: t.dim, border: mix(t.border, t.ai, 0.35) });
439
449
  const bg = box.bg;
440
450
  const inner = box.w - 2;
441
451
  let cy = box.y;
@@ -266,6 +266,7 @@ export class TokenLive {
266
266
  v.top10 = audit?.top10Pct ?? v.top10;
267
267
  v.dev = audit?.devPct ?? null;
268
268
  v.devMints = audit?.devMints ?? null;
269
+ v.devAddress = audit?.devAddress ?? v.devAddress ?? null;
269
270
  v.sources = [...new Set([...v.sources, ...r.sources])];
270
271
  const SHORT = { dexscreener: 'ds', 'jupiter-tokens': 'jup', 'jupiter-price': 'jup-price' };
271
272
  this.ok('market', r.sources.map((x) => SHORT[x] ?? x).join('+'), pair.fetchedAt, r.stale);
@@ -473,6 +474,9 @@ export class CandlePrefetcher {
473
474
  timer = null;
474
475
  busy = false;
475
476
  closed = false;
477
+ settledPromise = Promise.resolve();
478
+ resolveSettled = null;
479
+ waitingForSettled = false;
476
480
  stamps = [];
477
481
  /** Requests actually sent (granted by the limiter). */
478
482
  requests = 0;
@@ -494,9 +498,25 @@ export class CandlePrefetcher {
494
498
  return;
495
499
  if (t && this.target && t.mint === this.target.mint && t.pair === this.target.pair)
496
500
  return; // same row: keep waiting
501
+ this.finishSettled(); // a replaced target can no longer do useful work for its caller
497
502
  this.target = t;
503
+ if (t?.pair)
504
+ this.settledPromise = new Promise((resolve) => { this.resolveSettled = resolve; });
498
505
  this.schedule(this.opts.debounceMs);
499
506
  }
507
+ /**
508
+ * Resolve after the current hover pass has warmed every immediately available base, explicitly
509
+ * deferred the next attempt, failed a real request, been replaced, or been cancelled by close(). This
510
+ * is the completion contract for callers that need to observe the pass result; a debounce timer firing
511
+ * alone does not mean its sequential requests have finished.
512
+ */
513
+ settled() {
514
+ if (this.resolveSettled) {
515
+ this.waitingForSettled = true;
516
+ this.timer?.ref?.();
517
+ }
518
+ return this.settledPromise;
519
+ }
500
520
  /** Requests sent in the trailing 60 s. */
501
521
  rate() {
502
522
  const now = this.opts.now();
@@ -511,6 +531,7 @@ export class CandlePrefetcher {
511
531
  clearTimeout(this.timer);
512
532
  this.timer = null;
513
533
  }
534
+ this.finishSettled();
514
535
  }
515
536
  schedule(ms) {
516
537
  if (this.timer) {
@@ -521,7 +542,10 @@ export class CandlePrefetcher {
521
542
  if (!t || !t.pair || this.closed)
522
543
  return;
523
544
  this.timer = setTimeout(() => { this.timer = null; void this.step(t); }, Math.max(0, ms));
524
- this.timer.unref?.();
545
+ if (this.waitingForSettled)
546
+ this.timer.ref?.();
547
+ else
548
+ this.timer.unref?.();
525
549
  }
526
550
  bases() {
527
551
  const iv = this.opts.interval();
@@ -541,6 +565,7 @@ export class CandlePrefetcher {
541
565
  continue;
542
566
  if (this.rate() >= this.opts.maxPerMin) {
543
567
  this.schedule(this.stamps[0] + 60_000 - this.opts.now() + 50);
568
+ this.finishSettled(t);
544
569
  return;
545
570
  }
546
571
  this.busy = true;
@@ -554,9 +579,11 @@ export class CandlePrefetcher {
554
579
  // Try again when the bucket could be idle again (still only if the cursor stays here).
555
580
  const wait = this.dl.limiter.bucket('geckoterminal').delayFor('idle', this.opts.now());
556
581
  this.schedule(Number.isFinite(wait) ? Math.max(250, wait) : 60_000);
582
+ this.finishSettled(t);
557
583
  return;
558
584
  }
559
585
  this.sent(); // a real request that failed (HTTP error) still counts against the budget
586
+ this.finishSettled(t);
560
587
  return;
561
588
  }
562
589
  finally {
@@ -565,6 +592,17 @@ export class CandlePrefetcher {
565
592
  if (this.closed || this.target !== t)
566
593
  return; // the cursor moved on: its own debounce takes over
567
594
  }
595
+ this.finishSettled(t);
596
+ }
597
+ finishSettled(t) {
598
+ if (t && this.target !== t)
599
+ return;
600
+ const resolve = this.resolveSettled;
601
+ this.resolveSettled = null;
602
+ if (this.waitingForSettled)
603
+ this.timer?.unref?.();
604
+ this.waitingForSettled = false;
605
+ resolve?.();
568
606
  }
569
607
  sent() {
570
608
  this.requests++;