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,22 @@
1
+ import { drawBlockArt, drawPlaceholder } from "./blocks.js";
2
+ export function coinImage(c, s) {
3
+ if (s.w <= 0 || s.h <= 0)
4
+ return;
5
+ if (s.img && c.imageMode === 'pixels' && s.key) {
6
+ for (let cy = 0; cy < s.h; cy++)
7
+ for (let cx = 0; cx < s.w; cx++)
8
+ c.put(s.x + cx, s.y + cy, ' ', { fg: s.bg, bg: s.bg, hard: true });
9
+ c.noRain(s.x, s.y, s.w, s.h);
10
+ c.images.push({ key: s.key, x: s.x, y: s.y, w: s.w, h: s.h, img: s.img, png: s.png ?? null });
11
+ return;
12
+ }
13
+ if (s.img) {
14
+ drawBlockArt(c, s.x, s.y, s.w, s.h, s.img, { mode: s.mode, depth: s.depth, bg: s.bg, cacheKey: s.key ?? null });
15
+ return;
16
+ }
17
+ drawPlaceholder(c, s.x, s.y, s.w, s.h, s.symbol, { depth: s.depth, bg: s.bg, pending: s.pending });
18
+ }
19
+ /** Cell boxes the screens use: a one-row list icon and the token-header hero. */
20
+ export const COIN_ICON_W = 2;
21
+ export const COIN_HERO_W = 8;
22
+ export const COIN_HERO_H = 4;
@@ -0,0 +1,140 @@
1
+ /** Stage 1: the environment's verdict. Pure. */
2
+ export function protocolFromEnv(env) {
3
+ const prog = (env.TERM_PROGRAM || '').toLowerCase();
4
+ const term = (env.TERM || '').toLowerCase();
5
+ const lcTerm = (env.LC_TERMINAL || '').toLowerCase();
6
+ // Multiplexers do not pass graphics through without extra setup: block art is the only safe answer.
7
+ if (env.TMUX || prog === 'tmux' || term.startsWith('tmux') || term.startsWith('screen') || env.STY)
8
+ return { protocol: 'blocks', reason: 'tmux/screen multiplexer (no graphics passthrough)' };
9
+ if (env.KITTY_WINDOW_ID || prog === 'kitty' || term === 'xterm-kitty')
10
+ return { protocol: 'kitty', reason: 'kitty' };
11
+ if (prog === 'ghostty' || term === 'xterm-ghostty' || env.GHOSTTY_RESOURCES_DIR)
12
+ return { protocol: 'kitty', reason: 'Ghostty (kitty graphics)' };
13
+ if (prog === 'wezterm' || env.WEZTERM_EXECUTABLE)
14
+ return { protocol: 'kitty', reason: 'WezTerm (kitty graphics)' };
15
+ if (env.KONSOLE_VERSION)
16
+ return { protocol: 'kitty', reason: 'Konsole (kitty graphics)' };
17
+ if (prog === 'iterm.app' || lcTerm === 'iterm2')
18
+ return { protocol: 'iterm', reason: 'iTerm2 (inline images)' };
19
+ if (prog === 'apple_terminal')
20
+ return { protocol: 'blocks', reason: 'Apple Terminal.app has no inline-image protocol' };
21
+ if (prog === 'vscode' || env.VSCODE_INJECTION)
22
+ return { protocol: 'blocks', reason: 'VS Code terminal (images off by default)' };
23
+ if (env.WT_SESSION)
24
+ return { protocol: 'blocks', reason: 'Windows Terminal (sixel only when advertised)' };
25
+ return { protocol: 'blocks', reason: `unknown terminal (${env.TERM_PROGRAM || env.TERM || 'no TERM'})` };
26
+ }
27
+ /** The probe bytes written to the tty: kitty query, cell-size report, DA1 (always answered last). */
28
+ export const CAPABILITY_QUERY = '\x1b_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\x1b\\\x1b[16t\x1b[c';
29
+ /**
30
+ * Stage 2 parser, pure: scan a reply buffer for the kitty acknowledgement, the `CSI 6;h;w t` cell size and
31
+ * the DA1 `CSI ? … c` line; sixel is advertised as parameter 4 in DA1. Returns how many bytes belong to
32
+ * the replies (the rest is user input). `done` is true once DA1 arrived.
33
+ */
34
+ export function parseQueryReply(buf) {
35
+ let kittyOk = false, sixel = false, da1 = null, cellPx = null;
36
+ let consumed = 0;
37
+ let i = 0;
38
+ while (i < buf.length) {
39
+ if (buf[i] !== '\x1b') {
40
+ i += 1;
41
+ continue;
42
+ }
43
+ // APC: ESC _ ... ESC \ (kitty reply: ESC_Gi=31;OK ESC\)
44
+ if (buf[i + 1] === '_') {
45
+ const end = buf.indexOf('\x1b\\', i + 2);
46
+ if (end < 0)
47
+ break; // partial
48
+ const body = buf.slice(i + 2, end);
49
+ if (/^Gi=31;OK/.test(body))
50
+ kittyOk = true;
51
+ i = end + 2;
52
+ consumed = i;
53
+ continue;
54
+ }
55
+ if (buf[i + 1] === '[') {
56
+ let j = i + 2;
57
+ while (j < buf.length && /[0-9;?]/.test(buf[j]))
58
+ j += 1;
59
+ const fin = buf[j];
60
+ if (fin === undefined)
61
+ break; // partial CSI
62
+ const params = buf.slice(i + 2, j);
63
+ if (fin === 't') {
64
+ const m = /^6;(\d+);(\d+)$/.exec(params);
65
+ if (m)
66
+ cellPx = { h: Number(m[1]), w: Number(m[2]) };
67
+ i = j + 1;
68
+ consumed = i;
69
+ continue;
70
+ }
71
+ if (fin === 'c' && params.startsWith('?')) {
72
+ da1 = params;
73
+ const ps = params.slice(1).split(';');
74
+ sixel = ps.includes('4');
75
+ i = j + 1;
76
+ consumed = i;
77
+ return { facts: { kittyOk, sixel, da1, cellPx, consumed }, done: true };
78
+ }
79
+ // some other CSI (a key?): not ours — stop consuming here
80
+ break;
81
+ }
82
+ break;
83
+ }
84
+ return { facts: { kittyOk, sixel, da1, cellPx, consumed }, done: false };
85
+ }
86
+ /** Stage 1 + 2 verdict, pure given the query facts. */
87
+ export function resolveProtocol(env, q) {
88
+ const e = protocolFromEnv(env);
89
+ const forced = (env.DEXTERM_IMAGES || '').toLowerCase();
90
+ if (forced === 'kitty' || forced === 'iterm' || forced === 'sixel' || forced === 'blocks')
91
+ return { protocol: forced, cellPx: q?.cellPx ?? null, reason: `DEXTERM_IMAGES=${forced}`, envProtocol: e.protocol, ...(q ? { query: q } : {}) };
92
+ if (e.reason.startsWith('tmux'))
93
+ return { protocol: 'blocks', cellPx: q?.cellPx ?? null, reason: e.reason, envProtocol: e.protocol, ...(q ? { query: q } : {}) };
94
+ if (q?.kittyOk)
95
+ return { protocol: 'kitty', cellPx: q.cellPx, reason: 'terminal answered the kitty graphics query', envProtocol: e.protocol, query: q };
96
+ if (e.protocol === 'kitty' && (!q || q.timedOut))
97
+ return { protocol: 'kitty', cellPx: q?.cellPx ?? null, reason: `${e.reason}; query unanswered, trusting the environment`, envProtocol: e.protocol, ...(q ? { query: q } : {}) };
98
+ if (e.protocol === 'kitty' && q && !q.kittyOk)
99
+ return { protocol: q.sixel ? 'sixel' : 'blocks', cellPx: q.cellPx, reason: `${e.reason} but the kitty query was refused`, envProtocol: e.protocol, query: q };
100
+ if (e.protocol === 'iterm')
101
+ return { protocol: 'iterm', cellPx: q?.cellPx ?? null, reason: e.reason, envProtocol: e.protocol, ...(q ? { query: q } : {}) };
102
+ if (q?.sixel)
103
+ return { protocol: 'sixel', cellPx: q.cellPx, reason: 'DA1 advertises sixel', envProtocol: e.protocol, query: q };
104
+ return { protocol: 'blocks', cellPx: q?.cellPx ?? null, reason: e.reason, envProtocol: e.protocol, ...(q ? { query: q } : {}) };
105
+ }
106
+ /**
107
+ * Run the capability query on a raw-mode tty. Resolves with the facts plus any trailing bytes that were
108
+ * NOT part of a reply (early keypresses), so the caller can feed them to its key parser. Never rejects.
109
+ */
110
+ export function queryTerminal(io, timeoutMs = 150) {
111
+ const now = io.now ?? (() => Date.now());
112
+ const t0 = now();
113
+ return new Promise((resolve) => {
114
+ let buf = '';
115
+ let settled = false;
116
+ let off = () => { };
117
+ const finish = (timedOut) => {
118
+ if (settled)
119
+ return;
120
+ settled = true;
121
+ clearTimeout(timer);
122
+ off();
123
+ const { facts } = parseQueryReply(buf);
124
+ resolve({ facts: { ...facts, elapsedMs: now() - t0, timedOut }, leftover: buf.slice(facts.consumed) });
125
+ };
126
+ const timer = setTimeout(() => finish(true), timeoutMs);
127
+ timer.unref?.();
128
+ off = io.onData((chunk) => {
129
+ buf += chunk;
130
+ if (parseQueryReply(buf).done)
131
+ finish(false);
132
+ });
133
+ try {
134
+ io.write(CAPABILITY_QUERY);
135
+ }
136
+ catch {
137
+ finish(true);
138
+ }
139
+ });
140
+ }
@@ -0,0 +1,7 @@
1
+ // @dexterm/tui — coin images in the terminal (task-1326).
2
+ export { protocolFromEnv, parseQueryReply, resolveProtocol, queryTerminal, CAPABILITY_QUERY } from "./detect.js";
3
+ export { sampleGrid, ditherTo256, nearest256, gridHex, luma, flattenTo, resampleRgba } from "./pixels.js";
4
+ export { drawBlockArt, drawPlaceholder, placeholderColor, placeholderInitial } from "./blocks.js";
5
+ export { cup, kittyTransmit, kittyPlace, kittyDeletePlacement, kittyDeleteAllPlacements, kittyFreeAll, itermInline, sixelEncode, KITTY_CHUNK } from "./protocols.js";
6
+ export { ImageLayer } from "./layer.js";
7
+ export { coinImage, COIN_ICON_W, COIN_HERO_W, COIN_HERO_H } from "./coin.js";
@@ -0,0 +1,146 @@
1
+ import { flattenTo, resampleRgba } from "./pixels.js";
2
+ import { cup, kittyTransmit, kittyPlace, kittyDeletePlacement, kittyDeleteAllPlacements, kittyFreeAll, itermInline, sixelEncode } from "./protocols.js";
3
+ export class ImageLayer {
4
+ protocol;
5
+ opts;
6
+ ids = new Map();
7
+ transmitted = new Set();
8
+ placements = [];
9
+ drawn = new Map(); // iterm/sixel: "x,y" → key
10
+ nextId = 1000;
11
+ nextPid = 1;
12
+ lastScreen = null;
13
+ /** Counters for the handoff / measurements. */
14
+ stats = { transmits: 0, places: 0, deletes: 0, emits: 0, bytes: 0 };
15
+ constructor(protocol, opts) {
16
+ this.protocol = protocol;
17
+ this.opts = opts;
18
+ }
19
+ idFor(key) {
20
+ let id = this.ids.get(key);
21
+ if (id === undefined) {
22
+ id = this.nextId++;
23
+ this.ids.set(key, id);
24
+ }
25
+ return id;
26
+ }
27
+ /** Largest pixel box for a `w × h` cell slot: square-ish, bounded by maxPx. */
28
+ pixelBox(w, h) {
29
+ const cell = this.opts.cellPx ?? { w: 9, h: 18 };
30
+ const maxPx = this.opts.maxPx ?? 144;
31
+ const bw = w * cell.w, bh = h * cell.h;
32
+ const side = Math.min(bw, bh, maxPx);
33
+ return { pw: Math.max(1, Math.round(side)), ph: Math.max(1, Math.round(side)) };
34
+ }
35
+ /** Bytes to write after a flush. */
36
+ sync(input) {
37
+ let out = '';
38
+ const slots = dedupe(input.slots);
39
+ if (this.protocol === 'kitty') {
40
+ const full = input.changed === 'all';
41
+ if (this.lastScreen !== null && (input.screen !== this.lastScreen || full)) {
42
+ if (this.placements.length) {
43
+ out += kittyDeleteAllPlacements();
44
+ this.stats.deletes += this.placements.length;
45
+ }
46
+ this.placements = [];
47
+ }
48
+ this.lastScreen = input.screen;
49
+ const keep = [];
50
+ const want = new Map();
51
+ for (const s of slots)
52
+ want.set(`${s.key}@${s.x},${s.y},${s.w},${s.h}`, s);
53
+ for (const p of this.placements) {
54
+ const k = `${p.key}@${p.x},${p.y},${p.w},${p.h}`;
55
+ if (want.has(k)) {
56
+ keep.push(p);
57
+ want.delete(k);
58
+ }
59
+ else {
60
+ out += kittyDeletePlacement(p.id, p.pid);
61
+ this.stats.deletes += 1;
62
+ }
63
+ }
64
+ for (const s of want.values()) {
65
+ const id = this.idFor(s.key);
66
+ if (!this.transmitted.has(id)) {
67
+ const { pw, ph } = this.pixelBox(s.w, s.h);
68
+ const small = s.img.w > pw * 2 || s.img.h > ph * 2 ? resampleRgba(s.img, Math.min(s.img.w, pw * 2), Math.min(s.img.h, ph * 2)) : s.img;
69
+ const t = kittyTransmit(id, small);
70
+ out += t;
71
+ this.stats.transmits += 1;
72
+ this.stats.bytes += t.length;
73
+ this.transmitted.add(id);
74
+ }
75
+ const pid = this.nextPid++;
76
+ out += cup(s.y, s.x) + kittyPlace(id, pid, s.w, s.h);
77
+ this.stats.places += 1;
78
+ keep.push({ key: s.key, x: s.x, y: s.y, w: s.w, h: s.h, id, pid });
79
+ }
80
+ this.placements = keep;
81
+ return out;
82
+ }
83
+ // iterm / sixel: cell-bound images
84
+ const changed = input.changed;
85
+ const nextDrawn = new Map();
86
+ for (const s of slots) {
87
+ const pos = `${s.x},${s.y}`;
88
+ let rowsChanged = changed === 'all';
89
+ if (!rowsChanged)
90
+ for (let y = s.y; y < s.y + s.h; y++)
91
+ if (changed[y]) {
92
+ rowsChanged = true;
93
+ break;
94
+ }
95
+ const isNew = this.drawn.get(pos) !== s.key;
96
+ if (rowsChanged || isNew) {
97
+ const { pw, ph } = this.pixelBox(s.w, s.h);
98
+ let seq;
99
+ if (this.protocol === 'iterm') {
100
+ const png = s.png ?? (this.opts.encodePng ? this.opts.encodePng(resampleRgba(s.img, Math.min(s.img.w, pw * 2), Math.min(s.img.h, ph * 2))) : null);
101
+ if (!png)
102
+ continue;
103
+ seq = itermInline(png, s.w, s.h);
104
+ }
105
+ else {
106
+ // sixel has no alpha: flatten over the theme bg; height rounded down to a 6-row band multiple
107
+ const sh = Math.max(6, Math.floor(ph / 6) * 6);
108
+ seq = sixelEncode(flattenTo(s.img, pw, sh, this.opts.bg()));
109
+ }
110
+ out += cup(s.y, s.x) + seq;
111
+ this.stats.emits += 1;
112
+ this.stats.bytes += seq.length;
113
+ }
114
+ nextDrawn.set(pos, s.key);
115
+ }
116
+ this.drawn = nextDrawn;
117
+ return out;
118
+ }
119
+ /** Screen is about to change: forget cell-bound images (their rows will be rewritten). */
120
+ invalidate() { this.drawn.clear(); }
121
+ /** Everything off the screen; kitty also frees transmitted data. */
122
+ teardown() {
123
+ this.drawn.clear();
124
+ if (this.protocol !== 'kitty')
125
+ return '';
126
+ const had = this.placements.length > 0 || this.transmitted.size > 0;
127
+ this.placements = [];
128
+ this.transmitted.clear();
129
+ this.ids.clear();
130
+ return had ? kittyFreeAll() : '';
131
+ }
132
+ }
133
+ function dedupe(slots) {
134
+ const seen = new Set();
135
+ const out = [];
136
+ for (const s of slots) {
137
+ if (s.w <= 0 || s.h <= 0)
138
+ continue;
139
+ const k = `${s.x},${s.y}`;
140
+ if (seen.has(k))
141
+ continue;
142
+ seen.add(k);
143
+ out.push(s);
144
+ }
145
+ return out;
146
+ }
@@ -0,0 +1,157 @@
1
+ // @dexterm/tui — pixel helpers for the terminal image renderers (task-1326). Pure, dependency-free
2
+ // (the data package owns decoding; this file only needs an RGBA buffer). Compositing over the theme
3
+ // background, area-average sampling to a tiny grid, 256-colour quantisation with error diffusion.
4
+ import { hexToRgb, rgbToHex } from "../color.js";
5
+ /** Area-average the source over a `w × h` grid, compositing alpha over `bg`. Returns packed RGB rows. */
6
+ export function sampleGrid(img, w, h, bg) {
7
+ const [br, bgG, bb] = hexToRgb(bg);
8
+ const out = new Float32Array(w * h * 3);
9
+ const xs = img.w / w, ys = img.h / h;
10
+ for (let y = 0; y < h; y++) {
11
+ const y0 = y * ys, y1 = (y + 1) * ys;
12
+ for (let x = 0; x < w; x++) {
13
+ const x0 = x * xs, x1 = (x + 1) * xs;
14
+ let r = 0, g = 0, b = 0, a = 0, wsum = 0;
15
+ for (let sy = Math.floor(y0); sy < Math.min(img.h, Math.ceil(y1)); sy++) {
16
+ const wy = Math.min(y1, sy + 1) - Math.max(y0, sy);
17
+ if (wy <= 0)
18
+ continue;
19
+ for (let sx = Math.floor(x0); sx < Math.min(img.w, Math.ceil(x1)); sx++) {
20
+ const wx = Math.min(x1, sx + 1) - Math.max(x0, sx);
21
+ if (wx <= 0)
22
+ continue;
23
+ const wgt = wx * wy, o = (sy * img.w + sx) * 4, al = img.rgba[o + 3] / 255;
24
+ r += img.rgba[o] * al * wgt;
25
+ g += img.rgba[o + 1] * al * wgt;
26
+ b += img.rgba[o + 2] * al * wgt;
27
+ a += al * wgt;
28
+ wsum += wgt;
29
+ }
30
+ }
31
+ const oo = (y * w + x) * 3;
32
+ if (wsum <= 0) {
33
+ out[oo] = br;
34
+ out[oo + 1] = bgG;
35
+ out[oo + 2] = bb;
36
+ continue;
37
+ }
38
+ const cov = a / wsum; // coverage 0..1
39
+ const cr = a > 0 ? r / a : 0, cg = a > 0 ? g / a : 0, cb = a > 0 ? b / a : 0;
40
+ out[oo] = cr * cov + br * (1 - cov);
41
+ out[oo + 1] = cg * cov + bgG * (1 - cov);
42
+ out[oo + 2] = cb * cov + bb * (1 - cov);
43
+ }
44
+ }
45
+ return out;
46
+ }
47
+ // xterm-256: 6×6×6 cube (16..231) + 24 greys (232..255). Same tables as color.ts hexToAnsi256.
48
+ const CUBE = [0, 95, 135, 175, 215, 255];
49
+ const GREYS = Array.from({ length: 24 }, (_, i) => 8 + 10 * i);
50
+ /** Nearest xterm-256 colour (as RGB) to an RGB triple: cube or grey, whichever is closer. */
51
+ export function nearest256(r, g, b) {
52
+ const ci = (v) => { let best = 0, bd = Infinity; for (let i = 0; i < 6; i++) {
53
+ const d = Math.abs(CUBE[i] - v);
54
+ if (d < bd) {
55
+ bd = d;
56
+ best = i;
57
+ }
58
+ } return CUBE[best]; };
59
+ const cr = ci(r), cg = ci(g), cb = ci(b);
60
+ const cubeD = (cr - r) ** 2 + (cg - g) ** 2 + (cb - b) ** 2;
61
+ const avg = (r + g + b) / 3;
62
+ let gi = Math.round((avg - 8) / 10);
63
+ gi = Math.max(0, Math.min(23, gi));
64
+ const gv = GREYS[gi];
65
+ const greyD = (gv - r) ** 2 + (gv - g) ** 2 + (gv - b) ** 2;
66
+ return greyD < cubeD ? [gv, gv, gv] : [cr, cg, cb];
67
+ }
68
+ /**
69
+ * Quantise a sampled grid to the 256-colour palette with Floyd–Steinberg error diffusion. The palette
70
+ * cube is coarse (6 levels), so without diffusion a round logo on a dark panel turns into one flat blob;
71
+ * with it the tone gradients that make a disc read as a disc survive. Error is clamped so a single hot
72
+ * pixel cannot smear across the icon. In place; returns the same array.
73
+ */
74
+ export function ditherTo256(grid, w, h, strength = 0.75) {
75
+ const err = new Float32Array((w + 2) * 3 * 2); // two rows of error, 1px padding each side
76
+ const idx = (row, x) => (row * (w + 2) + x + 1) * 3;
77
+ for (let y = 0; y < h; y++) {
78
+ const cur = y & 1, nxt = cur ^ 1;
79
+ for (let x = -1; x <= w; x++) {
80
+ const o = idx(nxt, x);
81
+ err[o] = 0;
82
+ err[o + 1] = 0;
83
+ err[o + 2] = 0;
84
+ }
85
+ for (let x = 0; x < w; x++) {
86
+ const o = (y * w + x) * 3, e = idx(cur, x);
87
+ const r = Math.max(0, Math.min(255, grid[o] + err[e])), g = Math.max(0, Math.min(255, grid[o + 1] + err[e + 1])), b = Math.max(0, Math.min(255, grid[o + 2] + err[e + 2]));
88
+ const [qr, qg, qb] = nearest256(r, g, b);
89
+ grid[o] = qr;
90
+ grid[o + 1] = qg;
91
+ grid[o + 2] = qb;
92
+ const dr = Math.max(-48, Math.min(48, (r - qr) * strength)), dg = Math.max(-48, Math.min(48, (g - qg) * strength)), db = Math.max(-48, Math.min(48, (b - qb) * strength));
93
+ const spread = (row, xx, f) => { const q = idx(row, xx); err[q] += dr * f; err[q + 1] += dg * f; err[q + 2] += db * f; };
94
+ spread(cur, x + 1, 7 / 16);
95
+ spread(nxt, x - 1, 3 / 16);
96
+ spread(nxt, x, 5 / 16);
97
+ spread(nxt, x + 1, 1 / 16);
98
+ }
99
+ }
100
+ return grid;
101
+ }
102
+ export function gridHex(grid, i) {
103
+ return rgbToHex(Math.round(grid[i * 3]), Math.round(grid[i * 3 + 1]), Math.round(grid[i * 3 + 2]));
104
+ }
105
+ /** Luma 0..255. */
106
+ export function luma(r, g, b) { return 0.2126 * r + 0.7152 * g + 0.0722 * b; }
107
+ /**
108
+ * Composite straight-alpha RGBA over an opaque background colour and resample to `w × h` (area average),
109
+ * returning an opaque RGBA buffer — what the pixel protocols (sixel, kitty RGB) and the HTML proof use.
110
+ */
111
+ export function flattenTo(img, w, h, bg) {
112
+ const grid = sampleGrid(img, w, h, bg);
113
+ const rgba = new Uint8Array(w * h * 4);
114
+ for (let i = 0; i < w * h; i++) {
115
+ rgba[i * 4] = Math.round(grid[i * 3]);
116
+ rgba[i * 4 + 1] = Math.round(grid[i * 3 + 1]);
117
+ rgba[i * 4 + 2] = Math.round(grid[i * 3 + 2]);
118
+ rgba[i * 4 + 3] = 255;
119
+ }
120
+ return { w, h, rgba };
121
+ }
122
+ /** Area-average resample keeping alpha (for kitty RGBA placements that let the terminal composite). */
123
+ export function resampleRgba(img, w, h) {
124
+ const out = new Uint8Array(w * h * 4);
125
+ const xs = img.w / w, ys = img.h / h;
126
+ for (let y = 0; y < h; y++) {
127
+ const y0 = y * ys, y1 = (y + 1) * ys;
128
+ for (let x = 0; x < w; x++) {
129
+ const x0 = x * xs, x1 = (x + 1) * xs;
130
+ let r = 0, g = 0, b = 0, a = 0, wsum = 0;
131
+ for (let sy = Math.floor(y0); sy < Math.min(img.h, Math.ceil(y1)); sy++) {
132
+ const wy = Math.min(y1, sy + 1) - Math.max(y0, sy);
133
+ if (wy <= 0)
134
+ continue;
135
+ for (let sx = Math.floor(x0); sx < Math.min(img.w, Math.ceil(x1)); sx++) {
136
+ const wx = Math.min(x1, sx + 1) - Math.max(x0, sx);
137
+ if (wx <= 0)
138
+ continue;
139
+ const wgt = wx * wy, o = (sy * img.w + sx) * 4, al = img.rgba[o + 3] / 255;
140
+ r += img.rgba[o] * al * wgt;
141
+ g += img.rgba[o + 1] * al * wgt;
142
+ b += img.rgba[o + 2] * al * wgt;
143
+ a += al * wgt;
144
+ wsum += wgt;
145
+ }
146
+ }
147
+ const oo = (y * w + x) * 4;
148
+ if (wsum <= 0 || a <= 0)
149
+ continue;
150
+ out[oo] = Math.round(r / a);
151
+ out[oo + 1] = Math.round(g / a);
152
+ out[oo + 2] = Math.round(b / a);
153
+ out[oo + 3] = Math.round((a / wsum) * 255);
154
+ }
155
+ }
156
+ return { w, h, rgba: out };
157
+ }
@@ -0,0 +1,87 @@
1
+ const ESC = '\x1b';
2
+ export const KITTY_CHUNK = 4096;
3
+ /** `CSI row;col H` (1-based). */
4
+ export function cup(row, col) { return `${ESC}[${row + 1};${col + 1}H`; }
5
+ // ---------------------------------------------------------------------------------------------- kitty
6
+ /** Transmit straight-alpha RGBA as image `id` (no placement). Chunked at 4096 base64 bytes per APC. */
7
+ export function kittyTransmit(id, img) {
8
+ const b64 = Buffer.from(img.rgba.buffer, img.rgba.byteOffset, img.rgba.byteLength).toString('base64');
9
+ let out = '';
10
+ for (let i = 0; i < b64.length; i += KITTY_CHUNK) {
11
+ const chunk = b64.slice(i, i + KITTY_CHUNK);
12
+ const more = i + KITTY_CHUNK < b64.length ? 1 : 0;
13
+ const ctl = i === 0 ? `a=t,f=32,s=${img.w},v=${img.h},i=${id},q=2,m=${more}` : `m=${more}`;
14
+ out += `${ESC}_G${ctl};${chunk}${ESC}\\`;
15
+ }
16
+ return out;
17
+ }
18
+ /** Place image `id` as placement `pid` over `cols × rows` cells at the cursor, cursor unmoved. */
19
+ export function kittyPlace(id, pid, cols, rows) {
20
+ return `${ESC}_Ga=p,i=${id},p=${pid},c=${cols},r=${rows},C=1,q=2${ESC}\\`;
21
+ }
22
+ export function kittyDeletePlacement(id, pid) { return `${ESC}_Ga=d,d=i,i=${id},p=${pid},q=2${ESC}\\`; }
23
+ /** Delete every visible placement, keep the transmitted data (screen change). */
24
+ export function kittyDeleteAllPlacements() { return `${ESC}_Ga=d,d=a,q=2${ESC}\\`; }
25
+ /** Delete every placement AND free the image data (quit). */
26
+ export function kittyFreeAll() { return `${ESC}_Ga=d,d=A,q=2${ESC}\\`; }
27
+ // ---------------------------------------------------------------------------------------------- iTerm2
28
+ export function itermInline(png, cols, rows) {
29
+ const b64 = Buffer.from(png.buffer, png.byteOffset, png.byteLength).toString('base64');
30
+ return `${ESC}]1337;File=inline=1;size=${png.byteLength};width=${cols};height=${rows};preserveAspectRatio=1;doNotMoveCursor=1:${b64}\x07`;
31
+ }
32
+ // ---------------------------------------------------------------------------------------------- sixel
33
+ /** Opaque pixels → a ≤ 252-colour sixel image (6×7×6 uniform levels; plenty for a thumbnail). */
34
+ export function sixelEncode(img) {
35
+ const { w, h, rgba } = img;
36
+ if (w <= 0 || h <= 0)
37
+ return '';
38
+ const RL = 6, GL = 7, BL = 6;
39
+ const q = (v, levels) => Math.min(levels - 1, Math.round((v / 255) * (levels - 1)));
40
+ const idx = new Uint16Array(w * h);
41
+ const used = new Set();
42
+ for (let i = 0; i < w * h; i++) {
43
+ const r = q(rgba[i * 4], RL), g = q(rgba[i * 4 + 1], GL), b = q(rgba[i * 4 + 2], BL);
44
+ const k = (r * GL + g) * BL + b;
45
+ idx[i] = k;
46
+ used.add(k);
47
+ }
48
+ let out = `${ESC}P0;1q"1;1;${w};${h}`;
49
+ for (const k of used) {
50
+ const b = k % BL, g = Math.floor(k / BL) % GL, r = Math.floor(k / (BL * GL));
51
+ const pc = (v, levels) => Math.round((v / (levels - 1)) * 100);
52
+ out += `#${k};2;${pc(r, RL)};${pc(g, GL)};${pc(b, BL)}`;
53
+ }
54
+ for (let band = 0; band < h; band += 6) {
55
+ const rows = Math.min(6, h - band);
56
+ const bandColors = new Set();
57
+ for (let y = band; y < band + rows; y++)
58
+ for (let x = 0; x < w; x++)
59
+ bandColors.add(idx[y * w + x]);
60
+ let first = true;
61
+ for (const k of bandColors) {
62
+ if (!first)
63
+ out += '$';
64
+ first = false;
65
+ out += `#${k}`;
66
+ let run = 0, last = -1;
67
+ const flush = () => { if (run <= 0)
68
+ return; const ch = String.fromCharCode(63 + last); out += run > 3 ? `!${run}${ch}` : ch.repeat(run); run = 0; };
69
+ for (let x = 0; x < w; x++) {
70
+ let bits = 0;
71
+ for (let r = 0; r < rows; r++)
72
+ if (idx[(band + r) * w + x] === k)
73
+ bits |= 1 << r;
74
+ if (bits === last)
75
+ run += 1;
76
+ else {
77
+ flush();
78
+ last = bits;
79
+ run = 1;
80
+ }
81
+ }
82
+ flush();
83
+ }
84
+ out += '-';
85
+ }
86
+ return out + `${ESC}\\`;
87
+ }
@@ -0,0 +1,15 @@
1
+ // @dexterm/tui — public surface.
2
+ export * from "./color.js";
3
+ export * from "./theme.js";
4
+ export * from "./fmt.js";
5
+ export * from "./canvas.js";
6
+ export * from "./flush.js";
7
+ export * from "./layout.js";
8
+ export * from "./keymap.js";
9
+ export * from "./widgets.js";
10
+ export * from "./fx.js";
11
+ export * from "./fx-trade.js";
12
+ export * from "./sound.js";
13
+ export * from "./bubbles.js";
14
+ export * from "./chrome.js";
15
+ export * from "./images/index.js";