dexterm-cli 0.0.0-stage → 0.1.1

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 (349) hide show
  1. package/LICENSE +661 -0
  2. package/dist/packages/agents/src/audit.js +122 -0
  3. package/dist/packages/agents/src/bus.js +379 -0
  4. package/dist/packages/agents/src/executor.js +177 -0
  5. package/dist/packages/agents/src/gate.js +176 -0
  6. package/dist/packages/agents/src/identity.js +179 -0
  7. package/dist/packages/agents/src/index.js +15 -0
  8. package/dist/packages/agents/src/proposals.js +153 -0
  9. package/dist/packages/agents/src/schema.js +87 -0
  10. package/dist/packages/agents/src/sdk.js +140 -0
  11. package/dist/packages/agents/src/tiers.js +114 -0
  12. package/dist/packages/agents/src/tools.js +69 -0
  13. package/dist/packages/agents/src/ws.js +158 -0
  14. package/dist/packages/cli/assets/claude/analyst-system.md +76 -0
  15. package/dist/packages/cli/assets/claude/plugin/.claude-plugin/plugin.json +5 -0
  16. package/dist/packages/cli/assets/claude/plugin/skills/REGISTRY.json +16 -0
  17. package/dist/packages/cli/assets/claude/plugin/skills/larp-check/SKILL.md +67 -0
  18. package/dist/packages/cli/assets/claude/plugin/skills/rug-check/SKILL.md +64 -0
  19. package/dist/packages/cli/assets/claude/plugin/skills/token-dossier/SKILL.md +63 -0
  20. package/dist/packages/cli/assets/claude/plugin/skills/trench-scan/SKILL.md +44 -0
  21. package/dist/packages/cli/assets/claude/schemas/larp.schema.json +117 -0
  22. package/dist/packages/cli/assets/claude/schemas/trench-scan.schema.json +71 -0
  23. package/dist/packages/cli/assets/claude/schemas/verdict.schema.json +115 -0
  24. package/dist/packages/cli/bin/dexterm.mjs +11 -0
  25. package/dist/packages/cli/src/agent-cmd.js +303 -0
  26. package/dist/packages/cli/src/agent-roster.js +26 -0
  27. package/dist/packages/cli/src/analyst/backend.js +526 -0
  28. package/dist/packages/cli/src/analyst/results.js +38 -0
  29. package/dist/packages/cli/src/analyst/session.js +319 -0
  30. package/dist/packages/cli/src/audit.js +51 -0
  31. package/dist/packages/cli/src/backtest-cmd.js +149 -0
  32. package/dist/packages/cli/src/boot-state.js +62 -0
  33. package/dist/packages/cli/src/custom.js +261 -0
  34. package/dist/packages/cli/src/display.js +191 -0
  35. package/dist/packages/cli/src/doctor.js +361 -0
  36. package/dist/packages/cli/src/feed.js +634 -0
  37. package/dist/packages/cli/src/fixtures.js +275 -0
  38. package/dist/packages/cli/src/follow-cmd.js +221 -0
  39. package/dist/packages/cli/src/images-config.js +59 -0
  40. package/dist/packages/cli/src/index.js +31 -0
  41. package/dist/packages/cli/src/kb-skill-cmd.js +240 -0
  42. package/dist/packages/cli/src/larp-record.js +21 -0
  43. package/dist/packages/cli/src/live/copy.js +80 -0
  44. package/dist/packages/cli/src/live/flow.js +233 -0
  45. package/dist/packages/cli/src/live/index.js +509 -0
  46. package/dist/packages/cli/src/live/intel.js +227 -0
  47. package/dist/packages/cli/src/live/newpairs.js +334 -0
  48. package/dist/packages/cli/src/live/screens/newpairs-live.js +219 -0
  49. package/dist/packages/cli/src/live/screens/token-live.js +459 -0
  50. package/dist/packages/cli/src/live/screens/watchlist-live.js +149 -0
  51. package/dist/packages/cli/src/live/token.js +585 -0
  52. package/dist/packages/cli/src/live/trade.js +929 -0
  53. package/dist/packages/cli/src/live/watchlist.js +178 -0
  54. package/dist/packages/cli/src/main.js +5583 -0
  55. package/dist/packages/cli/src/narrative-cmd.js +76 -0
  56. package/dist/packages/cli/src/pack-cmd.js +323 -0
  57. package/dist/packages/cli/src/plan-cmd.js +278 -0
  58. package/dist/packages/cli/src/popup.js +810 -0
  59. package/dist/packages/cli/src/rules-cmd.js +131 -0
  60. package/dist/packages/cli/src/rules.js +339 -0
  61. package/dist/packages/cli/src/scan/command.js +57 -0
  62. package/dist/packages/cli/src/scan/engine.js +419 -0
  63. package/dist/packages/cli/src/scan/observe.js +64 -0
  64. package/dist/packages/cli/src/scan/ui.js +98 -0
  65. package/dist/packages/cli/src/screener/filter.js +241 -0
  66. package/dist/packages/cli/src/screener/presets.js +80 -0
  67. package/dist/packages/cli/src/screener/rows.js +146 -0
  68. package/dist/packages/cli/src/screener/rug.js +50 -0
  69. package/dist/packages/cli/src/screener/sort.js +52 -0
  70. package/dist/packages/cli/src/screener/view.js +183 -0
  71. package/dist/packages/cli/src/screens/analyst-session.js +343 -0
  72. package/dist/packages/cli/src/screens/analyst.js +326 -0
  73. package/dist/packages/cli/src/screens/boot.js +74 -0
  74. package/dist/packages/cli/src/screens/bubbles.js +255 -0
  75. package/dist/packages/cli/src/screens/coin.js +33 -0
  76. package/dist/packages/cli/src/screens/follows.js +201 -0
  77. package/dist/packages/cli/src/screens/kol.js +90 -0
  78. package/dist/packages/cli/src/screens/narrative.js +90 -0
  79. package/dist/packages/cli/src/screens/newpairs.js +150 -0
  80. package/dist/packages/cli/src/screens/overlay.js +257 -0
  81. package/dist/packages/cli/src/screens/plans.js +126 -0
  82. package/dist/packages/cli/src/screens/positions.js +176 -0
  83. package/dist/packages/cli/src/screens/rules.js +170 -0
  84. package/dist/packages/cli/src/screens/screener.js +459 -0
  85. package/dist/packages/cli/src/screens/social-panel.js +107 -0
  86. package/dist/packages/cli/src/screens/ticket.js +342 -0
  87. package/dist/packages/cli/src/screens/token.js +312 -0
  88. package/dist/packages/cli/src/screens/trending.js +181 -0
  89. package/dist/packages/cli/src/screens/watchlist.js +104 -0
  90. package/dist/packages/cli/src/social/demo.js +96 -0
  91. package/dist/packages/cli/src/social/view.js +250 -0
  92. package/dist/packages/cli/src/state.js +463 -0
  93. package/dist/packages/cli/src/theme-cmd.js +126 -0
  94. package/dist/packages/cli/src/trade.js +319 -0
  95. package/dist/packages/cli/src/voice-hud.js +42 -0
  96. package/dist/packages/cli/src/wallet-cmd.js +440 -0
  97. package/dist/packages/cli/src/wallet-command.js +31 -0
  98. package/dist/packages/cli/src/widgets.js +208 -0
  99. package/dist/packages/cli/src/workspace-cmd.js +68 -0
  100. package/dist/packages/cli/src/x-cmd.js +154 -0
  101. package/dist/packages/custom/src/config.js +213 -0
  102. package/dist/packages/custom/src/index.js +10 -0
  103. package/dist/packages/custom/src/keymap.js +107 -0
  104. package/dist/packages/custom/src/layout.js +235 -0
  105. package/dist/packages/custom/src/packs.js +633 -0
  106. package/dist/packages/custom/src/rules.js +704 -0
  107. package/dist/packages/custom/src/schema.js +515 -0
  108. package/dist/packages/custom/src/themes.js +176 -0
  109. package/dist/packages/custom/src/widget-html.js +222 -0
  110. package/dist/packages/custom/src/workspace.js +141 -0
  111. package/dist/packages/data/src/analyst-actions.js +133 -0
  112. package/dist/packages/data/src/budget.js +88 -0
  113. package/dist/packages/data/src/cache.js +142 -0
  114. package/dist/packages/data/src/candles.js +168 -0
  115. package/dist/packages/data/src/clock.js +64 -0
  116. package/dist/packages/data/src/credits.js +137 -0
  117. package/dist/packages/data/src/detail.js +97 -0
  118. package/dist/packages/data/src/fast-lane.js +321 -0
  119. package/dist/packages/data/src/fixtures.js +135 -0
  120. package/dist/packages/data/src/health.js +245 -0
  121. package/dist/packages/data/src/http.js +277 -0
  122. package/dist/packages/data/src/images/cache.js +141 -0
  123. package/dist/packages/data/src/images/decode-worker.js +28 -0
  124. package/dist/packages/data/src/images/decode.js +81 -0
  125. package/dist/packages/data/src/images/fetch.js +162 -0
  126. package/dist/packages/data/src/images/gif.js +214 -0
  127. package/dist/packages/data/src/images/index.js +10 -0
  128. package/dist/packages/data/src/images/jpeg.js +544 -0
  129. package/dist/packages/data/src/images/png.js +310 -0
  130. package/dist/packages/data/src/images/service.js +334 -0
  131. package/dist/packages/data/src/images/types.js +27 -0
  132. package/dist/packages/data/src/index.js +208 -0
  133. package/dist/packages/data/src/intel/helius-history.js +59 -0
  134. package/dist/packages/data/src/intel/holder-class.js +125 -0
  135. package/dist/packages/data/src/intel/rules.js +421 -0
  136. package/dist/packages/data/src/intel/scan.js +170 -0
  137. package/dist/packages/data/src/larp/evidence.js +288 -0
  138. package/dist/packages/data/src/larp/links.js +137 -0
  139. package/dist/packages/data/src/larp/robots.js +90 -0
  140. package/dist/packages/data/src/larp/safe-fetch.js +389 -0
  141. package/dist/packages/data/src/limiter.js +341 -0
  142. package/dist/packages/data/src/model.js +12 -0
  143. package/dist/packages/data/src/paper.js +331 -0
  144. package/dist/packages/data/src/rpc-config.js +126 -0
  145. package/dist/packages/data/src/rpc-pool.js +166 -0
  146. package/dist/packages/data/src/social/chain.js +83 -0
  147. package/dist/packages/data/src/social/dedupe.js +205 -0
  148. package/dist/packages/data/src/social/feed.js +462 -0
  149. package/dist/packages/data/src/social/firewall.js +110 -0
  150. package/dist/packages/data/src/social/index.js +11 -0
  151. package/dist/packages/data/src/social/kol.js +269 -0
  152. package/dist/packages/data/src/social/model.js +11 -0
  153. package/dist/packages/data/src/social/rank.js +184 -0
  154. package/dist/packages/data/src/social/rss.js +113 -0
  155. package/dist/packages/data/src/social/summary.js +104 -0
  156. package/dist/packages/data/src/social/venues.js +186 -0
  157. package/dist/packages/data/src/sources/dexscreener.js +170 -0
  158. package/dist/packages/data/src/sources/geckoterminal.js +133 -0
  159. package/dist/packages/data/src/sources/goplus.js +161 -0
  160. package/dist/packages/data/src/sources/jupiter-swap.js +236 -0
  161. package/dist/packages/data/src/sources/jupiter.js +198 -0
  162. package/dist/packages/data/src/sources/pda.js +113 -0
  163. package/dist/packages/data/src/sources/pump-curve.js +58 -0
  164. package/dist/packages/data/src/sources/pumpportal.js +247 -0
  165. package/dist/packages/data/src/sources/rugcheck.js +71 -0
  166. package/dist/packages/data/src/sources/solana-rpc.js +299 -0
  167. package/dist/packages/data/src/sources/solana-ws.js +287 -0
  168. package/dist/packages/data/src/store.js +289 -0
  169. package/dist/packages/data/src/trade/bridge.js +464 -0
  170. package/dist/packages/data/src/trade/caps.js +323 -0
  171. package/dist/packages/data/src/trade/copy/auto.js +385 -0
  172. package/dist/packages/data/src/trade/copy/follows.js +103 -0
  173. package/dist/packages/data/src/trade/copy/index.js +9 -0
  174. package/dist/packages/data/src/trade/copy/mirror.js +91 -0
  175. package/dist/packages/data/src/trade/copy/stats.js +120 -0
  176. package/dist/packages/data/src/trade/copy/tracker.js +158 -0
  177. package/dist/packages/data/src/trade/copy/trades.js +87 -0
  178. package/dist/packages/data/src/trade/copy/types.js +6 -0
  179. package/dist/packages/data/src/trade/executor.js +933 -0
  180. package/dist/packages/data/src/trade/kill-switch.js +47 -0
  181. package/dist/packages/data/src/trade/link-store.js +52 -0
  182. package/dist/packages/data/src/trade/plans/confirm.js +157 -0
  183. package/dist/packages/data/src/trade/plans/engine.js +784 -0
  184. package/dist/packages/data/src/trade/plans/executor-live.js +220 -0
  185. package/dist/packages/data/src/trade/plans/executor-paper.js +44 -0
  186. package/dist/packages/data/src/trade/plans/executor.js +11 -0
  187. package/dist/packages/data/src/trade/plans/index.js +12 -0
  188. package/dist/packages/data/src/trade/plans/journal.js +77 -0
  189. package/dist/packages/data/src/trade/plans/mandate.js +129 -0
  190. package/dist/packages/data/src/trade/plans/plan.js +179 -0
  191. package/dist/packages/data/src/trade/plans/service.js +168 -0
  192. package/dist/packages/data/src/trade/plans/types.js +6 -0
  193. package/dist/packages/data/src/trade/rpc-exec.js +229 -0
  194. package/dist/packages/data/src/trade/signer/client.js +197 -0
  195. package/dist/packages/data/src/trade/signer/fast-wallet.js +154 -0
  196. package/dist/packages/data/src/trade/signer/host.js +97 -0
  197. package/dist/packages/data/src/trade/signer/main.js +121 -0
  198. package/dist/packages/data/src/trade/signer/probe-builder.js +85 -0
  199. package/dist/packages/data/src/trade/signer/protocol.js +92 -0
  200. package/dist/packages/data/src/trade/signer/service.js +400 -0
  201. package/dist/packages/data/src/trade/signer/sol-usd-feed.js +98 -0
  202. package/dist/packages/data/src/trade/sol-usd.js +86 -0
  203. package/dist/packages/data/src/trade/swap-build.js +108 -0
  204. package/dist/packages/data/src/trade/token-delta.js +201 -0
  205. package/dist/packages/data/src/trade/tx-decode.js +632 -0
  206. package/dist/packages/data/src/util.js +24 -0
  207. package/dist/packages/data/src/watchlist.js +176 -0
  208. package/dist/packages/data/src/x/api.js +256 -0
  209. package/dist/packages/data/src/x/budget.js +66 -0
  210. package/dist/packages/data/src/x/config.js +49 -0
  211. package/dist/packages/data/src/x/index.js +10 -0
  212. package/dist/packages/data/src/x/mock-server.js +217 -0
  213. package/dist/packages/data/src/x/oauth.js +242 -0
  214. package/dist/packages/data/src/x/pkce.js +21 -0
  215. package/dist/packages/data/src/x/source.js +285 -0
  216. package/dist/packages/data/src/x/token-store.js +134 -0
  217. package/dist/packages/data/src/x/transport.js +71 -0
  218. package/dist/packages/data/vendor/solana-web3/LICENSE +20 -0
  219. package/dist/packages/data/vendor/solana-web3/NOTICE.md +13 -0
  220. package/dist/packages/data/vendor/solana-web3/index.iife.min.js +20 -0
  221. package/dist/packages/mcp/assets/cases.json +1194 -0
  222. package/dist/packages/mcp/assets/kb/entries/cabal-and-coordinated-launches.md +28 -0
  223. package/dist/packages/mcp/assets/kb/entries/common-rug-patterns.md +40 -0
  224. package/dist/packages/mcp/assets/kb/entries/dbc-mechanics.md +30 -0
  225. package/dist/packages/mcp/assets/kb/entries/dev-wallet-behaviour.md +33 -0
  226. package/dist/packages/mcp/assets/kb/entries/glossary.md +35 -0
  227. package/dist/packages/mcp/assets/kb/entries/holder-concentration.md +30 -0
  228. package/dist/packages/mcp/assets/kb/entries/jito-bundles.md +29 -0
  229. package/dist/packages/mcp/assets/kb/entries/launchlab-curve.md +31 -0
  230. package/dist/packages/mcp/assets/kb/entries/lp-burn-vs-lock.md +31 -0
  231. package/dist/packages/mcp/assets/kb/entries/metadata-and-copycats.md +29 -0
  232. package/dist/packages/mcp/assets/kb/entries/mint-freeze-authority.md +31 -0
  233. package/dist/packages/mcp/assets/kb/entries/narrative-lifecycle.md +32 -0
  234. package/dist/packages/mcp/assets/kb/entries/pump-bonding-curve.md +33 -0
  235. package/dist/packages/mcp/assets/kb/entries/pumpswap-migration.md +29 -0
  236. package/dist/packages/mcp/assets/kb/entries/sniping-and-snipers.md +29 -0
  237. package/dist/packages/mcp/assets/kb/entries/token2022-extensions-risk.md +32 -0
  238. package/dist/packages/mcp/assets/kb/entries/wash-trading-fake-volume.md +33 -0
  239. package/dist/packages/mcp/assets/skills/rug-check.md +52 -0
  240. package/dist/packages/mcp/assets/skills/token-dossier.md +57 -0
  241. package/dist/packages/mcp/assets/skills/trench-scan.md +40 -0
  242. package/dist/packages/mcp/bin/dexterm-mcp.mjs +16 -0
  243. package/dist/packages/mcp/src/dossier.js +78 -0
  244. package/dist/packages/mcp/src/firewall.js +21 -0
  245. package/dist/packages/mcp/src/index.js +22 -0
  246. package/dist/packages/mcp/src/server.js +849 -0
  247. package/dist/packages/mcp/src/user-content.js +434 -0
  248. package/dist/packages/packs/src/backtest.js +183 -0
  249. package/dist/packages/packs/src/digest.js +95 -0
  250. package/dist/packages/packs/src/firewall.js +57 -0
  251. package/dist/packages/packs/src/index.js +19 -0
  252. package/dist/packages/packs/src/larp-eval.js +100 -0
  253. package/dist/packages/packs/src/narrative.js +309 -0
  254. package/dist/packages/packs/src/reason.js +135 -0
  255. package/dist/packages/packs/src/rug-model.js +137 -0
  256. package/dist/packages/packs/src/schema.js +54 -0
  257. package/dist/packages/packs/src/token-dossier.js +174 -0
  258. package/dist/packages/packs/src/verdicts.js +17 -0
  259. package/dist/packages/packs/src/wallet-dossier.js +105 -0
  260. package/dist/packages/popup/src/config.js +71 -0
  261. package/dist/packages/popup/src/dock.js +271 -0
  262. package/dist/packages/popup/src/host.js +210 -0
  263. package/dist/packages/popup/src/index.js +12 -0
  264. package/dist/packages/popup/src/loopback.js +53 -0
  265. package/dist/packages/popup/src/open.js +183 -0
  266. package/dist/packages/popup/src/pages/bubbles-lib.js +160 -0
  267. package/dist/packages/popup/src/pages/bubbles.css +23 -0
  268. package/dist/packages/popup/src/pages/bubbles.html +36 -0
  269. package/dist/packages/popup/src/pages/bubbles.js +214 -0
  270. package/dist/packages/popup/src/pages/chart-lib.js +262 -0
  271. package/dist/packages/popup/src/pages/chart.css +50 -0
  272. package/dist/packages/popup/src/pages/chart.html +56 -0
  273. package/dist/packages/popup/src/pages/chart.js +554 -0
  274. package/dist/packages/popup/src/pages/common.css +34 -0
  275. package/dist/packages/popup/src/pages/common.js +187 -0
  276. package/dist/packages/popup/src/pages/feeds.html +20 -0
  277. package/dist/packages/popup/src/pages/feeds.js +77 -0
  278. package/dist/packages/popup/src/pages/narrative.html +20 -0
  279. package/dist/packages/popup/src/pages/narrative.js +61 -0
  280. package/dist/packages/popup/src/pages/plans.css +30 -0
  281. package/dist/packages/popup/src/pages/plans.html +26 -0
  282. package/dist/packages/popup/src/pages/plans.js +82 -0
  283. package/dist/packages/popup/src/pages/roster.css +41 -0
  284. package/dist/packages/popup/src/pages/roster.html +25 -0
  285. package/dist/packages/popup/src/pages/roster.js +75 -0
  286. package/dist/packages/popup/src/pages/token.html +20 -0
  287. package/dist/packages/popup/src/pages/token.js +112 -0
  288. package/dist/packages/popup/src/pages/widget-sdk.js +224 -0
  289. package/dist/packages/popup/src/pages/widget.css +5 -0
  290. package/dist/packages/popup/src/pages/widget.html +21 -0
  291. package/dist/packages/popup/src/pages/widget.js +85 -0
  292. package/dist/packages/popup/src/protocol.js +31 -0
  293. package/dist/packages/popup/src/selftest.js +156 -0
  294. package/dist/packages/popup/src/server.js +582 -0
  295. package/dist/packages/popup/src/sinkproxy.js +167 -0
  296. package/dist/packages/popup/src/widget-html.js +231 -0
  297. package/dist/packages/popup/vendor/lightweight-charts/LICENSE +201 -0
  298. package/dist/packages/popup/vendor/lightweight-charts/NOTICE +2 -0
  299. package/dist/packages/popup/vendor/lightweight-charts/README.md +30 -0
  300. package/dist/packages/popup/vendor/lightweight-charts/VERSION +1 -0
  301. package/dist/packages/popup/vendor/lightweight-charts/lightweight-charts.standalone.production.js +7 -0
  302. package/dist/packages/recorder/bin/dexterm-recorder.mjs +11 -0
  303. package/dist/packages/recorder/src/cli.js +113 -0
  304. package/dist/packages/recorder/src/export.js +71 -0
  305. package/dist/packages/recorder/src/index.js +20 -0
  306. package/dist/packages/recorder/src/labels.js +151 -0
  307. package/dist/packages/recorder/src/open.js +29 -0
  308. package/dist/packages/recorder/src/recorder.js +553 -0
  309. package/dist/packages/recorder/src/schedule.js +43 -0
  310. package/dist/packages/recorder/src/schema.js +135 -0
  311. package/dist/packages/recorder/src/snapshot.js +191 -0
  312. package/dist/packages/recorder/src/sweep.js +52 -0
  313. package/dist/packages/recorder/src/verdicts.js +52 -0
  314. package/dist/packages/tui/src/bubbles.js +415 -0
  315. package/dist/packages/tui/src/canvas.js +370 -0
  316. package/dist/packages/tui/src/chrome.js +85 -0
  317. package/dist/packages/tui/src/color.js +133 -0
  318. package/dist/packages/tui/src/flush.js +62 -0
  319. package/dist/packages/tui/src/fmt.js +188 -0
  320. package/dist/packages/tui/src/fx-trade.js +278 -0
  321. package/dist/packages/tui/src/fx.js +527 -0
  322. package/dist/packages/tui/src/images/blocks.js +141 -0
  323. package/dist/packages/tui/src/images/coin.js +22 -0
  324. package/dist/packages/tui/src/images/detect.js +140 -0
  325. package/dist/packages/tui/src/images/index.js +7 -0
  326. package/dist/packages/tui/src/images/layer.js +146 -0
  327. package/dist/packages/tui/src/images/pixels.js +157 -0
  328. package/dist/packages/tui/src/images/protocols.js +87 -0
  329. package/dist/packages/tui/src/index.js +15 -0
  330. package/dist/packages/tui/src/keymap.js +355 -0
  331. package/dist/packages/tui/src/layout.js +11 -0
  332. package/dist/packages/tui/src/sound.js +177 -0
  333. package/dist/packages/tui/src/theme.js +182 -0
  334. package/dist/packages/tui/src/widgets.js +598 -0
  335. package/dist/packages/voice/src/controller.js +395 -0
  336. package/dist/packages/voice/src/doctor.js +63 -0
  337. package/dist/packages/voice/src/engines.js +44 -0
  338. package/dist/packages/voice/src/index.js +16 -0
  339. package/dist/packages/voice/src/router.js +502 -0
  340. package/dist/packages/voice/src/stt/apple-helper.swift.js +103 -0
  341. package/dist/packages/voice/src/stt/apple.js +179 -0
  342. package/dist/packages/voice/src/stt/fake.js +34 -0
  343. package/dist/packages/voice/src/stt/whisper.js +102 -0
  344. package/dist/packages/voice/src/summary.js +44 -0
  345. package/dist/packages/voice/src/tts/fake.js +30 -0
  346. package/dist/packages/voice/src/tts/say.js +96 -0
  347. package/dist/packages/voice/src/types.js +3 -0
  348. package/package.json +42 -4
  349. package/README.md +0 -3
