@agentdeck/bridge 0.2.2 → 1.0.0

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 (435) hide show
  1. package/assets/fm-helper/agentdeck-fm-helper +0 -0
  2. package/assets/fonts/IBMPlexSans-Bold.ttf +0 -0
  3. package/assets/fonts/IBMPlexSans-Regular.ttf +0 -0
  4. package/assets/fonts/JetBrainsMono-Bold.ttf +0 -0
  5. package/assets/fonts/JetBrainsMono-Regular.ttf +0 -0
  6. package/assets/fonts/LICENSES.md +22 -0
  7. package/dist/adapters/claude-code.d.ts +6 -0
  8. package/dist/adapters/claude-code.d.ts.map +1 -1
  9. package/dist/adapters/claude-code.js +8 -0
  10. package/dist/adapters/claude-code.js.map +1 -1
  11. package/dist/adapters/openclaw.d.ts +24 -0
  12. package/dist/adapters/openclaw.d.ts.map +1 -1
  13. package/dist/adapters/openclaw.js +291 -35
  14. package/dist/adapters/openclaw.js.map +1 -1
  15. package/dist/adapters/opencode-adapter.d.ts +59 -0
  16. package/dist/adapters/opencode-adapter.d.ts.map +1 -1
  17. package/dist/adapters/opencode-adapter.js +297 -35
  18. package/dist/adapters/opencode-adapter.js.map +1 -1
  19. package/dist/adb-reverse.d.ts +1 -1
  20. package/dist/adb-reverse.js +1 -1
  21. package/dist/antigravity-local.d.ts +1 -0
  22. package/dist/antigravity-local.d.ts.map +1 -1
  23. package/dist/antigravity-local.js +33 -0
  24. package/dist/antigravity-local.js.map +1 -1
  25. package/dist/apme/adapters/claude-hook.d.ts.map +1 -1
  26. package/dist/apme/adapters/claude-hook.js +5 -0
  27. package/dist/apme/adapters/claude-hook.js.map +1 -1
  28. package/dist/apme/adapters/codex-hook.d.ts +17 -0
  29. package/dist/apme/adapters/codex-hook.d.ts.map +1 -0
  30. package/dist/apme/adapters/codex-hook.js +95 -0
  31. package/dist/apme/adapters/codex-hook.js.map +1 -0
  32. package/dist/apme/adapters/codex-turn-manager.d.ts +86 -0
  33. package/dist/apme/adapters/codex-turn-manager.d.ts.map +1 -0
  34. package/dist/apme/adapters/codex-turn-manager.js +496 -0
  35. package/dist/apme/adapters/codex-turn-manager.js.map +1 -0
  36. package/dist/apme/adapters/openclaw-hook.d.ts +99 -0
  37. package/dist/apme/adapters/openclaw-hook.d.ts.map +1 -0
  38. package/dist/apme/adapters/openclaw-hook.js +234 -0
  39. package/dist/apme/adapters/openclaw-hook.js.map +1 -0
  40. package/dist/apme/adapters/opencode-hook.d.ts +56 -0
  41. package/dist/apme/adapters/opencode-hook.d.ts.map +1 -0
  42. package/dist/apme/adapters/opencode-hook.js +182 -0
  43. package/dist/apme/adapters/opencode-hook.js.map +1 -0
  44. package/dist/apme/adapters/timeline.d.ts.map +1 -1
  45. package/dist/apme/adapters/timeline.js +6 -1
  46. package/dist/apme/adapters/timeline.js.map +1 -1
  47. package/dist/apme/antigravity-transcript.d.ts +18 -0
  48. package/dist/apme/antigravity-transcript.d.ts.map +1 -0
  49. package/dist/apme/antigravity-transcript.js +94 -0
  50. package/dist/apme/antigravity-transcript.js.map +1 -0
  51. package/dist/apme/classify-turn.d.ts +13 -0
  52. package/dist/apme/classify-turn.d.ts.map +1 -0
  53. package/dist/apme/classify-turn.js +49 -0
  54. package/dist/apme/classify-turn.js.map +1 -0
  55. package/dist/apme/claude-transcript-reader.d.ts +10 -0
  56. package/dist/apme/claude-transcript-reader.d.ts.map +1 -1
  57. package/dist/apme/claude-transcript-reader.js +35 -0
  58. package/dist/apme/claude-transcript-reader.js.map +1 -1
  59. package/dist/apme/collector.d.ts +133 -6
  60. package/dist/apme/collector.d.ts.map +1 -1
  61. package/dist/apme/collector.js +471 -23
  62. package/dist/apme/collector.js.map +1 -1
  63. package/dist/apme/dashboard-html.d.ts.map +1 -1
  64. package/dist/apme/dashboard-html.js +117 -11
  65. package/dist/apme/dashboard-html.js.map +1 -1
  66. package/dist/apme/http.d.ts.map +1 -1
  67. package/dist/apme/http.js +52 -6
  68. package/dist/apme/http.js.map +1 -1
  69. package/dist/apme/index.d.ts +26 -5
  70. package/dist/apme/index.d.ts.map +1 -1
  71. package/dist/apme/index.js +146 -9
  72. package/dist/apme/index.js.map +1 -1
  73. package/dist/apme/judge-detect.d.ts +26 -0
  74. package/dist/apme/judge-detect.d.ts.map +1 -0
  75. package/dist/apme/judge-detect.js +69 -0
  76. package/dist/apme/judge-detect.js.map +1 -0
  77. package/dist/apme/pareto.d.ts +39 -0
  78. package/dist/apme/pareto.d.ts.map +1 -0
  79. package/dist/apme/pareto.js +59 -0
  80. package/dist/apme/pareto.js.map +1 -0
  81. package/dist/apme/recommend.d.ts +3 -0
  82. package/dist/apme/recommend.d.ts.map +1 -1
  83. package/dist/apme/recommend.js +43 -1
  84. package/dist/apme/recommend.js.map +1 -1
  85. package/dist/apme/runner.d.ts +99 -4
  86. package/dist/apme/runner.d.ts.map +1 -1
  87. package/dist/apme/runner.js +743 -72
  88. package/dist/apme/runner.js.map +1 -1
  89. package/dist/apme/sample-to-timeline.d.ts +26 -0
  90. package/dist/apme/sample-to-timeline.d.ts.map +1 -0
  91. package/dist/apme/sample-to-timeline.js +95 -0
  92. package/dist/apme/sample-to-timeline.js.map +1 -0
  93. package/dist/apme/scorers/index.d.ts +47 -0
  94. package/dist/apme/scorers/index.d.ts.map +1 -0
  95. package/dist/apme/scorers/index.js +96 -0
  96. package/dist/apme/scorers/index.js.map +1 -0
  97. package/dist/apme/settings.d.ts +17 -11
  98. package/dist/apme/settings.d.ts.map +1 -1
  99. package/dist/apme/settings.js +30 -9
  100. package/dist/apme/settings.js.map +1 -1
  101. package/dist/apme/store.d.ts +33 -1
  102. package/dist/apme/store.d.ts.map +1 -1
  103. package/dist/apme/store.js +334 -25
  104. package/dist/apme/store.js.map +1 -1
  105. package/dist/awaiting-overlay.d.ts +112 -0
  106. package/dist/awaiting-overlay.d.ts.map +1 -0
  107. package/dist/awaiting-overlay.js +179 -0
  108. package/dist/awaiting-overlay.js.map +1 -0
  109. package/dist/ble-sync-spawn.d.ts +63 -0
  110. package/dist/ble-sync-spawn.d.ts.map +1 -0
  111. package/dist/ble-sync-spawn.js +196 -0
  112. package/dist/ble-sync-spawn.js.map +1 -0
  113. package/dist/bridge-core.d.ts +34 -1
  114. package/dist/bridge-core.d.ts.map +1 -1
  115. package/dist/bridge-core.js +207 -24
  116. package/dist/bridge-core.js.map +1 -1
  117. package/dist/broadcast.d.ts +3 -0
  118. package/dist/broadcast.d.ts.map +1 -0
  119. package/dist/broadcast.js +122 -0
  120. package/dist/broadcast.js.map +1 -0
  121. package/dist/check-deps.d.ts.map +1 -1
  122. package/dist/check-deps.js +25 -9
  123. package/dist/check-deps.js.map +1 -1
  124. package/dist/claude-permission-rules.d.ts +55 -0
  125. package/dist/claude-permission-rules.d.ts.map +1 -0
  126. package/dist/claude-permission-rules.js +197 -0
  127. package/dist/claude-permission-rules.js.map +1 -0
  128. package/dist/cli.d.ts +15 -1
  129. package/dist/cli.d.ts.map +1 -1
  130. package/dist/cli.js +1030 -93
  131. package/dist/cli.js.map +1 -1
  132. package/dist/codex-auth.d.ts +21 -0
  133. package/dist/codex-auth.d.ts.map +1 -1
  134. package/dist/codex-auth.js +52 -1
  135. package/dist/codex-auth.js.map +1 -1
  136. package/dist/codex-output-parser.d.ts +8 -0
  137. package/dist/codex-output-parser.d.ts.map +1 -1
  138. package/dist/codex-output-parser.js +110 -25
  139. package/dist/codex-output-parser.js.map +1 -1
  140. package/dist/codex-rate-limits.d.ts +16 -0
  141. package/dist/codex-rate-limits.d.ts.map +1 -0
  142. package/dist/codex-rate-limits.js +197 -0
  143. package/dist/codex-rate-limits.js.map +1 -0
  144. package/dist/codex-rollout-response.d.ts +31 -0
  145. package/dist/codex-rollout-response.d.ts.map +1 -0
  146. package/dist/codex-rollout-response.js +135 -0
  147. package/dist/codex-rollout-response.js.map +1 -0
  148. package/dist/d200h/image-renderer.d.ts +4 -16
  149. package/dist/d200h/image-renderer.d.ts.map +1 -1
  150. package/dist/d200h/image-renderer.js +46 -212
  151. package/dist/d200h/image-renderer.js.map +1 -1
  152. package/dist/daemon-server.d.ts +85 -0
  153. package/dist/daemon-server.d.ts.map +1 -1
  154. package/dist/daemon-server.js +1975 -159
  155. package/dist/daemon-server.js.map +1 -1
  156. package/dist/daemon.js +15 -6
  157. package/dist/daemon.js.map +1 -1
  158. package/dist/display-dim.d.ts +9 -0
  159. package/dist/display-dim.d.ts.map +1 -0
  160. package/dist/display-dim.js +53 -0
  161. package/dist/display-dim.js.map +1 -0
  162. package/dist/display-monitor.d.ts +15 -2
  163. package/dist/display-monitor.d.ts.map +1 -1
  164. package/dist/display-monitor.js +104 -26
  165. package/dist/display-monitor.js.map +1 -1
  166. package/dist/esp32-serial.d.ts +190 -1
  167. package/dist/esp32-serial.d.ts.map +1 -1
  168. package/dist/esp32-serial.js +1090 -156
  169. package/dist/esp32-serial.js.map +1 -1
  170. package/dist/fallback-task-timeline.d.ts +42 -0
  171. package/dist/fallback-task-timeline.d.ts.map +1 -0
  172. package/dist/fallback-task-timeline.js +119 -0
  173. package/dist/fallback-task-timeline.js.map +1 -0
  174. package/dist/foundation-models-helper.d.ts +11 -0
  175. package/dist/foundation-models-helper.d.ts.map +1 -0
  176. package/dist/foundation-models-helper.js +241 -0
  177. package/dist/foundation-models-helper.js.map +1 -0
  178. package/dist/hook-migration.js +1 -1
  179. package/dist/hook-migration.js.map +1 -1
  180. package/dist/hook-server.d.ts +2 -3
  181. package/dist/hook-server.d.ts.map +1 -1
  182. package/dist/hook-server.js +23 -10
  183. package/dist/hook-server.js.map +1 -1
  184. package/dist/idotmatrix/idotmatrix-daemon-sync.d.ts +33 -0
  185. package/dist/idotmatrix/idotmatrix-daemon-sync.d.ts.map +1 -0
  186. package/dist/idotmatrix/idotmatrix-daemon-sync.js +164 -0
  187. package/dist/idotmatrix/idotmatrix-daemon-sync.js.map +1 -0
  188. package/dist/idotmatrix/idotmatrix-discover.d.ts +18 -0
  189. package/dist/idotmatrix/idotmatrix-discover.d.ts.map +1 -0
  190. package/dist/idotmatrix/idotmatrix-discover.js +85 -0
  191. package/dist/idotmatrix/idotmatrix-discover.js.map +1 -0
  192. package/dist/idotmatrix/idotmatrix-settings.d.ts +20 -0
  193. package/dist/idotmatrix/idotmatrix-settings.d.ts.map +1 -0
  194. package/dist/idotmatrix/idotmatrix-settings.js +57 -0
  195. package/dist/idotmatrix/idotmatrix-settings.js.map +1 -0
  196. package/dist/index.d.ts.map +1 -1
  197. package/dist/index.js +217 -179
  198. package/dist/index.js.map +1 -1
  199. package/dist/log-stream.d.ts +15 -16
  200. package/dist/log-stream.d.ts.map +1 -1
  201. package/dist/log-stream.js +18 -96
  202. package/dist/log-stream.js.map +1 -1
  203. package/dist/logger.d.ts +3 -1
  204. package/dist/logger.d.ts.map +1 -1
  205. package/dist/logger.js +18 -5
  206. package/dist/logger.js.map +1 -1
  207. package/dist/mdns.d.ts +17 -0
  208. package/dist/mdns.d.ts.map +1 -1
  209. package/dist/mdns.js +52 -18
  210. package/dist/mdns.js.map +1 -1
  211. package/dist/model-catalog.d.ts +1 -1
  212. package/dist/model-catalog.d.ts.map +1 -1
  213. package/dist/model-catalog.js +2 -4
  214. package/dist/model-catalog.js.map +1 -1
  215. package/dist/modules/adb-module.d.ts +1 -1
  216. package/dist/modules/adb-module.d.ts.map +1 -1
  217. package/dist/modules/adb-module.js +4 -3
  218. package/dist/modules/adb-module.js.map +1 -1
  219. package/dist/modules/broadcast-module.d.ts +17 -0
  220. package/dist/modules/broadcast-module.d.ts.map +1 -0
  221. package/dist/modules/broadcast-module.js +26 -0
  222. package/dist/modules/broadcast-module.js.map +1 -0
  223. package/dist/modules/d200h-module.d.ts +22 -0
  224. package/dist/modules/d200h-module.d.ts.map +1 -1
  225. package/dist/modules/d200h-module.js +200 -65
  226. package/dist/modules/d200h-module.js.map +1 -1
  227. package/dist/modules/idotmatrix-module.d.ts +9 -0
  228. package/dist/modules/idotmatrix-module.d.ts.map +1 -0
  229. package/dist/modules/idotmatrix-module.js +46 -0
  230. package/dist/modules/idotmatrix-module.js.map +1 -0
  231. package/dist/modules/index.d.ts +3 -1
  232. package/dist/modules/index.d.ts.map +1 -1
  233. package/dist/modules/index.js +9 -3
  234. package/dist/modules/index.js.map +1 -1
  235. package/dist/modules/pixoo-module.d.ts.map +1 -1
  236. package/dist/modules/pixoo-module.js +14 -4
  237. package/dist/modules/pixoo-module.js.map +1 -1
  238. package/dist/modules/serial-module.d.ts +4 -0
  239. package/dist/modules/serial-module.d.ts.map +1 -1
  240. package/dist/modules/serial-module.js +14 -12
  241. package/dist/modules/serial-module.js.map +1 -1
  242. package/dist/modules/timebox-module.d.ts +9 -0
  243. package/dist/modules/timebox-module.d.ts.map +1 -0
  244. package/dist/modules/timebox-module.js +46 -0
  245. package/dist/modules/timebox-module.js.map +1 -0
  246. package/dist/modules/trmnl-module.d.ts +38 -0
  247. package/dist/modules/trmnl-module.d.ts.map +1 -0
  248. package/dist/modules/trmnl-module.js +111 -0
  249. package/dist/modules/trmnl-module.js.map +1 -0
  250. package/dist/modules/types.d.ts +4 -2
  251. package/dist/modules/types.d.ts.map +1 -1
  252. package/dist/observed-steering.d.ts +93 -0
  253. package/dist/observed-steering.d.ts.map +1 -0
  254. package/dist/observed-steering.js +247 -0
  255. package/dist/observed-steering.js.map +1 -0
  256. package/dist/openclaw-session.d.ts +18 -0
  257. package/dist/openclaw-session.d.ts.map +1 -0
  258. package/dist/openclaw-session.js +34 -0
  259. package/dist/openclaw-session.js.map +1 -0
  260. package/dist/opencode-steering.d.ts +36 -0
  261. package/dist/opencode-steering.d.ts.map +1 -0
  262. package/dist/opencode-steering.js +84 -0
  263. package/dist/opencode-steering.js.map +1 -0
  264. package/dist/output-parser.d.ts +30 -0
  265. package/dist/output-parser.d.ts.map +1 -1
  266. package/dist/output-parser.js +172 -18
  267. package/dist/output-parser.js.map +1 -1
  268. package/dist/passive-observer.d.ts +32 -0
  269. package/dist/passive-observer.d.ts.map +1 -1
  270. package/dist/passive-observer.js +288 -49
  271. package/dist/passive-observer.js.map +1 -1
  272. package/dist/permission-resolver.d.ts +55 -0
  273. package/dist/permission-resolver.d.ts.map +1 -0
  274. package/dist/permission-resolver.js +112 -0
  275. package/dist/permission-resolver.js.map +1 -0
  276. package/dist/pixoo/micro-glyphs.d.ts +18 -0
  277. package/dist/pixoo/micro-glyphs.d.ts.map +1 -0
  278. package/dist/pixoo/micro-glyphs.js +143 -0
  279. package/dist/pixoo/micro-glyphs.js.map +1 -0
  280. package/dist/pixoo/official-dot-glyphs.generated.d.ts +8 -0
  281. package/dist/pixoo/official-dot-glyphs.generated.d.ts.map +1 -0
  282. package/dist/pixoo/official-dot-glyphs.generated.js +247 -0
  283. package/dist/pixoo/official-dot-glyphs.generated.js.map +1 -0
  284. package/dist/pixoo/pixoo-bridge.d.ts +16 -8
  285. package/dist/pixoo/pixoo-bridge.d.ts.map +1 -1
  286. package/dist/pixoo/pixoo-bridge.js +127 -35
  287. package/dist/pixoo/pixoo-bridge.js.map +1 -1
  288. package/dist/pixoo/pixoo-camera.d.ts +19 -3
  289. package/dist/pixoo/pixoo-camera.d.ts.map +1 -1
  290. package/dist/pixoo/pixoo-camera.js +62 -27
  291. package/dist/pixoo/pixoo-camera.js.map +1 -1
  292. package/dist/pixoo/pixoo-client.d.ts +13 -3
  293. package/dist/pixoo/pixoo-client.d.ts.map +1 -1
  294. package/dist/pixoo/pixoo-client.js +51 -22
  295. package/dist/pixoo/pixoo-client.js.map +1 -1
  296. package/dist/pixoo/pixoo-discover.d.ts +37 -0
  297. package/dist/pixoo/pixoo-discover.d.ts.map +1 -0
  298. package/dist/pixoo/pixoo-discover.js +105 -0
  299. package/dist/pixoo/pixoo-discover.js.map +1 -0
  300. package/dist/pixoo/pixoo-renderer.d.ts +27 -3
  301. package/dist/pixoo/pixoo-renderer.d.ts.map +1 -1
  302. package/dist/pixoo/pixoo-renderer.js +533 -135
  303. package/dist/pixoo/pixoo-renderer.js.map +1 -1
  304. package/dist/pixoo/pixoo-settings.d.ts +6 -0
  305. package/dist/pixoo/pixoo-settings.d.ts.map +1 -1
  306. package/dist/pixoo/pixoo-settings.js +9 -0
  307. package/dist/pixoo/pixoo-settings.js.map +1 -1
  308. package/dist/pixoo/pixoo-sprites.d.ts +84 -11
  309. package/dist/pixoo/pixoo-sprites.d.ts.map +1 -1
  310. package/dist/pixoo/pixoo-sprites.js +620 -209
  311. package/dist/pixoo/pixoo-sprites.js.map +1 -1
  312. package/dist/pty-manager.d.ts.map +1 -1
  313. package/dist/pty-manager.js +8 -2
  314. package/dist/pty-manager.js.map +1 -1
  315. package/dist/review-runner.d.ts +113 -0
  316. package/dist/review-runner.d.ts.map +1 -0
  317. package/dist/review-runner.js +428 -0
  318. package/dist/review-runner.js.map +1 -0
  319. package/dist/session-activity.d.ts +14 -0
  320. package/dist/session-activity.d.ts.map +1 -0
  321. package/dist/session-activity.js +160 -0
  322. package/dist/session-activity.js.map +1 -0
  323. package/dist/session-aggregator.d.ts +25 -0
  324. package/dist/session-aggregator.d.ts.map +1 -1
  325. package/dist/session-aggregator.js +48 -9
  326. package/dist/session-aggregator.js.map +1 -1
  327. package/dist/session-focus-relay.d.ts.map +1 -1
  328. package/dist/session-focus-relay.js +7 -1
  329. package/dist/session-focus-relay.js.map +1 -1
  330. package/dist/session-registry.d.ts +74 -3
  331. package/dist/session-registry.d.ts.map +1 -1
  332. package/dist/session-registry.js +140 -8
  333. package/dist/session-registry.js.map +1 -1
  334. package/dist/session-timeline-relay.d.ts.map +1 -1
  335. package/dist/session-timeline-relay.js +13 -4
  336. package/dist/session-timeline-relay.js.map +1 -1
  337. package/dist/session-transcript-timeline.d.ts +49 -0
  338. package/dist/session-transcript-timeline.d.ts.map +1 -0
  339. package/dist/session-transcript-timeline.js +276 -0
  340. package/dist/session-transcript-timeline.js.map +1 -0
  341. package/dist/state-machine.d.ts +6 -1
  342. package/dist/state-machine.d.ts.map +1 -1
  343. package/dist/state-machine.js +86 -28
  344. package/dist/state-machine.js.map +1 -1
  345. package/dist/timebox/timebox-daemon-sync.d.ts +19 -0
  346. package/dist/timebox/timebox-daemon-sync.d.ts.map +1 -0
  347. package/dist/timebox/timebox-daemon-sync.js +135 -0
  348. package/dist/timebox/timebox-daemon-sync.js.map +1 -0
  349. package/dist/timebox/timebox-discover.d.ts +19 -0
  350. package/dist/timebox/timebox-discover.d.ts.map +1 -0
  351. package/dist/timebox/timebox-discover.js +87 -0
  352. package/dist/timebox/timebox-discover.js.map +1 -0
  353. package/dist/timebox/timebox-settings.d.ts +32 -0
  354. package/dist/timebox/timebox-settings.d.ts.map +1 -0
  355. package/dist/timebox/timebox-settings.js +80 -0
  356. package/dist/timebox/timebox-settings.js.map +1 -0
  357. package/dist/timeline-store.d.ts +112 -3
  358. package/dist/timeline-store.d.ts.map +1 -1
  359. package/dist/timeline-store.js +460 -14
  360. package/dist/timeline-store.js.map +1 -1
  361. package/dist/timeline-summarizer.d.ts.map +1 -1
  362. package/dist/timeline-summarizer.js +29 -5
  363. package/dist/timeline-summarizer.js.map +1 -1
  364. package/dist/trmnl/byos-server.d.ts +39 -0
  365. package/dist/trmnl/byos-server.d.ts.map +1 -0
  366. package/dist/trmnl/byos-server.js +301 -0
  367. package/dist/trmnl/byos-server.js.map +1 -0
  368. package/dist/trmnl/frame-cache.d.ts +37 -0
  369. package/dist/trmnl/frame-cache.d.ts.map +1 -0
  370. package/dist/trmnl/frame-cache.js +157 -0
  371. package/dist/trmnl/frame-cache.js.map +1 -0
  372. package/dist/trmnl/image-renderer.d.ts +27 -0
  373. package/dist/trmnl/image-renderer.d.ts.map +1 -0
  374. package/dist/trmnl/image-renderer.js +235 -0
  375. package/dist/trmnl/image-renderer.js.map +1 -0
  376. package/dist/trmnl/trmnl-settings.d.ts +96 -0
  377. package/dist/trmnl/trmnl-settings.d.ts.map +1 -0
  378. package/dist/trmnl/trmnl-settings.js +177 -0
  379. package/dist/trmnl/trmnl-settings.js.map +1 -0
  380. package/dist/trmnl/trmnl-telemetry.d.ts +47 -0
  381. package/dist/trmnl/trmnl-telemetry.d.ts.map +1 -0
  382. package/dist/trmnl/trmnl-telemetry.js +56 -0
  383. package/dist/trmnl/trmnl-telemetry.js.map +1 -0
  384. package/dist/tui/ansi.d.ts +0 -4
  385. package/dist/tui/ansi.d.ts.map +1 -1
  386. package/dist/tui/ansi.js +14 -7
  387. package/dist/tui/ansi.js.map +1 -1
  388. package/dist/tui/dashboard.d.ts +1 -0
  389. package/dist/tui/dashboard.d.ts.map +1 -1
  390. package/dist/tui/dashboard.js +38 -11
  391. package/dist/tui/dashboard.js.map +1 -1
  392. package/dist/tui/renderer.d.ts +36 -0
  393. package/dist/tui/renderer.d.ts.map +1 -1
  394. package/dist/tui/renderer.js +355 -121
  395. package/dist/tui/renderer.js.map +1 -1
  396. package/dist/tui/terrarium.d.ts.map +1 -1
  397. package/dist/tui/terrarium.js +44 -51
  398. package/dist/tui/terrarium.js.map +1 -1
  399. package/dist/types.d.ts +2 -2
  400. package/dist/types.d.ts.map +1 -1
  401. package/dist/types.js +2 -2
  402. package/dist/types.js.map +1 -1
  403. package/dist/usage-api.d.ts.map +1 -1
  404. package/dist/usage-api.js +7 -1
  405. package/dist/usage-api.js.map +1 -1
  406. package/dist/usage-event.d.ts +10 -3
  407. package/dist/usage-event.d.ts.map +1 -1
  408. package/dist/usage-event.js +98 -13
  409. package/dist/usage-event.js.map +1 -1
  410. package/dist/utility-proxy.d.ts.map +1 -1
  411. package/dist/utility-proxy.js +8 -0
  412. package/dist/utility-proxy.js.map +1 -1
  413. package/dist/utils/project-name.d.ts +3 -0
  414. package/dist/utils/project-name.d.ts.map +1 -1
  415. package/dist/utils/project-name.js +44 -2
  416. package/dist/utils/project-name.js.map +1 -1
  417. package/dist/version-check.d.ts.map +1 -1
  418. package/dist/version-check.js +1 -17
  419. package/dist/version-check.js.map +1 -1
  420. package/dist/windows-service.d.ts +26 -0
  421. package/dist/windows-service.d.ts.map +1 -0
  422. package/dist/windows-service.js +145 -0
  423. package/dist/windows-service.js.map +1 -0
  424. package/dist/ws-server.d.ts +17 -3
  425. package/dist/ws-server.d.ts.map +1 -1
  426. package/dist/ws-server.js +78 -8
  427. package/dist/ws-server.js.map +1 -1
  428. package/fm-helper/AgentDeckFMHelper.swift +112 -0
  429. package/package.json +10 -4
  430. package/scripts/build-fm-helper.mjs +26 -0
  431. package/LICENSE +0 -21
  432. package/dist/apme/tuner.d.ts +0 -64
  433. package/dist/apme/tuner.d.ts.map +0 -1
  434. package/dist/apme/tuner.js +0 -297
  435. package/dist/apme/tuner.js.map +0 -1
