dexterm-cli 0.0.0-stage → 0.1.2

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 (377) 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 +394 -0
  4. package/dist/packages/agents/src/executor.js +202 -0
  5. package/dist/packages/agents/src/gate.js +179 -0
  6. package/dist/packages/agents/src/identity.js +218 -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 +119 -0
  12. package/dist/packages/agents/src/tools.js +72 -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 +75 -0
  18. package/dist/packages/cli/assets/claude/plugin/skills/rug-check/SKILL.md +74 -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 +336 -0
  26. package/dist/packages/cli/src/agent-roster.js +26 -0
  27. package/dist/packages/cli/src/alerts/adapters/desktop.js +40 -0
  28. package/dist/packages/cli/src/alerts/adapters/discord.js +36 -0
  29. package/dist/packages/cli/src/alerts/adapters/telegram.js +43 -0
  30. package/dist/packages/cli/src/alerts/adapters/toast.js +16 -0
  31. package/dist/packages/cli/src/alerts/creds.js +83 -0
  32. package/dist/packages/cli/src/alerts/format.js +41 -0
  33. package/dist/packages/cli/src/alerts/index.js +10 -0
  34. package/dist/packages/cli/src/alerts/notifier.js +53 -0
  35. package/dist/packages/cli/src/alerts/route.js +19 -0
  36. package/dist/packages/cli/src/alerts/types.js +1 -0
  37. package/dist/packages/cli/src/alerts-cmd.js +212 -0
  38. package/dist/packages/cli/src/analyst/backend.js +526 -0
  39. package/dist/packages/cli/src/analyst/results.js +38 -0
  40. package/dist/packages/cli/src/analyst/session.js +319 -0
  41. package/dist/packages/cli/src/audit.js +51 -0
  42. package/dist/packages/cli/src/backtest-cmd.js +208 -0
  43. package/dist/packages/cli/src/boot-state.js +62 -0
  44. package/dist/packages/cli/src/coin-target.js +2 -0
  45. package/dist/packages/cli/src/custom.js +261 -0
  46. package/dist/packages/cli/src/display.js +191 -0
  47. package/dist/packages/cli/src/doctor.js +375 -0
  48. package/dist/packages/cli/src/export.js +235 -0
  49. package/dist/packages/cli/src/feed.js +634 -0
  50. package/dist/packages/cli/src/fixtures.js +275 -0
  51. package/dist/packages/cli/src/follow-cmd.js +221 -0
  52. package/dist/packages/cli/src/images-config.js +59 -0
  53. package/dist/packages/cli/src/index.js +31 -0
  54. package/dist/packages/cli/src/kb-skill-cmd.js +240 -0
  55. package/dist/packages/cli/src/larp-record.js +21 -0
  56. package/dist/packages/cli/src/live/copy.js +80 -0
  57. package/dist/packages/cli/src/live/flow.js +233 -0
  58. package/dist/packages/cli/src/live/index.js +511 -0
  59. package/dist/packages/cli/src/live/intel.js +227 -0
  60. package/dist/packages/cli/src/live/newpairs.js +334 -0
  61. package/dist/packages/cli/src/live/screens/newpairs-live.js +219 -0
  62. package/dist/packages/cli/src/live/screens/token-live.js +459 -0
  63. package/dist/packages/cli/src/live/screens/watchlist-live.js +149 -0
  64. package/dist/packages/cli/src/live/token.js +585 -0
  65. package/dist/packages/cli/src/live/trade.js +929 -0
  66. package/dist/packages/cli/src/live/watchlist.js +178 -0
  67. package/dist/packages/cli/src/main.js +5785 -0
  68. package/dist/packages/cli/src/mcp-cmd.js +326 -0
  69. package/dist/packages/cli/src/narrative-cmd.js +76 -0
  70. package/dist/packages/cli/src/pack-cmd.js +323 -0
  71. package/dist/packages/cli/src/plan-cmd.js +278 -0
  72. package/dist/packages/cli/src/popup.js +810 -0
  73. package/dist/packages/cli/src/rules-cmd.js +131 -0
  74. package/dist/packages/cli/src/rules.js +358 -0
  75. package/dist/packages/cli/src/scan/command.js +57 -0
  76. package/dist/packages/cli/src/scan/engine.js +419 -0
  77. package/dist/packages/cli/src/scan/observe.js +64 -0
  78. package/dist/packages/cli/src/scan/ui.js +98 -0
  79. package/dist/packages/cli/src/screener/filter.js +241 -0
  80. package/dist/packages/cli/src/screener/presets.js +80 -0
  81. package/dist/packages/cli/src/screener/rows.js +146 -0
  82. package/dist/packages/cli/src/screener/rug.js +50 -0
  83. package/dist/packages/cli/src/screener/sort.js +52 -0
  84. package/dist/packages/cli/src/screener/view.js +183 -0
  85. package/dist/packages/cli/src/screens/analyst-session.js +343 -0
  86. package/dist/packages/cli/src/screens/analyst.js +326 -0
  87. package/dist/packages/cli/src/screens/boot.js +74 -0
  88. package/dist/packages/cli/src/screens/bubbles.js +255 -0
  89. package/dist/packages/cli/src/screens/coin.js +33 -0
  90. package/dist/packages/cli/src/screens/follows.js +201 -0
  91. package/dist/packages/cli/src/screens/kol.js +90 -0
  92. package/dist/packages/cli/src/screens/narrative.js +90 -0
  93. package/dist/packages/cli/src/screens/newpairs.js +150 -0
  94. package/dist/packages/cli/src/screens/overlay.js +257 -0
  95. package/dist/packages/cli/src/screens/plans.js +126 -0
  96. package/dist/packages/cli/src/screens/positions.js +176 -0
  97. package/dist/packages/cli/src/screens/rules.js +170 -0
  98. package/dist/packages/cli/src/screens/screener.js +459 -0
  99. package/dist/packages/cli/src/screens/social-panel.js +107 -0
  100. package/dist/packages/cli/src/screens/ticket.js +342 -0
  101. package/dist/packages/cli/src/screens/token.js +312 -0
  102. package/dist/packages/cli/src/screens/trending.js +181 -0
  103. package/dist/packages/cli/src/screens/watchlist.js +104 -0
  104. package/dist/packages/cli/src/skill-eval-build.js +109 -0
  105. package/dist/packages/cli/src/social/demo.js +96 -0
  106. package/dist/packages/cli/src/social/view.js +250 -0
  107. package/dist/packages/cli/src/state.js +463 -0
  108. package/dist/packages/cli/src/theme-cmd.js +126 -0
  109. package/dist/packages/cli/src/trade.js +319 -0
  110. package/dist/packages/cli/src/update.js +294 -0
  111. package/dist/packages/cli/src/version.js +3 -0
  112. package/dist/packages/cli/src/voice-cmd.js +119 -0
  113. package/dist/packages/cli/src/voice-hud.js +42 -0
  114. package/dist/packages/cli/src/wallet-cmd.js +440 -0
  115. package/dist/packages/cli/src/wallet-command.js +31 -0
  116. package/dist/packages/cli/src/watch-cmd.js +190 -0
  117. package/dist/packages/cli/src/widgets.js +208 -0
  118. package/dist/packages/cli/src/workspace-cmd.js +68 -0
  119. package/dist/packages/cli/src/x-cmd.js +154 -0
  120. package/dist/packages/custom/src/config.js +213 -0
  121. package/dist/packages/custom/src/index.js +10 -0
  122. package/dist/packages/custom/src/keymap.js +107 -0
  123. package/dist/packages/custom/src/layout.js +235 -0
  124. package/dist/packages/custom/src/packs.js +633 -0
  125. package/dist/packages/custom/src/rules.js +704 -0
  126. package/dist/packages/custom/src/schema.js +538 -0
  127. package/dist/packages/custom/src/themes.js +176 -0
  128. package/dist/packages/custom/src/widget-html.js +222 -0
  129. package/dist/packages/custom/src/workspace.js +141 -0
  130. package/dist/packages/data/src/analyst-actions.js +133 -0
  131. package/dist/packages/data/src/budget.js +88 -0
  132. package/dist/packages/data/src/cache.js +142 -0
  133. package/dist/packages/data/src/candles.js +168 -0
  134. package/dist/packages/data/src/clock.js +64 -0
  135. package/dist/packages/data/src/coin-target.js +82 -0
  136. package/dist/packages/data/src/credits.js +137 -0
  137. package/dist/packages/data/src/detail.js +97 -0
  138. package/dist/packages/data/src/fast-lane.js +321 -0
  139. package/dist/packages/data/src/fixtures.js +135 -0
  140. package/dist/packages/data/src/health.js +245 -0
  141. package/dist/packages/data/src/http.js +277 -0
  142. package/dist/packages/data/src/images/cache.js +141 -0
  143. package/dist/packages/data/src/images/decode-worker.js +28 -0
  144. package/dist/packages/data/src/images/decode.js +81 -0
  145. package/dist/packages/data/src/images/fetch.js +162 -0
  146. package/dist/packages/data/src/images/gif.js +214 -0
  147. package/dist/packages/data/src/images/index.js +10 -0
  148. package/dist/packages/data/src/images/jpeg.js +544 -0
  149. package/dist/packages/data/src/images/png.js +310 -0
  150. package/dist/packages/data/src/images/service.js +334 -0
  151. package/dist/packages/data/src/images/types.js +27 -0
  152. package/dist/packages/data/src/index.js +211 -0
  153. package/dist/packages/data/src/intel/helius-history.js +70 -0
  154. package/dist/packages/data/src/intel/holder-class.js +125 -0
  155. package/dist/packages/data/src/intel/rules.js +421 -0
  156. package/dist/packages/data/src/intel/scan.js +170 -0
  157. package/dist/packages/data/src/larp/evidence.js +288 -0
  158. package/dist/packages/data/src/larp/link-baseline.js +196 -0
  159. package/dist/packages/data/src/larp/links.js +137 -0
  160. package/dist/packages/data/src/larp/robots.js +90 -0
  161. package/dist/packages/data/src/larp/safe-fetch.js +389 -0
  162. package/dist/packages/data/src/limiter.js +341 -0
  163. package/dist/packages/data/src/model.js +12 -0
  164. package/dist/packages/data/src/paper.js +331 -0
  165. package/dist/packages/data/src/rpc-config.js +126 -0
  166. package/dist/packages/data/src/rpc-pool.js +166 -0
  167. package/dist/packages/data/src/social/chain.js +83 -0
  168. package/dist/packages/data/src/social/dedupe.js +205 -0
  169. package/dist/packages/data/src/social/feed.js +462 -0
  170. package/dist/packages/data/src/social/firewall.js +110 -0
  171. package/dist/packages/data/src/social/index.js +11 -0
  172. package/dist/packages/data/src/social/kol.js +269 -0
  173. package/dist/packages/data/src/social/model.js +11 -0
  174. package/dist/packages/data/src/social/rank.js +184 -0
  175. package/dist/packages/data/src/social/rss.js +113 -0
  176. package/dist/packages/data/src/social/summary.js +104 -0
  177. package/dist/packages/data/src/social/venues.js +186 -0
  178. package/dist/packages/data/src/sources/dexscreener.js +184 -0
  179. package/dist/packages/data/src/sources/geckoterminal.js +133 -0
  180. package/dist/packages/data/src/sources/goplus.js +161 -0
  181. package/dist/packages/data/src/sources/jupiter-swap.js +236 -0
  182. package/dist/packages/data/src/sources/jupiter.js +198 -0
  183. package/dist/packages/data/src/sources/pda.js +113 -0
  184. package/dist/packages/data/src/sources/pump-curve.js +58 -0
  185. package/dist/packages/data/src/sources/pumpportal.js +252 -0
  186. package/dist/packages/data/src/sources/rugcheck.js +71 -0
  187. package/dist/packages/data/src/sources/solana-rpc.js +299 -0
  188. package/dist/packages/data/src/sources/solana-ws.js +287 -0
  189. package/dist/packages/data/src/store.js +289 -0
  190. package/dist/packages/data/src/trade/bridge.js +464 -0
  191. package/dist/packages/data/src/trade/caps.js +323 -0
  192. package/dist/packages/data/src/trade/copy/auto.js +385 -0
  193. package/dist/packages/data/src/trade/copy/follows.js +103 -0
  194. package/dist/packages/data/src/trade/copy/index.js +9 -0
  195. package/dist/packages/data/src/trade/copy/mirror.js +91 -0
  196. package/dist/packages/data/src/trade/copy/stats.js +120 -0
  197. package/dist/packages/data/src/trade/copy/tracker.js +158 -0
  198. package/dist/packages/data/src/trade/copy/trades.js +87 -0
  199. package/dist/packages/data/src/trade/copy/types.js +6 -0
  200. package/dist/packages/data/src/trade/executor.js +933 -0
  201. package/dist/packages/data/src/trade/kill-switch.js +47 -0
  202. package/dist/packages/data/src/trade/link-store.js +52 -0
  203. package/dist/packages/data/src/trade/plans/confirm.js +157 -0
  204. package/dist/packages/data/src/trade/plans/engine.js +784 -0
  205. package/dist/packages/data/src/trade/plans/executor-live.js +220 -0
  206. package/dist/packages/data/src/trade/plans/executor-paper.js +44 -0
  207. package/dist/packages/data/src/trade/plans/executor.js +11 -0
  208. package/dist/packages/data/src/trade/plans/index.js +12 -0
  209. package/dist/packages/data/src/trade/plans/journal.js +77 -0
  210. package/dist/packages/data/src/trade/plans/mandate.js +129 -0
  211. package/dist/packages/data/src/trade/plans/plan.js +179 -0
  212. package/dist/packages/data/src/trade/plans/service.js +168 -0
  213. package/dist/packages/data/src/trade/plans/types.js +6 -0
  214. package/dist/packages/data/src/trade/rpc-exec.js +229 -0
  215. package/dist/packages/data/src/trade/signer/client.js +197 -0
  216. package/dist/packages/data/src/trade/signer/fast-wallet.js +154 -0
  217. package/dist/packages/data/src/trade/signer/host.js +97 -0
  218. package/dist/packages/data/src/trade/signer/main.js +121 -0
  219. package/dist/packages/data/src/trade/signer/probe-builder.js +85 -0
  220. package/dist/packages/data/src/trade/signer/protocol.js +92 -0
  221. package/dist/packages/data/src/trade/signer/service.js +400 -0
  222. package/dist/packages/data/src/trade/signer/sol-usd-feed.js +98 -0
  223. package/dist/packages/data/src/trade/sol-usd.js +86 -0
  224. package/dist/packages/data/src/trade/swap-build.js +108 -0
  225. package/dist/packages/data/src/trade/token-delta.js +201 -0
  226. package/dist/packages/data/src/trade/tx-decode.js +632 -0
  227. package/dist/packages/data/src/util.js +24 -0
  228. package/dist/packages/data/src/watchlist.js +176 -0
  229. package/dist/packages/data/src/x/api.js +256 -0
  230. package/dist/packages/data/src/x/budget.js +66 -0
  231. package/dist/packages/data/src/x/config.js +49 -0
  232. package/dist/packages/data/src/x/index.js +10 -0
  233. package/dist/packages/data/src/x/mock-server.js +217 -0
  234. package/dist/packages/data/src/x/oauth.js +242 -0
  235. package/dist/packages/data/src/x/pkce.js +21 -0
  236. package/dist/packages/data/src/x/source.js +285 -0
  237. package/dist/packages/data/src/x/token-store.js +134 -0
  238. package/dist/packages/data/src/x/transport.js +71 -0
  239. package/dist/packages/data/vendor/solana-web3/LICENSE +20 -0
  240. package/dist/packages/data/vendor/solana-web3/NOTICE.md +13 -0
  241. package/dist/packages/data/vendor/solana-web3/index.iife.min.js +20 -0
  242. package/dist/packages/mcp/assets/cases.json +1194 -0
  243. package/dist/packages/mcp/assets/kb/entries/cabal-and-coordinated-launches.md +28 -0
  244. package/dist/packages/mcp/assets/kb/entries/common-rug-patterns.md +40 -0
  245. package/dist/packages/mcp/assets/kb/entries/dbc-mechanics.md +30 -0
  246. package/dist/packages/mcp/assets/kb/entries/dev-wallet-behaviour.md +33 -0
  247. package/dist/packages/mcp/assets/kb/entries/glossary.md +35 -0
  248. package/dist/packages/mcp/assets/kb/entries/holder-concentration.md +30 -0
  249. package/dist/packages/mcp/assets/kb/entries/jito-bundles.md +29 -0
  250. package/dist/packages/mcp/assets/kb/entries/launchlab-curve.md +31 -0
  251. package/dist/packages/mcp/assets/kb/entries/lp-burn-vs-lock.md +31 -0
  252. package/dist/packages/mcp/assets/kb/entries/metadata-and-copycats.md +29 -0
  253. package/dist/packages/mcp/assets/kb/entries/mint-freeze-authority.md +31 -0
  254. package/dist/packages/mcp/assets/kb/entries/narrative-lifecycle.md +32 -0
  255. package/dist/packages/mcp/assets/kb/entries/pump-bonding-curve.md +33 -0
  256. package/dist/packages/mcp/assets/kb/entries/pumpswap-migration.md +29 -0
  257. package/dist/packages/mcp/assets/kb/entries/sniping-and-snipers.md +29 -0
  258. package/dist/packages/mcp/assets/kb/entries/token2022-extensions-risk.md +32 -0
  259. package/dist/packages/mcp/assets/kb/entries/wash-trading-fake-volume.md +33 -0
  260. package/dist/packages/mcp/assets/skills/rug-check.md +52 -0
  261. package/dist/packages/mcp/assets/skills/token-dossier.md +57 -0
  262. package/dist/packages/mcp/assets/skills/trench-scan.md +40 -0
  263. package/dist/packages/mcp/bin/dexterm-mcp.mjs +16 -0
  264. package/dist/packages/mcp/src/dossier.js +78 -0
  265. package/dist/packages/mcp/src/firewall.js +21 -0
  266. package/dist/packages/mcp/src/index.js +22 -0
  267. package/dist/packages/mcp/src/server.js +936 -0
  268. package/dist/packages/mcp/src/user-content.js +434 -0
  269. package/dist/packages/packs/src/backtest.js +183 -0
  270. package/dist/packages/packs/src/digest.js +95 -0
  271. package/dist/packages/packs/src/firewall.js +57 -0
  272. package/dist/packages/packs/src/index.js +20 -0
  273. package/dist/packages/packs/src/larp-eval.js +100 -0
  274. package/dist/packages/packs/src/narrative.js +309 -0
  275. package/dist/packages/packs/src/reason.js +135 -0
  276. package/dist/packages/packs/src/rug-model.js +137 -0
  277. package/dist/packages/packs/src/schema.js +54 -0
  278. package/dist/packages/packs/src/skill-backtest.js +300 -0
  279. package/dist/packages/packs/src/token-dossier.js +174 -0
  280. package/dist/packages/packs/src/verdicts.js +17 -0
  281. package/dist/packages/packs/src/wallet-dossier.js +105 -0
  282. package/dist/packages/popup/src/config.js +71 -0
  283. package/dist/packages/popup/src/dock.js +271 -0
  284. package/dist/packages/popup/src/host.js +210 -0
  285. package/dist/packages/popup/src/index.js +12 -0
  286. package/dist/packages/popup/src/loopback.js +53 -0
  287. package/dist/packages/popup/src/open.js +183 -0
  288. package/dist/packages/popup/src/pages/bubbles-lib.js +160 -0
  289. package/dist/packages/popup/src/pages/bubbles.css +23 -0
  290. package/dist/packages/popup/src/pages/bubbles.html +36 -0
  291. package/dist/packages/popup/src/pages/bubbles.js +214 -0
  292. package/dist/packages/popup/src/pages/chart-lib.js +262 -0
  293. package/dist/packages/popup/src/pages/chart.css +50 -0
  294. package/dist/packages/popup/src/pages/chart.html +56 -0
  295. package/dist/packages/popup/src/pages/chart.js +554 -0
  296. package/dist/packages/popup/src/pages/common.css +34 -0
  297. package/dist/packages/popup/src/pages/common.js +187 -0
  298. package/dist/packages/popup/src/pages/feeds.html +20 -0
  299. package/dist/packages/popup/src/pages/feeds.js +77 -0
  300. package/dist/packages/popup/src/pages/narrative.html +20 -0
  301. package/dist/packages/popup/src/pages/narrative.js +61 -0
  302. package/dist/packages/popup/src/pages/plans.css +30 -0
  303. package/dist/packages/popup/src/pages/plans.html +26 -0
  304. package/dist/packages/popup/src/pages/plans.js +82 -0
  305. package/dist/packages/popup/src/pages/roster.css +41 -0
  306. package/dist/packages/popup/src/pages/roster.html +25 -0
  307. package/dist/packages/popup/src/pages/roster.js +75 -0
  308. package/dist/packages/popup/src/pages/token.html +20 -0
  309. package/dist/packages/popup/src/pages/token.js +112 -0
  310. package/dist/packages/popup/src/pages/widget-sdk.js +224 -0
  311. package/dist/packages/popup/src/pages/widget.css +5 -0
  312. package/dist/packages/popup/src/pages/widget.html +21 -0
  313. package/dist/packages/popup/src/pages/widget.js +85 -0
  314. package/dist/packages/popup/src/protocol.js +31 -0
  315. package/dist/packages/popup/src/selftest.js +156 -0
  316. package/dist/packages/popup/src/server.js +582 -0
  317. package/dist/packages/popup/src/sinkproxy.js +167 -0
  318. package/dist/packages/popup/src/widget-html.js +231 -0
  319. package/dist/packages/popup/vendor/lightweight-charts/LICENSE +201 -0
  320. package/dist/packages/popup/vendor/lightweight-charts/NOTICE +2 -0
  321. package/dist/packages/popup/vendor/lightweight-charts/README.md +30 -0
  322. package/dist/packages/popup/vendor/lightweight-charts/VERSION +1 -0
  323. package/dist/packages/popup/vendor/lightweight-charts/lightweight-charts.standalone.production.js +7 -0
  324. package/dist/packages/recorder/bin/dexterm-recorder.mjs +11 -0
  325. package/dist/packages/recorder/src/cli.js +113 -0
  326. package/dist/packages/recorder/src/export.js +71 -0
  327. package/dist/packages/recorder/src/index.js +20 -0
  328. package/dist/packages/recorder/src/labels.js +151 -0
  329. package/dist/packages/recorder/src/open.js +29 -0
  330. package/dist/packages/recorder/src/recorder.js +553 -0
  331. package/dist/packages/recorder/src/schedule.js +43 -0
  332. package/dist/packages/recorder/src/schema.js +135 -0
  333. package/dist/packages/recorder/src/snapshot.js +191 -0
  334. package/dist/packages/recorder/src/sweep.js +52 -0
  335. package/dist/packages/recorder/src/verdicts.js +52 -0
  336. package/dist/packages/tui/src/bubbles.js +415 -0
  337. package/dist/packages/tui/src/canvas.js +370 -0
  338. package/dist/packages/tui/src/chrome.js +85 -0
  339. package/dist/packages/tui/src/color.js +133 -0
  340. package/dist/packages/tui/src/flush.js +62 -0
  341. package/dist/packages/tui/src/fmt.js +188 -0
  342. package/dist/packages/tui/src/fx-trade.js +278 -0
  343. package/dist/packages/tui/src/fx.js +527 -0
  344. package/dist/packages/tui/src/images/blocks.js +141 -0
  345. package/dist/packages/tui/src/images/coin.js +22 -0
  346. package/dist/packages/tui/src/images/detect.js +140 -0
  347. package/dist/packages/tui/src/images/index.js +7 -0
  348. package/dist/packages/tui/src/images/layer.js +146 -0
  349. package/dist/packages/tui/src/images/pixels.js +157 -0
  350. package/dist/packages/tui/src/images/protocols.js +87 -0
  351. package/dist/packages/tui/src/index.js +18 -0
  352. package/dist/packages/tui/src/keymap.js +357 -0
  353. package/dist/packages/tui/src/layout.js +11 -0
  354. package/dist/packages/tui/src/raster-font.js +195 -0
  355. package/dist/packages/tui/src/raster.js +213 -0
  356. package/dist/packages/tui/src/sound.js +177 -0
  357. package/dist/packages/tui/src/theme.js +182 -0
  358. package/dist/packages/tui/src/widgets.js +598 -0
  359. package/dist/packages/voice/src/controller.js +407 -0
  360. package/dist/packages/voice/src/doctor.js +131 -0
  361. package/dist/packages/voice/src/download.js +184 -0
  362. package/dist/packages/voice/src/engines.js +84 -0
  363. package/dist/packages/voice/src/index.js +20 -0
  364. package/dist/packages/voice/src/router.js +502 -0
  365. package/dist/packages/voice/src/stt/apple-helper.swift.js +103 -0
  366. package/dist/packages/voice/src/stt/apple.js +179 -0
  367. package/dist/packages/voice/src/stt/fake.js +34 -0
  368. package/dist/packages/voice/src/stt/whisper.js +112 -0
  369. package/dist/packages/voice/src/summary.js +44 -0
  370. package/dist/packages/voice/src/tts/espeak.js +131 -0
  371. package/dist/packages/voice/src/tts/fake.js +30 -0
  372. package/dist/packages/voice/src/tts/piper.js +206 -0
  373. package/dist/packages/voice/src/tts/say.js +132 -0
  374. package/dist/packages/voice/src/tts/voices.js +206 -0
  375. package/dist/packages/voice/src/types.js +3 -0
  376. package/package.json +38 -4
  377. package/README.md +0 -3