@@ -0,0 +1,275 @@
1
+ export function mulberry32(seed) {
2
+ let a = seed >>> 0;
3
+ return function () {
4
+ a |= 0;
5
+ a = (a + 0x6d2b79f5) | 0;
6
+ let t = Math.imul(a ^ (a >>> 15), 1 | a);
7
+ t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
8
+ return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
9
+ };
10
+ }
11
+ const B58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
12
+ function fakeMint(rnd, suffix = 'pump') {
13
+ let s = '';
14
+ for (let i = 0; i < 44 - suffix.length; i++)
15
+ s += B58[Math.floor(rnd() * B58.length)];
16
+ return s + suffix;
17
+ }
18
+ function fakeAddr(rnd) { return fakeMint(rnd, ''); }
19
+ const NAMES = [
20
+ ['WIFHAT', 'dogwifhat classic', 'raydium'], ['PUDGY', 'Pudgy Terminal', 'pump.fun'], ['GIGA', 'Gigachad Protocol', 'pump.fun'],
21
+ ['MOODENG', 'Moo Deng Returns', 'meteora'], ['CATWIF', 'cat wif laser', 'pump.fun'], ['RETARDIO', 'retardio cousins', 'raydium'],
22
+ ['SNAIL', 'Snail Season', 'dbc'], ['HOUSE', 'housecoin', 'pump.fun'], ['FARTCOIN', 'Fartcoin', 'raydium'], ['PNUT', 'Peanut the Squirrel', 'raydium'],
23
+ ['ANSEM', 'ansem is back', 'pump.fun'], ['MANEKI', 'Maneki Neko', 'meteora'], ['GOAT', 'Goatseus Maximus', 'raydium'], ['ZEREBRO', 'zerebro', 'raydium'],
24
+ ['TITCOIN', 'titcoin', 'pump.fun'], ['FWOG', 'FWOG', 'raydium'], ['SIGMA', 'sigma grindset', 'pump.fun'], ['MICHI', 'michi', 'raydium'],
25
+ ['ALCH', 'Alchemist AI', 'dbc'], ['BUTTHOLE', 'butthole coin', 'pump.fun'], ['LOCKIN', 'lock in', 'raydium'], ['HARAMBE', 'Harambe on Solana', 'raydium'],
26
+ ['DADDY', 'DADDY TATE', 'raydium'], ['SKBDI', 'Skibidi Toilet', 'pump.fun'], ['CHILLGUY', 'Just a chill guy', 'raydium'], ['BRETT', 'Brett on Sol', 'meteora'],
27
+ ['NEIRO', 'Neiro', 'raydium'], ['SLERF', 'SLERF', 'raydium'], ['BOME', 'BOOK OF MEME', 'raydium'], ['POPCAT', 'Popcat', 'raydium'],
28
+ ['TRUMPCAT', 'Trump Cat', 'pump.fun'], ['MINI', 'mini', 'pump.fun'], ['AI16Z', 'ai16z', 'raydium'], ['ACT', 'Act I: The AI Prophecy', 'raydium'],
29
+ ];
30
+ const NEWPAIR_NAMES = [
31
+ ['BOOP', 'boop the snoot', 'pump.fun'], ['CLAUDE', 'claude wif terminal', 'pump.fun'], ['GRIDLOCK', 'gridlock', 'dbc'], ['RATTO', 'ratto', 'pump.fun'],
32
+ ['MOONPIE', 'moon pie', 'bonk'], ['WAFFLE', 'waffle house', 'pump.fun'], ['PEBBLE', 'pebble', 'pump.fun'], ['HONK', 'honk honk', 'dbc'],
33
+ ['SIRLOIN', 'sirloin', 'pump.fun'], ['ORB', 'the orb', 'bonk'], ['DRIFTER', 'drifter', 'pump.fun'], ['GLIZZY', 'glizzy gobbler', 'pump.fun'],
34
+ ['NOODLE', 'noodle arms', 'dbc'], ['TUNA', 'tuna melt', 'pump.fun'], ['CRAB', 'crab rave', 'pump.fun'], ['FELIX', 'felix the cat', 'bonk'],
35
+ ['KERNEL', 'kernel panic', 'pump.fun'], ['BAGEL', 'everything bagel', 'pump.fun'], ['YAP', 'yapper', 'dbc'], ['PLONK', 'plonk', 'pump.fun'],
36
+ ];
37
+ function walk(rnd, n, start, vol, drift = 0) {
38
+ const out = [start];
39
+ let p = start;
40
+ for (let i = 1; i < n; i++) {
41
+ const shock = rnd() < 0.04 ? (rnd() - 0.45) * vol * 6 : 0;
42
+ p = p * (1 + (rnd() - 0.5) * vol + drift + shock);
43
+ p = Math.max(p, start * 0.05);
44
+ out.push(p);
45
+ }
46
+ return out;
47
+ }
48
+ function candlesFrom(rnd, series, intervalMs, endMs, volBase) {
49
+ const out = [];
50
+ for (let i = 0; i < series.length - 1; i++) {
51
+ const o = series[i], c = series[i + 1];
52
+ const h = Math.max(o, c) * (1 + rnd() * 0.012);
53
+ const l = Math.min(o, c) * (1 - rnd() * 0.012);
54
+ const v = volBase * (0.3 + rnd() * 1.4) * (1 + Math.abs(c - o) / o * 25);
55
+ out.push({ o, h, l, c, v, t: endMs - (series.length - 1 - i) * intervalMs });
56
+ }
57
+ return out;
58
+ }
59
+ function makeToken(rnd, [symbol, name, launchpad], i, opts = {}) {
60
+ const fresh = !!opts.fresh;
61
+ const mcap = fresh ? 4e3 + rnd() * 90e3 : Math.exp(13 + rnd() * 6); // $440K .. $160M
62
+ const supply = 1e9;
63
+ const price = mcap / supply;
64
+ const liq = fresh ? mcap * (0.25 + rnd() * 0.3) : mcap * (0.04 + rnd() * 0.12);
65
+ const vol24 = fresh ? mcap * (0.5 + rnd() * 4) : mcap * (0.1 + rnd() * 1.6);
66
+ const ageMin = fresh ? rnd() * 90 : Math.exp(4 + rnd() * 7.5);
67
+ const holders = fresh ? Math.floor(20 + rnd() * 900) : Math.floor(Math.sqrt(mcap) * (2 + rnd() * 6));
68
+ const chg = {
69
+ m5: (rnd() - 0.5) * 8,
70
+ h1: (rnd() - 0.48) * 30,
71
+ h6: (rnd() - 0.47) * 70,
72
+ h24: (rnd() - 0.46) * 160,
73
+ };
74
+ if (fresh) {
75
+ chg.m5 = (rnd() - 0.4) * 40;
76
+ chg.h1 = (rnd() - 0.35) * 200;
77
+ chg.h6 = chg.h1;
78
+ chg.h24 = chg.h1;
79
+ }
80
+ const spark = walk(rnd, 48, price / (1 + chg.h24 / 100), 0.06);
81
+ spark[spark.length - 1] = price;
82
+ const buys = Math.floor(vol24 / (40 + rnd() * 400));
83
+ const sells = Math.floor(buys * (0.6 + rnd() * 0.7));
84
+ const org = fresh ? Math.floor(rnd() * 40) : Math.floor(20 + rnd() * 80);
85
+ const top10 = fresh ? 20 + rnd() * 50 : 8 + rnd() * 35;
86
+ const dev = fresh ? rnd() * 8 : rnd() * 4;
87
+ const lpLocked = launchpad === 'pump.fun' ? 100 : (rnd() < 0.7 ? 100 : Math.floor(rnd() * 100));
88
+ const mintAuth = rnd() < 0.08;
89
+ const freezeAuth = rnd() < 0.05;
90
+ const snipers = fresh ? Math.floor(rnd() * 30) : Math.floor(rnd() * 8);
91
+ const bundled = fresh ? rnd() * 30 : rnd() * 10;
92
+ const flags = [];
93
+ if (mintAuth)
94
+ flags.push('MINT');
95
+ if (freezeAuth)
96
+ flags.push('FREEZE');
97
+ if (top10 > 35)
98
+ flags.push('TOP10');
99
+ if (dev > 5)
100
+ flags.push('DEV');
101
+ if (bundled > 15)
102
+ flags.push('BUNDLE');
103
+ if (lpLocked < 50)
104
+ flags.push('LP');
105
+ const endMs = Date.UTC(2026, 9, 5, 23, 0, 0);
106
+ // 60 hourly candles; the walk is rescaled so the series ends exactly at the current price
107
+ const rawSeries = walk(rnd, 61, price, 0.05, (rnd() - 0.5) * 0.004);
108
+ const scale = price / rawSeries[rawSeries.length - 1];
109
+ const hourSeries = rawSeries.map((v) => v * scale);
110
+ const candles = candlesFrom(rnd, hourSeries, 3600e3, endMs, vol24 / 24);
111
+ const bonding = launchpad === 'pump.fun' && fresh ? Math.min(100, (mcap / 69e3) * 100) : null;
112
+ const mint = fakeMint(rnd, launchpad === 'pump.fun' ? 'pump' : launchpad === 'bonk' ? 'bonk' : '');
113
+ const holdersTop = Array.from({ length: 10 }, (_, k) => {
114
+ const pct = (top10 / 10) * (1.9 - k * 0.18) * (0.8 + rnd() * 0.4);
115
+ const kind = k === 0 && launchpad !== 'pump.fun' ? 'LP' : rnd() < 0.15 ? 'dev' : rnd() < 0.12 ? 'sniper' : rnd() < 0.1 ? 'cex' : '';
116
+ return { addr: fakeAddr(rnd), pct, kind, sol: pct / 100 * mcap / 120 };
117
+ });
118
+ const traders = Array.from({ length: 8 }, () => {
119
+ const pnl = (rnd() - 0.35) * 40000;
120
+ return { addr: fakeAddr(rnd), pnl, buys: Math.floor(rnd() * 40), sells: Math.floor(rnd() * 30), smart: rnd() < 0.3, winRate: 30 + rnd() * 60 };
121
+ }).sort((a, b) => b.pnl - a.pnl);
122
+ const trades = Array.from({ length: 24 }, (_, k) => {
123
+ const side = rnd() < 0.56 ? 'buy' : 'sell';
124
+ const usd = Math.exp(3 + rnd() * 6);
125
+ // PRNG draw order matters for parity with the prototype: ago, price, addr, then tag.
126
+ const ago = k * (4 + rnd() * 30);
127
+ const tradePrice = price * (1 + (rnd() - 0.5) * 0.02);
128
+ const addr = fakeAddr(rnd);
129
+ const tag = rnd() < 0.08 ? 'smart' : rnd() < 0.06 ? 'dev' : '';
130
+ return { ago, side, usd, price: tradePrice, addr, tag };
131
+ });
132
+ return {
133
+ id: i, symbol, name, launchpad, mint, price, mcap, fdv: mcap * (1 + rnd() * 0.1), liq, vol24, ageMin, holders,
134
+ holders24: Math.floor((rnd() - 0.3) * holders * 0.2), chg, spark, buys, sells, org, top10, dev, lpLocked, mintAuth, freezeAuth,
135
+ snipers, bundled, flags, candles, bonding, supply,
136
+ socials: { x: rnd() < 0.85, tg: rnd() < 0.7, web: rnd() < 0.6 },
137
+ xFollowers: Math.floor(rnd() * 60000),
138
+ devHistory: { launches: Math.floor(rnd() * 12), rugged: Math.floor(rnd() * 3), bestAth: Math.exp(10 + rnd() * 6) },
139
+ holdersTop, traders, trades,
140
+ rug: { score: Math.floor(rnd() * 100), risks: flags },
141
+ migrated: launchpad === 'pump.fun' ? !fresh : true,
142
+ };
143
+ }
144
+ export function makeFixtures(seed = 7) {
145
+ const rnd = mulberry32(seed);
146
+ const tokens = NAMES.map((n, i) => makeToken(rnd, n, i));
147
+ tokens.sort((a, b) => b.vol24 - a.vol24);
148
+ const newPairs = NEWPAIR_NAMES.map((n, i) => makeToken(rnd, n, 100 + i, { fresh: true }));
149
+ newPairs.forEach((p, k) => { p.ageMin = (k + 1) * (0.4 + rnd() * 1.6); });
150
+ const NOTES = ['thesis: CT rotation into cats', 'dev doxxed, LP burned', 'wait for retest of 1.2M', 'watch holder growth', 'claude flagged: wash vol', 'ATH breakout candidate'];
151
+ const watch = [tokens[1], tokens[4], tokens[7], tokens[12], newPairs[1], tokens[20]].map((t, i) => ({
152
+ token: t,
153
+ added: Math.floor(60 + rnd() * 3000),
154
+ entry: t.price / (1 + (rnd() - 0.35) * 0.8),
155
+ note: NOTES[i % NOTES.length],
156
+ alerts: [],
157
+ }));
158
+ const alerts = [
159
+ { ago: 0.3, kind: 'price', text: `${tokens[1].symbol} crossed +25% 1h (now ${fmtPctRaw(tokens[1].chg.h1)})`, level: 'up' },
160
+ { ago: 2.1, kind: 'holders', text: `${tokens[4].symbol} holders +312 in 10m (velocity 3.4x)`, level: 'info' },
161
+ { ago: 5.8, kind: 'risk', text: `${newPairs[1].symbol} dev wallet sold 60% of allocation`, level: 'down' },
162
+ { ago: 9.4, kind: 'migration', text: `${newPairs[3].symbol} graduated pump.fun → PumpSwap`, level: 'info' },
163
+ { ago: 14, kind: 'smart', text: `smart wallet 7xKp…q3Lm bought ${tokens[7].symbol} $12.4K`, level: 'up' },
164
+ { ago: 22, kind: 'ai', text: `claude: ${tokens[12].symbol} thesis invalidated (liq -40%)`, level: 'ai' },
165
+ { ago: 31, kind: 'price', text: `${tokens[20].symbol} -18% 5m, sell wall at $0.0042`, level: 'down' },
166
+ ];
167
+ const sol = { price: 120.73, chg24: -0.67 };
168
+ return { tokens, newPairs, watch, alerts, sol, seed };
169
+ }
170
+ function fmtPctRaw(n) { return (n > 0 ? '+' : '') + n.toFixed(1) + '%'; }
171
+ /** Fixture analyst transcript for the token detail panel (what `claude -p` would return after tool calls). */
172
+ export function aiTranscript(token) {
173
+ const s = token.symbol;
174
+ const verdict = token.org > 60 && token.top10 < 25 && !token.mintAuth ? 'watch' : token.flags.length >= 2 ? 'avoid' : 'speculative';
175
+ const lines = [];
176
+ lines.push({ role: 'user', text: `is $${s} worth a position here? what would invalidate it?` });
177
+ lines.push({ role: 'tool', text: `get_token(${s}) 84ms · get_holders(top=20) 131ms · get_trades(1h) 97ms · rugcheck 210ms` });
178
+ lines.push({ role: 'ai', verdict, text: verdictLine(verdict, token) });
179
+ lines.push({ role: 'ai', bullets: [
180
+ `${token.org >= 60 ? 'Organic score ' + token.org + '/100, real buyers outnumber bots' : 'Organic score ' + token.org + '/100: most volume looks automated'}`,
181
+ `Top 10 hold ${token.top10.toFixed(1)}% ${token.top10 > 30 ? '(concentrated, one wallet can nuke it)' : '(acceptable spread)'}`,
182
+ `${token.holders24 >= 0 ? '+' : ''}${token.holders24} holders 24h vs ${fmtK(token.vol24)} volume: ${token.holders24 > 0 ? 'accumulation' : 'distribution'} pattern`,
183
+ `Dev: ${token.devHistory.launches} prior launches, ${token.devHistory.rugged} rugged, holds ${token.dev.toFixed(2)}%`,
184
+ token.mintAuth ? 'Mint authority still enabled. Hard no until revoked.' : `Mint/freeze revoked, LP ${token.lpLocked}% locked`,
185
+ ] });
186
+ lines.push({ role: 'ai', text: `Invalidation: liquidity below ${fmtK(token.liq * 0.6)} or top-10 above 35%. I set two alerts for that. I don't trade; say "quote 0.5 SOL" and I'll show the Jupiter route for you to confirm.` });
187
+ lines.push({ role: 'user', text: `compare to the other cat coins in the screener` });
188
+ lines.push({ role: 'tool', text: `screener_query(filter="cat", sort=vol24) 42ms` });
189
+ lines.push({ role: 'ai', text: `3 matches. $${s} has the best organic/volume ratio but the thinnest liquidity of the three; CATWIF has 2.1x the holder growth. Want the comparison table?` });
190
+ return lines;
191
+ }
192
+ function verdictLine(v, t) {
193
+ if (v === 'watch')
194
+ return `Lean watch. Setup is decent: ${t.chg.h24 >= 0 ? 'momentum is positive' : 'pulling back on light volume'} and the on-chain basics check out.`;
195
+ if (v === 'avoid')
196
+ return `Avoid for now. ${t.flags.length} risk flags (${t.flags.join(', ')}) and the holder structure is fragile.`;
197
+ return `Speculative. Nothing disqualifying on-chain, but the activity is thin and the chart is mostly noise.`;
198
+ }
199
+ function fmtK(n) { return n >= 1e6 ? `$${(n / 1e6).toFixed(1)}M` : `$${(n / 1e3).toFixed(0)}K`; }
200
+ const SPAWN_NAMES = [['WAGMI', 'we are all gonna make it', 'pump.fun'], ['JEET', 'jeet detector', 'pump.fun'], ['NGMI', 'ngmi club', 'dbc'], ['COPIUM', 'copium inhaler', 'bonk'], ['REKT', 'rekt capital', 'pump.fun']];
201
+ /** Demo event: a brand-new pair lands at the top of the feed (fires the new-pair glitch in the loop). */
202
+ export function spawnPair(fx, rnd) {
203
+ const n = SPAWN_NAMES[Math.floor(rnd() * SPAWN_NAMES.length)];
204
+ const p = makeToken(rnd, n, 200 + fx.newPairs.length, { fresh: true });
205
+ p.ageMin = 0.15;
206
+ p.bonding = 3 + rnd() * 10;
207
+ fx.newPairs.unshift(p);
208
+ fx.newPairs.pop();
209
+ return p;
210
+ }
211
+ /** Demo event: force a pump (pct > 0) or a dump on a token. Mutates price/changes/candles/tape so every widget reacts. */
212
+ export function shock(tk, pct, rnd) {
213
+ const j = pct / 100;
214
+ tk.price *= 1 + j;
215
+ tk.mcap *= 1 + j;
216
+ tk.chg.m5 += pct * 0.8;
217
+ tk.chg.h1 += pct * 0.6;
218
+ tk.chg.h24 += pct * 0.4;
219
+ tk.spark.push(tk.price);
220
+ tk.spark.shift();
221
+ // spread the move over the last three candles so the chart scale survives (one giant candle looks like a bug)
222
+ const n = tk.candles.length;
223
+ const steps = [0.35, 0.7, 1];
224
+ let prevClose = tk.candles[n - 4].c;
225
+ for (let i = 0; i < 3; i++) {
226
+ const k = tk.candles[n - 3 + i];
227
+ const close = prevClose * (1 + j * (steps[i] - (i ? steps[i - 1] : 0)));
228
+ k.o = prevClose;
229
+ k.c = close;
230
+ k.h = Math.max(k.o, k.c) * 1.01;
231
+ k.l = Math.min(k.o, k.c) * 0.99;
232
+ k.v *= 1.4 + i * 0.3;
233
+ prevClose = close;
234
+ }
235
+ tk.candles[n - 1].c = tk.price;
236
+ tk.candles[n - 1].h = Math.max(tk.candles[n - 1].h, tk.price);
237
+ tk.candles[n - 1].l = Math.min(tk.candles[n - 1].l, tk.price);
238
+ const side = pct > 0 ? 'buy' : 'sell';
239
+ for (let i = 0; i < 4; i++)
240
+ tk.trades.unshift({ ago: i * 2, side, usd: 800 + rnd() * 9000, price: tk.price * (1 + (rnd() - 0.5) * 0.01), addr: tk.trades[i].addr, tag: i === 0 ? 'smart' : '' });
241
+ tk.trades.length = 24;
242
+ if (pct > 0)
243
+ tk.buys += 4;
244
+ else
245
+ tk.sells += 4;
246
+ }
247
+ /** Advance prices by a small jitter so the interactive demo feels alive. */
248
+ export function tick(fx, rnd) {
249
+ for (const t of [...fx.tokens, ...fx.newPairs]) {
250
+ const j = (rnd() - 0.5) * (t.bonding != null ? 0.03 : 0.008);
251
+ t.price *= 1 + j;
252
+ t.mcap *= 1 + j;
253
+ t.chg.m5 += j * 100 * 0.5;
254
+ t.chg.h1 += j * 100 * 0.3;
255
+ t.spark.push(t.price);
256
+ t.spark.shift();
257
+ const last = t.candles[t.candles.length - 1];
258
+ last.c = t.price;
259
+ last.h = Math.max(last.h, t.price);
260
+ last.l = Math.min(last.l, t.price);
261
+ if (rnd() < 0.2) {
262
+ t.buys += 1;
263
+ t.vol24 += 50 + rnd() * 900;
264
+ }
265
+ if (rnd() < 0.12) {
266
+ t.sells += 1;
267
+ }
268
+ if (t.bonding != null)
269
+ t.bonding = Math.min(100, t.bonding + j * 50);
270
+ }
271
+ for (const p of fx.newPairs)
272
+ p.ageMin += 1 / 120;
273
+ for (const a of fx.alerts)
274
+ a.ago += 1 / 120;
275
+ }
@@ -0,0 +1,221 @@
1
+ // `dexterm follow …` — the copy-trading follow list from a shell (task-1360 Tier 1).
2
+ //
3
+ // dexterm follow add <addr> [--name LABEL] follow a wallet (label = your own words, firewalled, local only)
4
+ // dexterm follow remove <addr>
5
+ // dexterm follow list [--json]
6
+ // dexterm follow stats <addr> [--json] one history fetch (Helius, 10 credits): trades, FIFO PnL, win rate (n)
7
+ // dexterm follow trades <addr> [--limit N] the decoded swaps behind the stats
8
+ // dexterm follow purge --yes delete every follow and label (the local label store is deletable)
9
+ // dexterm follow auto <addr> [--per-trade USD] [--daily USD] [--max-open N] [--cooldown SEC] [--k X] [--disarm N]
10
+ // draft the auto-mirror caps (clamped down to the hard ceilings; auto stays OFF —
11
+ // enabling is a keypress in the app after the less-safe popup) · --off turns it off
12
+ // dexterm follow auto list the auto policies and their state
13
+ //
14
+ // Self-directed only: your list, your wallet, your keys. Nothing here trades, proposes or signs; `stats` needs a free
15
+ // Helius key (keyless prints the fix) and reads public history. Secrets never print: the RPC URL stays inside the
16
+ // data layer.
17
+ import { createDataLayer, resolveRpcUrl, HeliusHistory } from '../../data/src/index.js';
18
+ import { FollowStore, WalletTracker, defaultFollowsPath, isWalletAddress, shortAddr, CopyAuto, defaultCopyJournalPath, AUTO_HARD, autoSizeCap } from '../../data/src/trade/copy/index.js';
19
+ import { PlanService, defaultPlansJournalPath } from '../../data/src/trade/plans/index.js';
20
+ function flag(rest, name) { const i = rest.indexOf(name); return i >= 0 ? rest[i + 1] : undefined; }
21
+ function has(rest, name) { return rest.includes(name); }
22
+ const USAGE = `dexterm follow <command>
23
+ add <addr> [--name LABEL] follow a wallet (your own label, never inferred, local only)
24
+ remove <addr>
25
+ list [--json]
26
+ stats <addr> [--json] one Helius history fetch: trades, FIFO realised PnL, win rate (hidden under n=10)
27
+ trades <addr> [--limit N] the decoded swaps behind the stats
28
+ purge --yes delete every follow and label
29
+ auto <addr> [--per-trade USD] [--daily USD] [--max-open N] [--cooldown SEC] [--k X] [--disarm N] [--off]
30
+ draft the auto-mirror caps (always OFF here: enabling is a keypress in the app, U then A,
31
+ after the "less safe" popup) · --off turns a running policy off · no addr = list
32
+ self-directed only: your list, your wallet, your keys · nothing here trades or signs`;
33
+ function fmtStats(s) {
34
+ const out = [
35
+ `${shortAddr(s.wallet)} ${s.trades} trades (${s.buys} buys · ${s.sells} sells · ${s.transfers} transfers) over ${s.mints} mints · ${s.sample.note}`,
36
+ `realised ${s.realisedSol >= 0 ? '+' : ''}${s.realisedSol.toFixed(4)} SOL${s.realisedUsd !== null ? ` (${s.realisedUsd >= 0 ? '+' : ''}$${s.realisedUsd.toFixed(2)} at $${s.solUsdAt}/SOL now)` : ' (no SOL price: USD not shown)'} · FIFO over fetched history, fees and tips included`,
37
+ `win rate ${s.winRate === null ? '—' : `${(s.winRate * 100).toFixed(0)}%`} · ${s.winRateNote} · open positions ${s.open}`,
38
+ `early-entry score ${s.earlyEntry.score === null ? '—' : s.earlyEntry.score.toFixed(2)} · ${s.earlyEntry.note}`,
39
+ ];
40
+ for (const p of s.positions.slice(0, 12))
41
+ out.push(` ${shortAddr(p.mint)} ${p.closed ? 'closed' : 'open '} realised ${p.realisedSol >= 0 ? '+' : ''}${p.realisedSol.toFixed(4)} SOL ${p.buys}b/${p.sells}s${p.flagged ? ' (cost-0 lot: airdrop/transfer/unpriced leg)' : ''}`);
42
+ if (s.positions.length > 12)
43
+ out.push(` … ${s.positions.length - 12} more mints`);
44
+ out.push('not a recommendation · a wallet\'s past fills say nothing about its next one');
45
+ return out;
46
+ }
47
+ export async function runFollow(rest, io, over = {}) {
48
+ const cmd = rest[0];
49
+ const out = (s) => io.stdout.write(s + '\n');
50
+ const errOut = (s) => io.stderr.write(s + '\n');
51
+ const store = new FollowStore({ path: over.followsPath === undefined ? defaultFollowsPath(io.env) : over.followsPath });
52
+ switch (cmd) {
53
+ case 'add': {
54
+ const addr = rest[1];
55
+ if (!addr || addr.startsWith('--')) {
56
+ errOut('usage: dexterm follow add <addr> [--name LABEL]');
57
+ return 2;
58
+ }
59
+ const r = store.add(addr, flag(rest, '--name'));
60
+ if (!r.ok) {
61
+ errOut(`dexterm follow add: ${r.reason}`);
62
+ return 1;
63
+ }
64
+ out(`following ${shortAddr(r.follow.addr)}${r.follow.name ? ` as "${r.follow.name}"` : ''} · ${store.list().length} followed · alerts show in the app (U)`);
65
+ return 0;
66
+ }
67
+ case 'remove': {
68
+ const addr = rest[1];
69
+ if (!addr) {
70
+ errOut('usage: dexterm follow remove <addr>');
71
+ return 2;
72
+ }
73
+ out(store.remove(addr) ? `unfollowed ${shortAddr(addr)}` : `${shortAddr(addr)} was not followed`);
74
+ return 0;
75
+ }
76
+ case 'list': {
77
+ const rows = store.list();
78
+ if (has(rest, '--json')) {
79
+ out(JSON.stringify(rows));
80
+ return 0;
81
+ }
82
+ if (!rows.length) {
83
+ out('no wallets followed · dexterm follow add <addr> [--name LABEL]');
84
+ return 0;
85
+ }
86
+ for (const f of rows)
87
+ out(`${f.addr} ${f.name ?? '—'} since ${new Date(f.since).toISOString().slice(0, 10)}`);
88
+ return 0;
89
+ }
90
+ case 'auto': {
91
+ const addr = rest[1] && !rest[1].startsWith('--') ? rest[1] : null;
92
+ const plans = new PlanService({ journalPath: over.plansJournalPath === undefined ? defaultPlansJournalPath(io.env) : over.plansJournalPath });
93
+ const auto = new CopyAuto({ plans, journalPath: over.copyJournalPath === undefined ? defaultCopyJournalPath(io.env) : over.copyJournalPath, market: async () => null, isFollowed: (w) => store.has(w) });
94
+ if (!addr) {
95
+ const pols = auto.list();
96
+ if (has(rest, '--json')) {
97
+ out(JSON.stringify(pols));
98
+ return 0;
99
+ }
100
+ if (!pols.length) {
101
+ out('no auto-mirror policies · dexterm follow auto <addr> --per-trade 20 --daily 100');
102
+ return 0;
103
+ }
104
+ for (const p of pols)
105
+ out(`${p.wallet} ${p.enabled ? 'ON ' : 'off'} ≤ $${autoSizeCap(p).toFixed(2)}/mirror (¼ of $${Math.min(p.perTradeUsd, p.dailyUsd)}) $${p.dailyUsd}/day max ${p.maxOpen} open ${Math.round(p.cooldownMs / 1000)} s cooldown k=${p.k} disarm@${p.autoDisarmStreak}${p.offReason ? ` (${p.offReason})` : ''}`);
106
+ out('auto is OFF in every fresh process; enable it in the app: U → A (needs the less-safe popup, G on the O screen)');
107
+ return 0;
108
+ }
109
+ if (!isWalletAddress(addr)) {
110
+ errOut('usage: dexterm follow auto <addr> [caps…] [--off]');
111
+ return 2;
112
+ }
113
+ if (!store.has(addr)) {
114
+ errOut(`dexterm follow auto: ${shortAddr(addr)} is not followed (dexterm follow add <addr> first)`);
115
+ return 1;
116
+ }
117
+ if (has(rest, '--off')) {
118
+ const p = auto.disable(addr, 'user (cli)');
119
+ out(p ? `auto-mirror off for ${shortAddr(addr)}` : 'no policy for that wallet');
120
+ return 0;
121
+ }
122
+ const sec = flag(rest, '--cooldown');
123
+ try {
124
+ const p = auto.draft(addr, {
125
+ perTradeUsd: flag(rest, '--per-trade') ? Number(flag(rest, '--per-trade')) : undefined,
126
+ dailyUsd: flag(rest, '--daily') ? Number(flag(rest, '--daily')) : undefined,
127
+ maxOpen: flag(rest, '--max-open') ? Number(flag(rest, '--max-open')) : undefined,
128
+ cooldownMs: sec ? Number(sec) * 1000 : undefined,
129
+ k: flag(rest, '--k') ? Number(flag(rest, '--k')) : undefined,
130
+ autoDisarmStreak: flag(rest, '--disarm') ? Number(flag(rest, '--disarm')) : undefined,
131
+ });
132
+ if (has(rest, '--json')) {
133
+ out(JSON.stringify(p));
134
+ return 0;
135
+ }
136
+ out(`auto-mirror caps for ${shortAddr(addr)}: ≤ $${autoSizeCap(p).toFixed(2)} per mirror (¼ of the $${Math.min(p.perTradeUsd, p.dailyUsd)} per-trade cap, hands-free tier) · $${p.dailyUsd}/day · max ${p.maxOpen} open · ${Math.round(p.cooldownMs / 1000)} s cooldown · k=${p.k} · auto-disarm after ${p.autoDisarmStreak} refused/failed · ceilings $${AUTO_HARD.perTradeUsd}/trade $${AUTO_HARD.dailyUsd}/day`);
137
+ out('status: OFF · enable in the app with a keypress: U → A (after the "less safe" popup, G on the O screen) · mirror-sell is not built');
138
+ return 0;
139
+ }
140
+ catch (e) {
141
+ errOut(`dexterm follow auto: ${e instanceof Error ? e.message : String(e)}`);
142
+ return 1;
143
+ }
144
+ }
145
+ case 'purge': {
146
+ if (!has(rest, '--yes')) {
147
+ errOut('dexterm follow purge: add --yes to delete every follow and label');
148
+ return 2;
149
+ }
150
+ out(`purged ${store.purge()} follow(s) and their labels`);
151
+ return 0;
152
+ }
153
+ case 'stats':
154
+ case 'trades': {
155
+ const addr = rest[1];
156
+ if (!isWalletAddress(addr)) {
157
+ errOut(`usage: dexterm follow ${cmd} <addr>`);
158
+ return 2;
159
+ }
160
+ let dl = null;
161
+ let history;
162
+ if (over.history !== undefined)
163
+ history = over.history;
164
+ else {
165
+ const rpc = resolveRpcUrl({ env: io.env });
166
+ if (rpc.provider !== 'helius')
167
+ history = null;
168
+ else {
169
+ dl = createDataLayer({ rpcUrl: rpc.url, rpcFallbackUrl: rpc.fallbackUrl });
170
+ history = dl.rpcPool.heliusUrl ? new HeliusHistory(dl.http, dl.rpcPool.heliusUrl) : null;
171
+ }
172
+ }
173
+ try {
174
+ const scratch = new FollowStore();
175
+ scratch.add(addr);
176
+ const tracker = new WalletTracker({ follows: scratch, history, solUsd: () => over.solUsd ?? null });
177
+ const st = tracker.status();
178
+ if (st.state === 'unavailable') {
179
+ errOut(`dexterm follow ${cmd}: ${st.why}`);
180
+ return 1;
181
+ }
182
+ await tracker.pollOnce();
183
+ const after = tracker.status();
184
+ if (after.state === 'degraded') {
185
+ errOut(`dexterm follow ${cmd}: ${after.why}`);
186
+ return 1;
187
+ }
188
+ if (cmd === 'stats') {
189
+ const s = tracker.stats(addr);
190
+ if (has(rest, '--json')) {
191
+ out(JSON.stringify({ ...s, positions: s.positions.map((p) => ({ ...p, tokensRaw: p.tokensRaw.toString(), peakRaw: p.peakRaw.toString() })) }));
192
+ return 0;
193
+ }
194
+ for (const line of fmtStats(s))
195
+ out(line);
196
+ return 0;
197
+ }
198
+ const limit = Number(flag(rest, '--limit') ?? 20);
199
+ const trades = tracker.trades(addr).slice(0, Number.isFinite(limit) && limit > 0 ? limit : 20);
200
+ if (!trades.length) {
201
+ out('no swaps in the fetched history');
202
+ return 0;
203
+ }
204
+ for (const tr of trades)
205
+ out(`${tr.tKnown ? new Date(tr.t).toISOString().replace('T', ' ').slice(0, 19) : 'time unknown '} ${tr.side.toUpperCase().padEnd(8)} ${shortAddr(tr.mint)} ${tr.solDelta !== null ? `${Math.abs(tr.solDelta).toFixed(4)} SOL` : 'unpriced '}${tr.usd !== null ? ` ≈ $${tr.usd.toFixed(2)}` : ''}${tr.note ? ` (${tr.note})` : ''} ${tr.sig.slice(0, 12)}…`);
206
+ return 0;
207
+ }
208
+ finally {
209
+ dl?.close();
210
+ }
211
+ }
212
+ default:
213
+ if (cmd) {
214
+ errOut(`dexterm follow: unknown subcommand ${JSON.stringify(cmd)}`);
215
+ errOut(USAGE);
216
+ return 2;
217
+ }
218
+ out(USAGE);
219
+ return 0;
220
+ }
221
+ }
@@ -0,0 +1,59 @@
1
+ // dexterm — coin-image settings (task-1326). Three layers, strongest last: the file ~/.dexterm/images.json
2
+ // (DEXTERM_HOME overrides the directory, same as popup.json / state.json), the DEXTERM_IMAGES environment
3
+ // variable, and the --no-images flag. A missing or malformed file degrades to the defaults and never throws.
4
+ //
5
+ // images.json: { "enabled": true, "blocks": "half" | "quad", "protocol": "auto" | "kitty" | "iterm" | "sixel" | "blocks",
6
+ // "thumbMax": 96, "diskMb": 32, "replay": false }
7
+ // DEXTERM_IMAGES=0|off|false images off DEXTERM_IMAGES=kitty|iterm|sixel|blocks force a protocol
8
+ // A --replay / DEXTERM_OFFLINE run has no network, so images there could only come from the disk cache: they stay
9
+ // OFF unless `replay: true` in the file or DEXTERM_IMAGES says on — recordings keep rendering exactly as recorded.
10
+ import { readFileSync } from 'node:fs';
11
+ import { join } from 'node:path';
12
+ import { dextermHome } from "./boot-state.js";
13
+ export const DEFAULT_IMAGES_CONFIG = { enabled: true, blocks: 'half', protocol: 'auto', thumbMax: 96, diskMb: 32, replay: false, source: 'defaults' };
14
+ export function imagesConfigPath(env = process.env) { return join(dextermHome(env), 'images.json'); }
15
+ export function normalizeImagesConfig(raw, source = 'file') {
16
+ const o = (raw && typeof raw === 'object' ? raw : {});
17
+ const num = (v, lo, hi, d) => (typeof v === 'number' && Number.isFinite(v) ? Math.max(lo, Math.min(hi, v)) : d);
18
+ const protocol = typeof o.protocol === 'string' && ['auto', 'kitty', 'iterm', 'sixel', 'blocks'].includes(o.protocol) ? o.protocol : 'auto';
19
+ return {
20
+ enabled: typeof o.enabled === 'boolean' ? o.enabled : true,
21
+ blocks: o.blocks === 'quad' ? 'quad' : 'half',
22
+ protocol,
23
+ thumbMax: Math.round(num(o.thumbMax, 32, 192, DEFAULT_IMAGES_CONFIG.thumbMax)),
24
+ diskMb: Math.round(num(o.diskMb, 4, 512, DEFAULT_IMAGES_CONFIG.diskMb)),
25
+ replay: o.replay === true,
26
+ source,
27
+ };
28
+ }
29
+ /** The file's settings, or the defaults. Never throws. */
30
+ export function loadImagesConfig(env = process.env) {
31
+ try {
32
+ return normalizeImagesConfig(JSON.parse(readFileSync(imagesConfigPath(env), 'utf8')), 'file');
33
+ }
34
+ catch {
35
+ return { ...DEFAULT_IMAGES_CONFIG };
36
+ }
37
+ }
38
+ /** File → env → flag. `noImagesFlag` is `--no-images`; `offline` = a --replay / DEXTERM_OFFLINE run (cache only). */
39
+ export function resolveImagesConfig(env, noImagesFlag, opts = {}) {
40
+ const out = { ...(opts.file ?? loadImagesConfig(env)) };
41
+ const e = (env.DEXTERM_IMAGES || '').trim().toLowerCase();
42
+ let explicitOn = false;
43
+ if (e === '0' || e === 'off' || e === 'false' || e === 'no')
44
+ out.enabled = false;
45
+ else if (e === '1' || e === 'on' || e === 'true' || e === 'yes') {
46
+ out.enabled = true;
47
+ explicitOn = true;
48
+ }
49
+ else if (e === 'kitty' || e === 'iterm' || e === 'sixel' || e === 'blocks') {
50
+ out.enabled = true;
51
+ out.protocol = e;
52
+ explicitOn = true;
53
+ }
54
+ if (opts.offline && !out.replay && !explicitOn)
55
+ out.enabled = false;
56
+ if (noImagesFlag)
57
+ out.enabled = false;
58
+ return out;
59
+ }
@@ -0,0 +1,31 @@
1
+ // dexterm — library surface of the CLI package (used by tests and tools).
2
+ export * from "./state.js";
3
+ export * from "./fixtures.js";
4
+ export { parseArgs, stateFromArgs, applyScreenerArgs, applyEffectArgs, applyAction, applyAnalystAction, applyKey, colorDepthFor, intensityFor, asciiRainFor, fpsFor, demoEvent, main, interactive, terminalGuard, describeError, buildScreenState, HELP, LIVE_REFRESH_MS, FPS_BY_INTENSITY, MAX_FPS, DEMO_KEYS, } from "./main.js";
5
+ export { AnalystSession, parseResults, parseFilterApplied } from "./analyst/session.js";
6
+ export { resolveAnalystResults } from "./analyst/results.js";
7
+ export { runAnalyst, buildArgv, turnPrompt, analystContextBlock, untrusted, ASSETS as ANALYST_ASSETS, MCP_BIN } from "./analyst/backend.js";
8
+ export { renderAnalystSession } from "./screens/analyst-session.js";
9
+ export * from "./boot-state.js";
10
+ export * from "./doctor.js";
11
+ export { renderOverlay, renderGotoPrompt, OVERLAY_HINTS, helpRows } from "./screens/overlay.js";
12
+ export * from "./audit.js";
13
+ export { renderBoot } from "./screens/boot.js";
14
+ export { renderScreener, screenerColumns, spotlight, COLUMN_GATE } from "./screens/screener.js";
15
+ export { renderToken, analystPanel } from "./screens/token.js";
16
+ export { renderNewPairs } from "./screens/newpairs.js";
17
+ export { renderWatchlist } from "./screens/watchlist.js";
18
+ export { renderAnalyst, renderContextRail, renderCoinList } from "./screens/analyst.js";
19
+ export { renderTicket } from "./screens/ticket.js";
20
+ export { renderPositions } from "./screens/positions.js";
21
+ export * from "./trade.js";
22
+ export { TradeTicketLive, PositionsLive, LivePositions, CombinedPositions, POSITIONS_REFRESH_MS } from "./live/trade.js";
23
+ export { parseWalletCommand, WALLET_HELP } from "./wallet-command.js";
24
+ export * from "./screener/filter.js";
25
+ export * from "./screener/sort.js";
26
+ export * from "./screener/presets.js";
27
+ export * from "./screener/view.js";
28
+ export { fromFixture, fromSnapshot, deriveFlags, impliedSpark, cleanText } from "./screener/rows.js";
29
+ export * from "./feed.js";
30
+ export * from "./images-config.js";
31
+ export { drawCoin, imagesOn, popupImagePath } from "./screens/coin.js";