@@ -9,7 +9,7 @@
9
9
  */
10
10
  import { cursor, screen as screenCodes, RESET, colors, box, hLine, sgr, stateColor, stateIcon, truncText, padRight, visLen, terminalCaps, centerText, fg, } from './ansi.js';
11
11
  import { blockGauge, resetTimeStr, formatTokens } from './gauge.js';
12
- import { sortSessions, assignDisplayNames } from '@agentdeck/shared';
12
+ import { sortSessions, assignDisplayNames, timelineShouldRenderTaskRow, timelineTaskHeaderDisplay, } from '@agentdeck/shared';
13
13
  // ===== Layout Breakpoints =====
14
14
  export function getLayout(cols, rows) {
15
15
  if (cols >= 120)
@@ -92,6 +92,11 @@ function typeIcon(type) {
92
92
  case 'scheduled': return 's';
93
93
  case 'user_action': return 'u';
94
94
  case 'eval_result': return '#';
95
+ // Task hierarchy -- mirrors timelineIconKey() (shared/src/timeline-icons.ts):
96
+ // task_start/task_end -> task, task_milestone -> success.
97
+ case 'task_start':
98
+ case 'task_end': return '=';
99
+ case 'task_milestone': return '+';
95
100
  default: return '*';
96
101
  }
97
102
  }