@@ -0,0 +1,122 @@
1
+ // @dexterm/agents — the audit log (task-1345). Every agent connection, call, refusal, proposal and
2
+ // roster action is one row. Two stores behind one interface: in memory (tests, --fixtures) and
3
+ // node:sqlite in the shared dexterm DB (live / replay), so `dexterm agent audit` and the roster popup
4
+ // read the same rows. Detail strings are firewalled at write time (agent-supplied text can never carry
5
+ // an escape sequence or a 10 KB payload into the terminal or a model).
6
+ import { DatabaseSync } from 'node:sqlite';
7
+ import { mkdirSync } from 'node:fs';
8
+ import { dirname } from 'node:path';
9
+ import { firewallText } from '../../data/src/index.js';
10
+ export const AUDIT_DETAIL_MAX = 160;
11
+ /** Make a detail string safe for the terminal and the log: firewall, single line, capped. */
12
+ export function auditDetail(s) {
13
+ const r = firewallText(s === undefined || s === null ? '' : String(s), { max: AUDIT_DETAIL_MAX, keepUrls: false });
14
+ return r.text.replace(/\s+/g, ' ').trim();
15
+ }
16
+ export class MemoryAuditLog {
17
+ rows = [];
18
+ seq = 0;
19
+ now;
20
+ cap;
21
+ constructor(opts = {}) { this.now = opts.now ?? (() => Date.now()); this.cap = opts.cap ?? 5000; }
22
+ append(e) {
23
+ const row = { ...e, id: ++this.seq, t: e.t ?? this.now(), detail: auditDetail(e.detail), agentName: auditDetail(e.agentName).slice(0, 24), tool: auditDetail(e.tool).slice(0, 64) };
24
+ this.rows.push(row);
25
+ if (this.rows.length > this.cap)
26
+ this.rows.splice(0, this.rows.length - this.cap);
27
+ return row;
28
+ }
29
+ recent(limit = 50, filter = {}) {
30
+ const out = [];
31
+ for (let i = this.rows.length - 1; i >= 0 && out.length < limit; i--) {
32
+ const r = this.rows[i];
33
+ if (filter.agentId && r.agentId !== filter.agentId)
34
+ continue;
35
+ if (filter.agentName && r.agentName !== filter.agentName)
36
+ continue;
37
+ if (filter.kind && r.kind !== filter.kind)
38
+ continue;
39
+ if (filter.since !== undefined && r.t < filter.since)
40
+ continue;
41
+ out.push({ ...r });
42
+ }
43
+ return out;
44
+ }
45
+ counts(agentId) {
46
+ let calls = 0, refused = 0, proposals = 0, lastAt = null;
47
+ for (const r of this.rows) {
48
+ if (r.agentId !== agentId)
49
+ continue;
50
+ if (r.kind === 'call')
51
+ calls++;
52
+ else if (r.kind === 'refused')
53
+ refused++;
54
+ else if (r.kind === 'proposal')
55
+ proposals++;
56
+ if (lastAt === null || r.t > lastAt)
57
+ lastAt = r.t;
58
+ }
59
+ return { calls, refused, proposals, lastAt };
60
+ }
61
+ close() { }
62
+ }
63
+ export class SqliteAuditLog {
64
+ db;
65
+ now;
66
+ constructor(path, opts = {}) {
67
+ if (path !== ':memory:')
68
+ mkdirSync(dirname(path), { recursive: true });
69
+ this.db = new DatabaseSync(path);
70
+ this.now = opts.now ?? (() => Date.now());
71
+ this.db.exec(`
72
+ PRAGMA journal_mode = WAL;
73
+ CREATE TABLE IF NOT EXISTS agent_audit (
74
+ id INTEGER PRIMARY KEY AUTOINCREMENT, t INTEGER NOT NULL, agent_id TEXT, agent_name TEXT NOT NULL, session TEXT,
75
+ kind TEXT NOT NULL, tool TEXT NOT NULL, detail TEXT NOT NULL, ok INTEGER NOT NULL
76
+ );
77
+ CREATE INDEX IF NOT EXISTS agent_audit_agent ON agent_audit(agent_id, t);
78
+ `);
79
+ }
80
+ append(e) {
81
+ const t = e.t ?? this.now();
82
+ const detail = auditDetail(e.detail);
83
+ const name = auditDetail(e.agentName).slice(0, 24);
84
+ const tool = auditDetail(e.tool).slice(0, 64);
85
+ const r = this.db.prepare('INSERT INTO agent_audit (t, agent_id, agent_name, session, kind, tool, detail, ok) VALUES (?, ?, ?, ?, ?, ?, ?, ?)')
86
+ .run(t, e.agentId, name, e.session, e.kind, tool, detail, e.ok ? 1 : 0);
87
+ return { ...e, id: Number(r.lastInsertRowid), t, detail, agentName: name, tool };
88
+ }
89
+ recent(limit = 50, filter = {}) {
90
+ const where = [];
91
+ const params = [];
92
+ if (filter.agentId) {
93
+ where.push('agent_id = ?');
94
+ params.push(filter.agentId);
95
+ }
96
+ if (filter.agentName) {
97
+ where.push('agent_name = ?');
98
+ params.push(filter.agentName);
99
+ }
100
+ if (filter.kind) {
101
+ where.push('kind = ?');
102
+ params.push(filter.kind);
103
+ }
104
+ if (filter.since !== undefined) {
105
+ where.push('t >= ?');
106
+ params.push(filter.since);
107
+ }
108
+ const sql = `SELECT id, t, agent_id, agent_name, session, kind, tool, detail, ok FROM agent_audit${where.length ? ' WHERE ' + where.join(' AND ') : ''} ORDER BY id DESC LIMIT ?`;
109
+ const rows = this.db.prepare(sql).all(...params, Math.max(1, Math.min(limit, 2000)));
110
+ return rows.map((r) => ({ id: Number(r.id), t: Number(r.t), agentId: r.agent_id ?? null, agentName: String(r.agent_name), session: r.session ?? null, kind: r.kind, tool: String(r.tool), detail: String(r.detail), ok: Number(r.ok) === 1 }));
111
+ }
112
+ counts(agentId) {
113
+ const r = this.db.prepare(`SELECT
114
+ SUM(CASE WHEN kind = 'call' THEN 1 ELSE 0 END) AS calls, SUM(CASE WHEN kind = 'refused' THEN 1 ELSE 0 END) AS refused,
115
+ SUM(CASE WHEN kind = 'proposal' THEN 1 ELSE 0 END) AS proposals, MAX(t) AS last FROM agent_audit WHERE agent_id = ?`).get(agentId);
116
+ return { calls: Number(r.calls ?? 0), refused: Number(r.refused ?? 0), proposals: Number(r.proposals ?? 0), lastAt: r.last === null || r.last === undefined ? null : Number(r.last) };
117
+ }
118
+ close() { try {
119
+ this.db.close();
120
+ }
121
+ catch { /* ignore */ } }
122
+ }
@@ -0,0 +1,394 @@
1
+ // @dexterm/agents — the loopback agent bus (task-1345, tier 2). A WebSocket + JSON-RPC 2.0 server on
2
+ // 127.0.0.1 that external agents connect to. Every connection authenticates once with a registered name
3
+ // + token (identity.ts); every call passes the gate (gate.ts) before any execution; every connect, call,
4
+ // refusal, proposal and disconnect is one audit row. Agents can subscribe to live topics (new pairs,
5
+ // trades, alerts, screen) and create proposals the user must confirm. No bus path can arm, sign, send,
6
+ // raise a cap, change the gate, or touch a wallet/mandate/signer — the gate's never-list sees to that.
7
+ import { writeFileSync, rmSync, mkdirSync, chmodSync } from 'node:fs';
8
+ import { dirname, join } from 'node:path';
9
+ import { createWsServer } from "./ws.js";
10
+ import { AgentGate } from "./gate.js";
11
+ import { AgentRegistry, dextermHome, looksLikeToken, AGENT_NAME_RE } from "./identity.js";
12
+ import { lowerTier, isTier, toolsForTier } from "./tiers.js";
13
+ import { toolSchema, agentTool, toolsForTierList } from "./tools.js";
14
+ import { isTopic, scrubStrings } from "./executor.js";
15
+ import { TOOL_TO_KIND } from "./proposals.js";
16
+ import { firewallText } from '../../data/src/index.js';
17
+ export const BUS_PROTOCOL = 'dexterm-agent-bus/1';
18
+ /** A connection that does not authenticate within this window is closed. */
19
+ export const HELLO_TIMEOUT_MS = 10_000;
20
+ /** Hard cap on simultaneous un-authenticated sockets (a connect flood cannot exhaust memory). */
21
+ export const MAX_PENDING = 16;
22
+ export class AgentBus {
23
+ server = null;
24
+ conns = new Set();
25
+ registry;
26
+ audit;
27
+ executor;
28
+ proposals;
29
+ feed;
30
+ gate;
31
+ now;
32
+ paused = new Set();
33
+ discoveryPath;
34
+ feedOff = null;
35
+ sessionSeq = 0;
36
+ constructor(opts) {
37
+ this.registry = opts.registry;
38
+ this.audit = opts.audit;
39
+ this.executor = opts.executor;
40
+ this.proposals = opts.proposals;
41
+ this.feed = opts.feed ?? null;
42
+ this.now = opts.now ?? (() => Date.now());
43
+ this.discoveryPath = opts.discoveryPath === undefined ? join(dextermHome(opts.env), 'agent-bus.json') : opts.discoveryPath;
44
+ this.gate = new AgentGate({
45
+ audit: this.audit,
46
+ now: this.now,
47
+ isPaused: (id) => this.paused.has(id),
48
+ onFlood: (id, name) => { this.audit.append({ agentId: id, agentName: name, session: null, kind: 'pause', tool: '-', detail: 'auto-paused by the flood breaker', ok: false }); },
49
+ });
50
+ }
51
+ get port() { return this.server?.port ?? 0; }
52
+ get connectionCount() { return this.conns.size; }
53
+ async start() {
54
+ this.server = await createWsServer({ port: undefined, onConnection: (ws) => this.onConnection(ws) });
55
+ if (this.feed)
56
+ this.feedOff = this.feed.on((ev) => this.fanout(ev));
57
+ this.writeDiscovery();
58
+ return this.server.port;
59
+ }
60
+ async close() {
61
+ this.feedOff?.();
62
+ this.feedOff = null;
63
+ for (const c of [...this.conns]) {
64
+ try {
65
+ c.ws.close(1001);
66
+ }
67
+ catch { /* ignore */ }
68
+ }
69
+ this.conns.clear();
70
+ if (this.discoveryPath) {
71
+ try {
72
+ rmSync(this.discoveryPath);
73
+ }
74
+ catch { /* ignore */ }
75
+ }
76
+ if (this.server) {
77
+ await this.server.close();
78
+ this.server = null;
79
+ }
80
+ }
81
+ // ----- roster/CLI actions (user side; never reachable from an agent path) -----
82
+ pauseAgent(name) {
83
+ const a = this.registry.get(name);
84
+ if (!a)
85
+ return false;
86
+ this.paused.add(a.id);
87
+ this.registry.setPaused(name, true);
88
+ this.audit.append({ agentId: a.id, agentName: name, session: null, kind: 'pause', tool: '-', detail: 'paused by the user', ok: false });
89
+ return true;
90
+ }
91
+ resumeAgent(name) {
92
+ const a = this.registry.get(name);
93
+ if (!a)
94
+ return false;
95
+ this.paused.delete(a.id);
96
+ this.registry.setPaused(name, false);
97
+ this.gate.clearFlood(a.id);
98
+ this.audit.append({ agentId: a.id, agentName: name, session: null, kind: 'resume', tool: '-', detail: 'resumed by the user', ok: true });
99
+ return true;
100
+ }
101
+ /** Kick: close every live session for an agent now (the token keeps working — use `rotate`/`remove` to revoke it). */
102
+ kickAgent(name) {
103
+ const a = this.registry.get(name);
104
+ if (!a)
105
+ return 0;
106
+ let n = 0;
107
+ for (const c of [...this.conns])
108
+ if (c.session && c.session.agentId === a.id) {
109
+ c.session.closed = true;
110
+ c.session.closedReason = 'kicked';
111
+ try {
112
+ c.ws.close(4003);
113
+ }
114
+ catch { /* ignore */ }
115
+ n++;
116
+ }
117
+ this.audit.append({ agentId: a.id, agentName: name, session: null, kind: 'kick', tool: '-', detail: `kicked ${n} session(s)`, ok: true });
118
+ return n;
119
+ }
120
+ /** For the roster (tier 4): live sessions + usage per connected agent. */
121
+ roster() {
122
+ const byAgent = new Map();
123
+ for (const c of this.conns) {
124
+ const s = c.session;
125
+ if (!s)
126
+ continue;
127
+ const cur = byAgent.get(s.agentId) ?? { name: s.agentName, tier: s.tier, sessions: 0, client: s.client, lastActivity: 0, topics: new Set() };
128
+ cur.sessions++;
129
+ cur.lastActivity = Math.max(cur.lastActivity, s.lastActivity);
130
+ for (const t of s.topics)
131
+ cur.topics.add(t);
132
+ byAgent.set(s.agentId, cur);
133
+ }
134
+ return [...byAgent].map(([agentId, v]) => ({ agentId, name: v.name, tier: v.tier, sessions: v.sessions, client: v.client, lastActivity: v.lastActivity, topics: [...v.topics], usage: this.gate.usage(agentId), counts: this.audit.counts(agentId), paused: this.paused.has(agentId) }));
135
+ }
136
+ // ----- connection lifecycle -----
137
+ onConnection(ws) {
138
+ if (this.conns.size >= MAX_PENDING + 64) {
139
+ ws.close(1013);
140
+ return;
141
+ } // overall cap (pending + authed)
142
+ const conn = { ws, session: null, helloTimer: null };
143
+ this.conns.add(conn);
144
+ conn.helloTimer = setTimeout(() => { if (!conn.session) {
145
+ try {
146
+ ws.close(4001);
147
+ }
148
+ catch { /* ignore */ }
149
+ } }, HELLO_TIMEOUT_MS);
150
+ conn.helloTimer.unref?.();
151
+ ws.onMessage = (text) => this.onMessage(conn, text);
152
+ ws.onClose = () => this.onClose(conn);
153
+ }
154
+ onClose(conn) {
155
+ if (conn.helloTimer)
156
+ clearTimeout(conn.helloTimer);
157
+ if (conn.session)
158
+ this.audit.append({ agentId: conn.session.agentId, agentName: conn.session.agentName, session: conn.session.id, kind: 'disconnect', tool: '-', detail: 'socket closed', ok: true });
159
+ this.conns.delete(conn);
160
+ }
161
+ reply(conn, id, result) { conn.ws.send({ jsonrpc: '2.0', id, result }); }
162
+ fail(conn, id, code, message, data) { conn.ws.send({ jsonrpc: '2.0', id, error: { code, message, ...(data ? { data } : {}) } }); }
163
+ onMessage(conn, text) {
164
+ if (text.length > 256 * 1024) {
165
+ conn.ws.close(1009);
166
+ return;
167
+ }
168
+ let msg;
169
+ try {
170
+ msg = JSON.parse(text);
171
+ }
172
+ catch {
173
+ this.fail(conn, null, -32700, 'parse error');
174
+ return;
175
+ }
176
+ if (!msg || typeof msg !== 'object' || msg.jsonrpc !== '2.0' || typeof msg.method !== 'string') {
177
+ this.fail(conn, msg?.id ?? null, -32600, 'invalid request');
178
+ return;
179
+ }
180
+ const id = msg.id ?? null;
181
+ const params = (msg.params && typeof msg.params === 'object' && !Array.isArray(msg.params)) ? msg.params : {};
182
+ if (msg.method === 'hello') {
183
+ void this.onHello(conn, id, params);
184
+ return;
185
+ }
186
+ if (msg.method === 'ping') {
187
+ this.reply(conn, id, { pong: true, t: this.now() });
188
+ return;
189
+ }
190
+ if (!conn.session) {
191
+ this.fail(conn, id, -32001, 'say hello first (authenticate with your agent name + token)');
192
+ return;
193
+ }
194
+ if (msg.method === 'tools/list') {
195
+ this.reply(conn, id, { tools: this.visibleToolDefs(conn.session) });
196
+ return;
197
+ }
198
+ if (msg.method === 'tools/call') {
199
+ void this.onCall(conn, id, params);
200
+ return;
201
+ }
202
+ this.fail(conn, id, -32601, `method not found: ${String(msg.method).slice(0, 40)}`);
203
+ }
204
+ async onHello(conn, id, params) {
205
+ if (conn.session) {
206
+ this.fail(conn, id, -32002, 'already authenticated on this connection');
207
+ return;
208
+ }
209
+ const name = params.name;
210
+ const token = params.token;
211
+ if (typeof name !== 'string' || !AGENT_NAME_RE.test(name) || !looksLikeToken(token)) {
212
+ this.audit.append({ agentId: null, agentName: typeof name === 'string' ? name.slice(0, 24) : '?', session: null, kind: 'refused', tool: 'hello', detail: 'bad credentials', ok: false });
213
+ this.fail(conn, id, -32010, 'authentication failed');
214
+ try {
215
+ conn.ws.close(4002);
216
+ }
217
+ catch { /* ignore */ }
218
+ return;
219
+ }
220
+ const rec = this.registry.verify(name, token);
221
+ if (!rec) {
222
+ this.audit.append({ agentId: null, agentName: name.slice(0, 24), session: null, kind: 'refused', tool: 'hello', detail: 'unknown agent or wrong token', ok: false });
223
+ this.fail(conn, id, -32010, 'authentication failed');
224
+ try {
225
+ conn.ws.close(4002);
226
+ }
227
+ catch { /* ignore */ }
228
+ return;
229
+ }
230
+ // connection cap per agent
231
+ const limits = this.gate.limitsFor(rec.id);
232
+ const live = [...this.conns].filter((c) => c.session && c.session.agentId === rec.id).length;
233
+ if (live >= limits.connections) {
234
+ this.fail(conn, id, -32011, `too many connections for this agent (max ${limits.connections})`);
235
+ try {
236
+ conn.ws.close(4009);
237
+ }
238
+ catch { /* ignore */ }
239
+ return;
240
+ }
241
+ // requested tier can only LOWER the granted one; a bogus request is ignored
242
+ const reqTier = isTier(params.tier) ? params.tier : rec.tier;
243
+ const tier = lowerTier(rec.tier, reqTier);
244
+ const client = firewallText(params.client, { max: 40 }).text.replace(/\s+/g, ' ').trim() || 'unknown';
245
+ if (rec.paused)
246
+ this.paused.add(rec.id);
247
+ this.gate.setAgentLimits(rec.id, rec.limits);
248
+ const scope = rec.scope && rec.scope.length ? new Set(rec.scope) : null;
249
+ const session = { id: `sess_${(++this.sessionSeq).toString(36)}`, agentId: rec.id, agentName: rec.name, tier, transport: 'bus', openedAt: this.now(), lastActivity: this.now(), closed: false, closedReason: null, client, topics: new Set(), scope };
250
+ conn.session = session;
251
+ if (conn.helloTimer) {
252
+ clearTimeout(conn.helloTimer);
253
+ conn.helloTimer = null;
254
+ }
255
+ this.audit.append({ agentId: rec.id, agentName: rec.name, session: session.id, kind: 'connect', tool: '-', detail: `tier ${tier}${scope ? ` · mandate[${[...scope].join(',')}]` : ''} · ${client} · ${conn.ws.remote}`, ok: true });
256
+ this.reply(conn, id, { protocol: BUS_PROTOCOL, agent: rec.name, tier, grantedTier: rec.tier, tools: this.visibleTools(session), mandate: scope ? [...scope] : null, paused: rec.paused });
257
+ }
258
+ async onCall(conn, id, params) {
259
+ const session = conn.session;
260
+ if (!session) {
261
+ this.fail(conn, id, -32001, 'say hello first');
262
+ return;
263
+ }
264
+ const name = typeof params.name === 'string' ? params.name : '';
265
+ const args = (params.arguments && typeof params.arguments === 'object' && !Array.isArray(params.arguments)) ? params.arguments : {};
266
+ const g = this.gate.check(session, { tool: name, args, schema: toolSchema(name) });
267
+ if (!g.ok) {
268
+ this.fail(conn, id, -32020, g.error, { code: g.code });
269
+ return;
270
+ }
271
+ try {
272
+ // bus-native observe
273
+ if (name === 'agent_whoami') {
274
+ this.reply(conn, id, this.whoami(session));
275
+ return;
276
+ }
277
+ if (name === 'subscribe') {
278
+ this.reply(conn, id, this.subscribe(conn, args));
279
+ return;
280
+ }
281
+ if (name === 'unsubscribe') {
282
+ this.reply(conn, id, this.unsubscribe(session, args));
283
+ return;
284
+ }
285
+ if (name === 'list_proposals') {
286
+ const limit = Math.min(Number(args.limit ?? 50), 100);
287
+ this.gate.record(session, name, `listed proposals`, 'call');
288
+ this.reply(conn, id, { proposals: this.proposals.list({ agentId: session.agentId, limit }) });
289
+ return;
290
+ }
291
+ // proposals
292
+ if (TOOL_TO_KIND[name]) {
293
+ const { proposal, duplicate } = this.proposals.create(session, name, args);
294
+ if (duplicate)
295
+ this.gate.refundProposal(session.agentId);
296
+ this.audit.append({ agentId: session.agentId, agentName: session.agentName, session: session.id, kind: 'proposal', tool: name, detail: `${duplicate ? 'duplicate ' : ''}${proposal.summary}`, ok: true });
297
+ this.reply(conn, id, { proposal, duplicate, note: 'This is a PROPOSAL. The user confirms it with a keypress; you can never arm, confirm or send it.' });
298
+ return;
299
+ }
300
+ // read / navigation / note → executor. Scrub every string leaf of the result before it reaches the
301
+ // agent (belt-and-braces over the source firewall): no escape/bidi/zero-width can pass through.
302
+ const result = scrubStrings(await this.executor.exec(session, name, args));
303
+ const isErr = typeof result.error === 'string';
304
+ this.gate.record(session, name, isErr ? `error: ${String(result.error).slice(0, 80)}` : summarise(name, args), name === 'agent_note' ? 'note' : 'call');
305
+ this.reply(conn, id, result);
306
+ return;
307
+ }
308
+ catch (e) {
309
+ this.fail(conn, id, -32000, 'internal error', { detail: e.message.slice(0, 80) });
310
+ }
311
+ }
312
+ whoami(session) {
313
+ return { agent: session.agentName, tier: session.tier, mandate: session.scope ? [...session.scope] : null, tools: this.visibleTools(session).map((t) => ({ name: t, tier: agentTool(t)?.tier })), usage: this.gate.usage(session.agentId), subscriptions: [...session.topics], note: 'Your identity, tier and mandate come from the server. You cannot change them.' };
314
+ }
315
+ /** Tool names this session may call: its tier surface, narrowed by a mandate (+ agent_whoami, always). */
316
+ visibleTools(session) {
317
+ const all = toolsForTier(session.tier);
318
+ if (!session.scope)
319
+ return all;
320
+ return all.filter((t) => t === 'agent_whoami' || session.scope.has(t));
321
+ }
322
+ /** The advertised tool DEFINITIONS for tools/list, narrowed the same way. */
323
+ visibleToolDefs(session) {
324
+ const defs = toolsForTierList(session.tier);
325
+ if (!session.scope)
326
+ return defs;
327
+ return defs.filter((t) => t.name === 'agent_whoami' || session.scope.has(t.name));
328
+ }
329
+ subscribe(conn, args) {
330
+ const session = conn.session;
331
+ const topics = Array.isArray(args.topics) ? args.topics.filter(isTopic) : [];
332
+ const limit = this.gate.limitsFor(session.agentId).maxTopics;
333
+ const added = [];
334
+ for (const t of topics) {
335
+ if (session.topics.size >= limit)
336
+ break;
337
+ if (!session.topics.has(t)) {
338
+ session.topics.add(t);
339
+ added.push(t);
340
+ }
341
+ }
342
+ this.audit.append({ agentId: session.agentId, agentName: session.agentName, session: session.id, kind: 'subscribe', tool: 'subscribe', detail: `+[${added.join(',')}]`, ok: true });
343
+ // push an immediate snapshot per newly-added topic, if the feed offers one
344
+ if (this.feed?.snapshot)
345
+ for (const t of added) {
346
+ const snap = this.feed.snapshot(t);
347
+ if (snap)
348
+ conn.ws.send({ jsonrpc: '2.0', method: 'event', params: scrubStrings({ topic: t, seq: 0, t: this.now(), data: snap, snapshot: true }) });
349
+ }
350
+ return { subscribed: [...session.topics] };
351
+ }
352
+ unsubscribe(session, args) {
353
+ const topics = Array.isArray(args.topics) ? args.topics.filter(isTopic) : null;
354
+ if (topics === null)
355
+ session.topics.clear();
356
+ else
357
+ for (const t of topics)
358
+ session.topics.delete(t);
359
+ return { subscribed: [...session.topics] };
360
+ }
361
+ /** Fan a feed event out to every session subscribed to its topic. */
362
+ fanout(ev) {
363
+ for (const c of this.conns) {
364
+ const s = c.session;
365
+ if (!s || s.closed || this.paused.has(s.agentId))
366
+ continue;
367
+ if (s.topics.has(ev.topic))
368
+ c.ws.send({ jsonrpc: '2.0', method: 'event', params: scrubStrings(ev) });
369
+ }
370
+ }
371
+ writeDiscovery() {
372
+ if (!this.discoveryPath)
373
+ return;
374
+ try {
375
+ mkdirSync(dirname(this.discoveryPath), { recursive: true, mode: 0o700 });
376
+ writeFileSync(this.discoveryPath, JSON.stringify({ protocol: BUS_PROTOCOL, port: this.port, pid: process.pid, startedAt: this.now() }, null, 2) + '\n', { mode: 0o600 });
377
+ try {
378
+ chmodSync(this.discoveryPath, 0o600);
379
+ }
380
+ catch { /* ignore */ }
381
+ }
382
+ catch { /* discovery is best-effort; the port can also be passed explicitly */ }
383
+ }
384
+ }
385
+ function summarise(name, args) {
386
+ const mint = typeof args.mint === 'string' ? args.mint.slice(0, 6) + '…' : '';
387
+ if (mint)
388
+ return `${name} ${mint}`;
389
+ if (typeof args.query === 'string')
390
+ return `${name} "${args.query.slice(0, 24)}"`;
391
+ if (typeof args.preset === 'string')
392
+ return `${name} ${args.preset}`;
393
+ return name;
394
+ }