@@ -108,6 +113,10 @@ function typeIcon(type) {
108
113
  case 'model_response': return '\u25C8';
109
114
  case 'memory_recall': return '\u25CC';
110
115
  case 'scheduled': return '\u25D1';
116
+ // Task hierarchy -- mirrors timelineIconKey() (shared/src/timeline-icons.ts).
117
+ case 'task_start':
118
+ case 'task_end': return '\u25A3'; // white square w/ centre
119
+ case 'task_milestone': return '\u2713'; // check mark
111
120
  case 'eval_result': return '\u2605'; // ★
112
121
  default: return '\u25C6';
113
122
  }
@@ -140,20 +149,24 @@ function creatureEmoji(agentType) {
140
149
  return 'D';
141
150
  if (agentType === 'openclaw')
142
151
  return 'C';
143
- if (agentType === 'codex-cli')
152
+ if (agentType === 'codex-cli' || agentType === 'codex-app')
144
153
  return 'X';
145
154
  if (agentType === 'opencode')
146
155
  return 'O';
156
+ if (agentType === 'antigravity')
157
+ return 'A';
147
158
  return '*';
148
159
  }
149
160
  if (agentType === 'daemon')
150
161
  return '\u2699\uFE0F'; // ⚙️
151
162
  if (agentType === 'openclaw')
152
163
  return '\uD83E\uDD9E'; // 🦞
153
- if (agentType === 'codex-cli')
164
+ if (agentType === 'codex-cli' || agentType === 'codex-app')
154
165
  return '\u2601'; // ☁ (cloud — matches creature)
155
166
  if (agentType === 'opencode')
156
167
  return '\u25A3'; // ▣ (nested square — matches creature)
168
+ if (agentType === 'antigravity')
169
+ return '\u25B2'; // ▲ (Antigravity peak)
157
170
  return '\u273B'; // ✻ (teardrop-spoked asterisk — Claude sparkle)
158
171
  }
159
172
  function creatureBrandColor(agentType) {
@@ -162,8 +175,10 @@ function creatureBrandColor(agentType) {
162
175
  switch (agentType) {
163
176
  case 'claude-code': return fg(192, 112, 88); // terracotta
164
177
  case 'openclaw': return fg(255, 77, 77); // red
165
- case 'codex-cli': return fg(177, 167, 255); // indigo
178
+ case 'codex-cli':
179
+ case 'codex-app': return fg(177, 167, 255); // indigo
166
180
  case 'opencode': return fg(241, 236, 236); // warm gray (#F1ECEC)
181
+ case 'antigravity': return fg(210, 214, 220); // Google gray
167
182
  default: return '';
168
183
  }
169
184
  }
@@ -197,8 +212,129 @@ function sessionHotkeyLabel(index) {
197
212
  return '·';
198
213
  return String(index + 1);
199
214
  }
200
- function sessionHotkeyIndex(session, nextIndex) {
201
- if (!session.port || session.controlMode === 'observed')
215
+ /**
216
+ * Build the unified left-HUD entry list shared with macOS / iOS / Android.
217
+ *
218
+ * Collapses primary + siblings + virtual OpenClaw into one array, sorts via
219
+ * the shared sortSessions (agentType → projectName → startedAt → id), and
220
+ * applies #N suffix via assignDisplayNames so the display order and #N
221
+ * numbering match every other surface.
222
+ *
223
+ * Primary handling mirrors apple/AgentDeck/UI/Monitor/SessionListPanel.swift:
224
+ * - if a sibling matches our connected port, that sibling becomes the
225
+ * primary anchor (its startedAt anchors the sort position)
226
+ * - otherwise primary is appended only when no sibling shares its
227
+ * agentType (duplicatePrimaryWithoutId guard)
228
+ * - daemon / openclaw primaries are never appended (they're virtual)
229
+ */
230
+ export function buildHudEntries(state) {
231
+ const items = [];
232
+ const portToItem = new Map();
233
+ for (const s of state.sessions) {
234
+ const ri = s;
235
+ const item = {
236
+ id: s.id,
237
+ projectName: s.projectName ?? 'unknown',
238
+ agentType: s.agentType ?? undefined,
239
+ state: s.state ?? 'idle',
240
+ modelName: s.modelName ?? undefined,
241
+ startedAt: s.startedAt ?? undefined,
242
+ port: s.port ?? undefined,
243
+ controlMode: ri.controlMode,
244
+ currentTask: ri.currentTask,
245
+ contextPercent: ri.contextPercent,
246
+ totalTokens: ri.totalTokens,
247
+ isPrimary: false,
248
+ isVirtualOpenClaw: false,
249
+ };
250
+ items.push(item);
251
+ if (item.port !== undefined)
252
+ portToItem.set(item.port, item);
253
+ }
254
+ if (state.agentType && state.agentType !== 'daemon' && state.agentType !== 'openclaw' && state.state) {
255
+ const anchor = state.currentPort != null ? portToItem.get(state.currentPort) : undefined;
256
+ if (anchor) {
257
+ // Patch anchor with primary's live fields. macOS / Android compose
258
+ // SessionEntry from primary state and only borrow the anchor sibling's
259
+ // startedAt; if we left the sibling's snapshot in place the row would
260
+ // render stale modelName / state / currentTask whenever the sibling
261
+ // payload lagged the primary state_update. startedAt, port, id, and
262
+ // controlMode stay with the anchor so sort position and hotkey
263
+ // identity match every other surface.
264
+ anchor.isPrimary = true;
265
+ anchor.projectName = state.projectName ?? anchor.projectName;
266
+ anchor.agentType = state.agentType;
267
+ anchor.state = state.state;
268
+ anchor.modelName = state.modelName ?? undefined;
269
+ anchor.currentTask = state.currentTool ?? undefined;
270
+ }
271
+ else {
272
+ const duplicateAgentType = state.sessions.some(s => s.agentType === state.agentType);
273
+ if (!duplicateAgentType) {
274
+ items.push({
275
+ id: '__self__',
276
+ projectName: state.projectName ?? 'unknown',
277
+ agentType: state.agentType,
278
+ state: state.state,
279
+ modelName: state.modelName ?? undefined,
280
+ startedAt: undefined,
281
+ port: state.currentPort ?? undefined,
282
+ controlMode: undefined,
283
+ currentTask: state.currentTool ?? undefined,
284
+ contextPercent: undefined,
285
+ totalTokens: undefined,
286
+ isPrimary: true,
287
+ isVirtualOpenClaw: false,
288
+ });
289
+ }
290
+ }
291
+ }
292
+ const hasOpenClaw = items.some(it => it.agentType === 'openclaw' || it.agentType === 'gateway');
293
+ if (state.gatewayAvailable && !hasOpenClaw) {
294
+ items.push({
295
+ id: '__virtual_openclaw__',
296
+ projectName: 'OpenClaw',
297
+ agentType: 'openclaw',
298
+ state: state.crayfishRouting ? 'processing' : 'idle',
299
+ modelName: undefined,
300
+ startedAt: undefined,
301
+ port: undefined,
302
+ controlMode: undefined,
303
+ currentTask: undefined,
304
+ contextPercent: undefined,
305
+ totalTokens: undefined,
306
+ isPrimary: false,
307
+ isVirtualOpenClaw: true,
308
+ });
309
+ }
310
+ const sorted = sortSessions(items);
311
+ const named = assignDisplayNames(sorted.map(it => ({
312
+ id: it.id,
313
+ projectName: it.projectName,
314
+ agentType: it.agentType,
315
+ state: it.state,
316
+ })));
317
+ return sorted.map((it, i) => ({
318
+ id: it.id,
319
+ displayName: named[i].displayName,
320
+ projectName: it.projectName,
321
+ agentType: it.agentType,
322
+ state: it.state,
323
+ modelName: it.modelName,
324
+ startedAt: it.startedAt,
325
+ port: it.port,
326
+ controlMode: it.controlMode,
327
+ currentTask: it.currentTask,
328
+ contextPercent: it.contextPercent,
329
+ totalTokens: it.totalTokens,
330
+ isPrimary: it.isPrimary,
331
+ isVirtualOpenClaw: it.isVirtualOpenClaw,
332
+ }));
333
+ }
334
+ function hudHotkeyIndex(entry, nextIndex) {
335
+ if (entry.isPrimary || entry.isVirtualOpenClaw)
336
+ return null;
337
+ if (!entry.port || entry.controlMode === 'observed')
202
338
  return null;
203
339
  return nextIndex;
204
340
  }
@@ -214,6 +350,125 @@ function observedDetailParts(session) {
214
350
  parts.push(session.currentTask);
215
351
  return parts;
216
352
  }
353
+ function asRecord(value) {
354
+ return value && typeof value === 'object' && !Array.isArray(value)
355
+ ? value
356
+ : undefined;
357
+ }
358
+ function asArray(value) {
359
+ return Array.isArray(value) ? value : [];
360
+ }
361
+ function asNumber(value) {
362
+ return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
363
+ }
364
+ function moduleStatusIcon(ok, warning = false) {
365
+ if (!terminalCaps.unicode)
366
+ return ok ? 'o' : warning ? '!' : 'x';
367
+ return ok ? '\u25CF' : warning ? '\u25C6' : '\u25CB';
368
+ }
369
+ function renderModuleHealthLines(moduleHealth, width) {
370
+ const lines = [];
371
+ if (!moduleHealth)
372
+ return lines;
373
+ const push = (label, detail, ok, warning = false) => {
374
+ const color = ok ? colors.idle : warning ? colors.awaiting : colors.dim;
375
+ lines.push(` ${color}${moduleStatusIcon(ok, warning)}${RESET} ${truncText(`${label} ${detail}`.trim(), width - 4)}`);
376
+ };
377
+ const serial = asRecord(moduleHealth.serial);
378
+ if (serial) {
379
+ const connections = asArray(serial.connections).map(asRecord).filter(Boolean);
380
+ const connected = connections.filter((c) => c.connected === true || c.transportOpen === true);
381
+ const boards = connected
382
+ .map((c) => asRecord(c.deviceInfo)?.board)
383
+ .filter((b) => typeof b === 'string' && b.length > 0);
384
+ const count = asNumber(serial.connectionCount) ?? connected.length;
385
+ const shown = boards.slice(0, 3).join(', ');
386
+ const more = boards.length > 3 ? ` +${boards.length - 3}` : '';
387
+ const detail = count > 0 ? `${count}${shown ? `: ${shown}${more}` : ''}` : 'none';
388
+ push('Serial', detail, count > 0, Boolean(serial.lastError));
389
+ }
390
+ const pixoo = asRecord(moduleHealth.pixoo);
391
+ if (pixoo) {
392
+ const devices = asArray(pixoo.devices).map(asRecord).filter(Boolean);
393
+ const configured = asNumber(pixoo.configuredDeviceCount) ?? devices.length;
394
+ const online = devices.filter((d) => d.online === true && d.backedOff !== true).length;
395
+ const dimmed = pixoo.displayDimmed === true ? ' dim' : '';
396
+ push('Pixoo', `${online}/${configured}${dimmed}`, configured > 0 && online > 0, configured > 0);
397
+ }
398
+ // BLE matrix panels — Divoom Timebox Mini + iDotMatrix. The Swift daemon
399
+ // reports a live `connected`/`statusReason`; the Node daemon only knows a
400
+ // panel is configured (the Python BLE sync subprocess owns the link), so a
401
+ // configured-but-state-unknown panel reads as amber "cfg" rather than a red
402
+ // offline, which would be a false negative for a working Node-driven panel.
403
+ for (const [key, label] of [['timebox', 'Timebox'], ['idotmatrix', 'iDotMatrix']]) {
404
+ const m = asRecord(moduleHealth[key]);
405
+ if (!m)
406
+ continue;
407
+ const configured = asNumber(m.configuredDeviceCount) ?? asArray(m.devices).length;
408
+ if (configured <= 0)
409
+ continue;
410
+ const connected = m.connected === true;
411
+ const dimmed = m.displayDimmed === true ? ' dim' : '';
412
+ const reason = typeof m.statusReason === 'string' ? m.statusReason : '';
413
+ const detail = connected ? `ready${dimmed}` : (reason || `${configured} cfg`);
414
+ push(label, detail, connected, !connected);
415
+ }
416
+ // The daemon only emits d200h while the Ulanzi Studio plugin is connected —
417
+ // an absent key means no D200H row at all, not an offline one.
418
+ const d200h = asRecord(moduleHealth.d200h);
419
+ if (d200h) {
420
+ const connected = d200h.connected === true;
421
+ push('D200H', connected ? 'ready plugin' : 'offline', connected);
422
+ }
423
+ const adb = asRecord(moduleHealth.adb);
424
+ if (adb) {
425
+ const devices = asArray(adb.devices);
426
+ const reverse = asNumber(adb.reverseReadyCount) ?? devices.length;
427
+ const available = adb.available === true;
428
+ push('ADB', available ? `${reverse} reverse` : 'missing', available && reverse > 0, available);
429
+ }
430
+ // Stream Deck plugin roster — the plugin registers over WS; the daemon
431
+ // reports one row per attached deck. Mirrors the macOS TopologyRail /
432
+ // menubar Stream Deck section (Node-tier row added in bf23fb8e).
433
+ const streamDeck = asRecord(moduleHealth.streamDeck);
434
+ if (streamDeck) {
435
+ const devices = asArray(streamDeck.devices).map(asRecord).filter(Boolean);
436
+ for (const dev of devices) {
437
+ const name = typeof dev.name === 'string' && dev.name.length > 0 ? dev.name : 'Stream Deck';
438
+ const cols = asNumber(dev.columns);
439
+ const rows = asNumber(dev.rows);
440
+ const detail = cols && rows ? `${cols}×${rows}` : '';
441
+ push(name, detail, true);
442
+ }
443
+ }
444
+ // WiFi-only ESP32 boards. Dual-homed boards (also live on USB serial) are
445
+ // already shown in the Serial row, so filter them out here via the
446
+ // per-board `serialActive` flag — mirrors TopologyRail.wifiOnlyEsp32Boards.
447
+ const esp32Wifi = asRecord(moduleHealth.esp32Wifi);
448
+ if (esp32Wifi) {
449
+ const devices = asArray(esp32Wifi.devices).map(asRecord).filter(Boolean);
450
+ const wifiOnly = devices.filter((d) => d.serialActive !== true);
451
+ for (const dev of wifiOnly) {
452
+ const board = typeof dev.board === 'string' && dev.board.length > 0 ? dev.board : 'esp32';
453
+ const ip = typeof dev.ip === 'string' ? dev.ip : '';
454
+ const stale = dev.stale === true;
455
+ const detail = [ip, 'WiFi', stale ? 'stale' : ''].filter(Boolean).join(' · ');
456
+ push(`Wi-Fi ESP32 ${board}`, detail, !stale, stale);
457
+ }
458
+ }
459
+ // Terminal dashboards (`agentdeck dashboard`) attached to the daemon —
460
+ // presence-only roster, one row per open TUI WS. Mirrors the macOS
461
+ // TopologyRail "Terminal · TUI Dashboard" section.
462
+ const tuiDashboards = asRecord(moduleHealth.tuiDashboards);
463
+ if (tuiDashboards) {
464
+ const devices = asArray(tuiDashboards.devices).map(asRecord).filter(Boolean);
465
+ for (const dev of devices) {
466
+ const host = typeof dev.name === 'string' ? dev.name : '';
467
+ push('TUI Dashboard', host, true);
468
+ }
469
+ }
470
+ return lines;
471
+ }
217
472
  // ===== Panel Renderers =====
218
473
  function renderAgentLines(state, maxWidth, useLogo) {
219
474
  const lines = [];
@@ -241,68 +496,33 @@ function renderAgentLines(state, maxWidth, useLogo) {
241
496
  lines.push(` ${hotkey} ${emoji} ${col}${name}${RESET}`);
242
497
  lines.push(`${colors.dim} ${truncText(secondary, maxWidth - 4)}${RESET}`);
243
498
  };
244
- // #N suffix via shared assignDisplayNames
245
- // Daemon mode: sessions list already contains all agents (including virtual OpenClaw).
246
- // Also applies when daemon relays OpenClaw (agentType='openclaw' but sessions has the entry).
247
- // Session bridge mode: sessions has siblings only — prepend self.
248
- const isDaemonLike = state.agentType === 'daemon' ||
249
- (state.agentType && state.sessions.some(s => s.agentType === state.agentType));
250
- if (isDaemonLike) {
251
- const sorted = sortSessions(state.sessions);
252
- const displayed = assignDisplayNames(sorted.map(s => ({
253
- id: s.id, projectName: s.projectName || 'unknown', agentType: s.agentType, state: s.state,
254
- modelName: s.modelName,
255
- port: s.port, controlMode: s.controlMode,
256
- currentTask: s.currentTask,
257
- contextPercent: s.contextPercent,
258
- totalTokens: s.totalTokens,
259
- })));
260
- let focusableIndex = 0;
261
- for (const d of displayed) {
262
- const hotkeyIndex = sessionHotkeyIndex(d.session, focusableIndex);
263
- if (hotkeyIndex !== null)
264
- focusableIndex += 1;
265
- renderSession(d.displayName, d.session.modelName, d.session.state || 'idle', d.session.agentType, hotkeyIndex, d.session);
266
- }
267
- }
268
- else if (state.state) {
269
- // Self (primary session)
270
- renderSession(state.projectName || 'unknown', state.modelName ?? undefined, state.state, state.agentType ?? undefined, null);
271
- // Siblings — include self as virtual entry for correct #N numbering
272
- const sorted = sortSessions(state.sessions);
273
- const selfEntry = {
274
- id: '__self__', projectName: state.projectName || 'unknown',
275
- agentType: state.agentType ?? undefined, state: state.state,
276
- };
277
- const allForNumbering = [selfEntry, ...sorted.map(s => ({
278
- id: s.id, projectName: s.projectName || 'unknown', agentType: s.agentType, state: s.state,
279
- modelName: s.modelName,
280
- port: s.port, controlMode: s.controlMode,
281
- currentTask: s.currentTask,
282
- contextPercent: s.contextPercent,
283
- totalTokens: s.totalTokens,
284
- }))];
285
- const displayed = assignDisplayNames(allForNumbering);
286
- // Skip the self entry (index 0), render siblings with hotkey indices
287
- let focusableIndex = 0;
288
- for (let i = 1; i < displayed.length; i++) {
289
- const d = displayed[i];
290
- const sessionInfo = d.session;
291
- const hotkeyIndex = sessionHotkeyIndex(sessionInfo, focusableIndex);
292
- if (hotkeyIndex !== null)
293
- focusableIndex += 1;
294
- renderSession(d.displayName, d.session.modelName, d.session.state || 'idle', d.session.agentType, hotkeyIndex, sessionInfo);
295
- }
296
- }
297
- // Virtual OpenClaw entry when gateway detected but not in sessions list
298
- const hasOcSession = state.sessions.some(s => s.agentType === 'openclaw' || s.agentType === 'gateway');
299
- if (state.gatewayAvailable && !hasOcSession) {
300
- renderSession('OpenClaw', undefined, state.crayfishRouting ? 'processing' : 'idle', 'openclaw', null);
499
+ // Unified entry list (primary + siblings + virtual OpenClaw). Order and #N
500
+ // suffix matches macOS / iOS / Android via the shared sortSessions +
501
+ // assignDisplayNames pipeline inside buildHudEntries.
502
+ const entries = buildHudEntries(state);
503
+ let focusableIndex = 0;
504
+ for (const e of entries) {
505
+ const hotkeyIndex = hudHotkeyIndex(e, focusableIndex);
506
+ if (hotkeyIndex !== null)
507
+ focusableIndex += 1;
508
+ renderSession(e.displayName, e.modelName, e.state, e.agentType, hotkeyIndex, {
509
+ port: e.port,
510
+ controlMode: e.controlMode,
511
+ currentTask: e.currentTask,
512
+ contextPercent: e.contextPercent,
513
+ totalTokens: e.totalTokens,
514
+ });
301
515
  }
302
516
  // Gateway error warning
303
517
  if (state.gatewayHasError) {
304
518
  lines.push(`${colors.error} \u26A0 Gateway Error${RESET}`);
305
519
  }
520
+ const moduleLines = renderModuleHealthLines(state.moduleHealth, maxWidth);
521
+ if (moduleLines.length > 0) {
522
+ lines.push('');
523
+ lines.push(`${colors.header} DOWNSTREAM${RESET}`);
524
+ lines.push(...moduleLines);
525
+ }
306
526
  // Voice assistant indicator
307
527
  if (state.voiceAssistantState && state.voiceAssistantState !== 'disabled' && state.voiceAssistantState !== 'idle') {
308
528
  lines.push('');
@@ -391,9 +611,9 @@ function renderStatusLines(state, width) {
391
611
  }
392
612
  function renderOauthCatalogLines(modelCatalog, oauthConnected, width) {
393
613
  const lines = [];
394
- const models = modelCatalog.filter((m) => m.available).map((m) => m.name);
614
+ const models = (modelCatalog ?? []).filter((m) => m.available).map((m) => m.name);
395
615
  if (models.length > 0) {
396
- return wrapCommaList(' OAuth: ', models, width);
616
+ return wrapCommaList(' OAuth: ', models, width, 4);
397
617
  }
398
618
  if (oauthConnected === true) {
399
619
  lines.push(`${colors.dim}${truncText(' OAuth: connected', width)}${RESET}`);
@@ -403,22 +623,38 @@ function renderOauthCatalogLines(modelCatalog, oauthConnected, width) {
403
623
  }
404
624
  return lines;
405
625
  }
406
- function wrapCommaList(prefix, items, width) {
626
+ function wrapCommaList(prefix, items, width, maxLines = Number.POSITIVE_INFINITY) {
407
627
  const lines = [];
408
628
  const indent = ' '.repeat(prefix.length);
409
629
  let current = prefix;
630
+ let consumed = 0;
410
631
  for (let i = 0; i < items.length; i++) {
411
632
  const chunk = i === 0 ? items[i] : `, ${items[i]}`;
412
633
  if (visLen(current) + visLen(chunk) <= width) {
413
634
  current += chunk;
635
+ consumed = i + 1;
414
636
  continue;
415
637
  }
416
638
  if (visLen(current) > visLen(prefix)) {
417
639
  lines.push(`${colors.dim}${padRight(current, width)}${RESET}`.trimEnd());
640
+ if (lines.length >= maxLines) {
641
+ const hidden = items.length - consumed;
642
+ if (hidden > 0)
643
+ lines.push(`${colors.dim}${truncText(` ${hidden} more models`, width)}${RESET}`);
644
+ return lines;
645
+ }
418
646
  current = indent + items[i];
647
+ consumed = i + 1;
419
648
  continue;
420
649
  }
421
650
  lines.push(`${colors.dim}${truncText(current + chunk, width)}${RESET}`);
651
+ consumed = i + 1;
652
+ if (lines.length >= maxLines) {
653
+ const hidden = items.length - consumed;
654
+ if (hidden > 0)
655
+ lines.push(`${colors.dim}${truncText(` ${hidden} more models`, width)}${RESET}`);
656
+ return lines;
657
+ }
422
658
  current = indent;
423
659
  }
424
660
  if (visLen(current.trim()) > 0) {
@@ -440,7 +676,11 @@ function renderOllamaSummaryLines(ollamaStatus, width) {
440
676
  }
441
677
  function renderTimelineLines(state, width, maxLines, scrollOffset) {
442
678
  const lines = [];
443
- const entries = state.timeline;
679
+ // One-row-per-task render contract (shared/src/timeline-task-display.ts):
680
+ // task_end rows are data-only closure records — the task_start header folds
681
+ // in the closure label + judge verdict instead. Bare "Task N" headers with
682
+ // no eval payload (including every interrupted reaper closure) drop out.
683
+ const entries = state.timeline.filter((e) => timelineShouldRenderTaskRow(e, state.timeline));
444
684
  if (entries.length === 0) {
445
685
  lines.push(`${colors.dim} No events yet${RESET}`);
446
686
  return lines;
@@ -451,12 +691,39 @@ function renderTimelineLines(state, width, maxLines, scrollOffset) {
451
691
  const e = entries[i];
452
692
  const time = new Date(e.ts);
453
693
  const timeStr = `${String(time.getHours()).padStart(2, '0')}:${String(time.getMinutes()).padStart(2, '0')}`;
454
- const raw = truncText(e.raw, width - 10);
694
+ // Task headers render their folded closure: judge summary as title when
695
+ // the own title is a bare "Task N", the closure label ("Session end ·
696
+ // 2 turns · 6m") as a chip, and the score+outcome suffix once the judge
697
+ // resolves (5–30 s after the boundary itself).
698
+ let text = e.raw;
699
+ let evalSuffix = '';
700
+ if (e.type === 'task_start') {
701
+ const d = timelineTaskHeaderDisplay(e, state.timeline);
702
+ text = d.closureText ? `${d.title} · ${d.closureText}` : d.title;
703
+ if (d.taskOutcome)
704
+ evalSuffix = formatTaskEvalSuffix(d.taskScore, d.taskOutcome);
705
+ }
706
+ const raw = truncText(`${text}${evalSuffix}`, width - 10);
455
707
  const pending = e.status === 'pending' ? `${colors.dim} [PENDING]${RESET}` : '';
456
708
  lines.push(` ${colors.dim}${timeStr}${RESET} ${typeColor(e.type)}${typeIcon(e.type)}${RESET} ${raw}${pending}`);
457
709
  }
458
710
  return lines;
459
711
  }
712
+ export function formatTaskEvalSuffix(score, outcome) {
713
+ // `abandoned` flows from the manual `agentdeck task cancel` path and
714
+ // must render as its own glyph — not fall through to '' (which would
715
+ // make the task look pending) and not borrow the fail glyph (which
716
+ // would read as agent failure rather than user-initiated stop).
717
+ const glyph = outcome === 'success' ? '✓'
718
+ : outcome === 'fail' ? '✗'
719
+ : outcome === 'partial' ? '△'
720
+ : outcome === 'abandoned' ? '⊘'
721
+ : '';
722
+ if (!glyph)
723
+ return '';
724
+ const scoreText = typeof score === 'number' ? score.toFixed(2) : '?';
725
+ return ` · ${scoreText} ${glyph}`;
726
+ }
460
727
  function timelineHeader(state, width, maxLines, scrollOffset) {
461
728
  const total = state.timeline.length;
462
729
  if (total === 0)
@@ -649,64 +916,31 @@ function renderStandardLayout(state, cols, rows, terrariumLines, frame, scrollOf
649
916
  }
650
917
  function renderAgentCompactLines(state, width) {
651
918
  const lines = [];
652
- const isDaemonLikeCompact = state.agentType === 'daemon' ||
653
- (state.agentType && state.sessions.some(s => s.agentType === state.agentType));
654
- if (isDaemonLikeCompact) {
655
- let focusableIndex = 0;
656
- for (const s of sortSessions(state.sessions)) {
657
- const renderInfo = s;
658
- const st = s.state || 'idle';
659
- const col = stateColor(st);
660
- const emoji = `${creatureBrandColor(s.agentType)}${creatureEmoji(s.agentType)}${RESET}`;
661
- const status = `${col}${stateIcon(st)} ${compactStateLabel(st)}${RESET}`;
662
- const detail = renderInfo.currentTask || s.modelName;
663
- const model = detail ? `${colors.dim} · ${truncText(detail, Math.max(8, width - 24))}${RESET}` : '';
664
- const marker = renderInfo.controlMode === 'observed' ? `${colors.dim} · obs${RESET}` : '';
665
- const project = truncText(s.projectName || '?', Math.max(8, width - 20));
666
- const hotkeyIndex = sessionHotkeyIndex(renderInfo, focusableIndex);
667
- if (hotkeyIndex !== null)
668
- focusableIndex += 1;
669
- lines.push(` ${colors.dim}[${sessionHotkeyLabel(hotkeyIndex)}]${RESET} ${emoji} ${project} ${status}${marker}${model}`);
670
- }
671
- }
672
- else if (state.state) {
673
- // Self first
674
- const col = stateColor(state.state);
675
- const proj = truncText(state.projectName || '?', Math.max(8, width - 16));
676
- const status = `${col}${stateIcon(state.state)} ${compactStateLabel(state.state)}${RESET}`;
677
- const model = state.modelName ? `${colors.dim} · ${truncText(state.modelName, Math.max(8, width - 24))}${RESET}` : '';
678
- const emoji = `${creatureBrandColor(state.agentType ?? undefined)}${creatureEmoji(state.agentType ?? undefined)}${RESET}`;
679
- lines.push(` ${emoji} ${proj} ${status}${model}`);
680
- // Siblings
681
- let focusableIndex = 0;
682
- for (const s of sortSessions(state.sessions)) {
683
- const renderInfo = s;
684
- const st = s.state || 'idle';
685
- const sCol = stateColor(st);
686
- const sEmoji = `${creatureBrandColor(s.agentType)}${creatureEmoji(s.agentType)}${RESET}`;
687
- const sStatus = `${sCol}${stateIcon(st)} ${compactStateLabel(st)}${RESET}`;
688
- const detail = renderInfo.currentTask || s.modelName;
689
- const sModel = detail ? `${colors.dim} · ${truncText(detail, Math.max(8, width - 24))}${RESET}` : '';
690
- const marker = renderInfo.controlMode === 'observed' ? `${colors.dim} · obs${RESET}` : '';
691
- const sProject = truncText(s.projectName || '?', Math.max(8, width - 20));
692
- const hotkeyIndex = sessionHotkeyIndex(renderInfo, focusableIndex);
693
- if (hotkeyIndex !== null)
694
- focusableIndex += 1;
695
- lines.push(` ${colors.dim}[${sessionHotkeyLabel(hotkeyIndex)}]${RESET} ${sEmoji} ${sProject} ${sStatus}${marker}${sModel}`);
696
- }
697
- }
698
- // Virtual OpenClaw entry
699
- const hasOcCompact = state.sessions.some(s => s.agentType === 'openclaw' || s.agentType === 'gateway');
700
- if (state.gatewayAvailable && !hasOcCompact) {
701
- const ocState = state.crayfishRouting ? 'processing' : 'idle';
702
- const ocCol = stateColor(ocState);
703
- const ocEmoji = `${creatureBrandColor('openclaw')}${creatureEmoji('openclaw')}${RESET}`;
704
- lines.push(` ${ocEmoji} OpenClaw ${ocCol}${stateIcon(ocState)}${ocState.toUpperCase()}${RESET}`);
919
+ // Unified entry list same ordering and #N suffix as macOS / iOS / Android.
920
+ const entries = buildHudEntries(state);
921
+ let focusableIndex = 0;
922
+ for (const e of entries) {
923
+ const hotkeyIndex = hudHotkeyIndex(e, focusableIndex);
924
+ if (hotkeyIndex !== null)
925
+ focusableIndex += 1;
926
+ const col = stateColor(e.state);
927
+ const emoji = `${creatureBrandColor(e.agentType)}${creatureEmoji(e.agentType)}${RESET}`;
928
+ const status = `${col}${stateIcon(e.state)} ${compactStateLabel(e.state)}${RESET}`;
929
+ const detail = e.currentTask || e.modelName;
930
+ const model = detail ? `${colors.dim} · ${truncText(detail, Math.max(8, width - 24))}${RESET}` : '';
931
+ const marker = e.controlMode === 'observed' ? `${colors.dim} · obs${RESET}` : '';
932
+ const project = truncText(e.displayName, Math.max(8, width - 20));
933
+ lines.push(` ${colors.dim}[${sessionHotkeyLabel(hotkeyIndex)}]${RESET} ${emoji} ${project} ${status}${marker}${model}`);
705
934
  }
706
935
  // Gateway error warning
707
936
  if (state.gatewayHasError) {
708
937
  lines.push(`${colors.error} \u26A0 Gateway Error${RESET}`);
709
938
  }
939
+ const moduleLines = renderModuleHealthLines(state.moduleHealth, width);
940
+ if (moduleLines.length > 0) {
941
+ lines.push(`${colors.header} DOWNSTREAM${RESET}`);
942
+ lines.push(...moduleLines);
943
+ }
710
944
  // Voice assistant indicator (compact)
711
945
  if (state.voiceAssistantState && state.voiceAssistantState !== 'disabled' && state.voiceAssistantState !== 'idle') {
712
946
  if (state.voiceAssistantState === 'listening') {