omp-fabric 0.85.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 (772) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +170 -0
  3. package/THIRD_PARTY_NOTICES.md +33 -0
  4. package/dist/activity/store.d.ts +32 -0
  5. package/dist/activity/store.d.ts.map +1 -0
  6. package/dist/activity/types.d.ts +104 -0
  7. package/dist/activity/types.d.ts.map +1 -0
  8. package/dist/actors/binding-store.d.ts +17 -0
  9. package/dist/actors/binding-store.d.ts.map +1 -0
  10. package/dist/actors/context.d.ts +13 -0
  11. package/dist/actors/context.d.ts.map +1 -0
  12. package/dist/actors/delivery-policy.d.ts +8 -0
  13. package/dist/actors/delivery-policy.d.ts.map +1 -0
  14. package/dist/actors/directory.d.ts +47 -0
  15. package/dist/actors/directory.d.ts.map +1 -0
  16. package/dist/actors/global-registry.d.ts +47 -0
  17. package/dist/actors/global-registry.d.ts.map +1 -0
  18. package/dist/actors/host-event-observer.d.ts +5 -0
  19. package/dist/actors/host-event-observer.d.ts.map +1 -0
  20. package/dist/actors/host-event-payload.d.ts +14 -0
  21. package/dist/actors/host-event-payload.d.ts.map +1 -0
  22. package/dist/actors/manager.d.ts +175 -0
  23. package/dist/actors/manager.d.ts.map +1 -0
  24. package/dist/actors/predicate.d.ts +7 -0
  25. package/dist/actors/predicate.d.ts.map +1 -0
  26. package/dist/actors/types.d.ts +211 -0
  27. package/dist/actors/types.d.ts.map +1 -0
  28. package/dist/agents/bash-worktree-add.d.ts +24 -0
  29. package/dist/agents/bash-worktree-add.d.ts.map +1 -0
  30. package/dist/agents/budget-ledger.d.ts +88 -0
  31. package/dist/agents/budget-ledger.d.ts.map +1 -0
  32. package/dist/agents/claude-cli.d.ts +32 -0
  33. package/dist/agents/claude-cli.d.ts.map +1 -0
  34. package/dist/agents/claude-cli.js +17 -0
  35. package/dist/agents/claude-cli.js.map +7 -0
  36. package/dist/agents/clone-first-worktree.d.ts +17 -0
  37. package/dist/agents/clone-first-worktree.d.ts.map +1 -0
  38. package/dist/agents/compact-control.d.ts +32 -0
  39. package/dist/agents/compact-control.d.ts.map +1 -0
  40. package/dist/agents/compact-control.js +127 -0
  41. package/dist/agents/compact-control.js.map +7 -0
  42. package/dist/agents/constants.d.ts +5 -0
  43. package/dist/agents/constants.d.ts.map +1 -0
  44. package/dist/agents/cow-clone.d.ts +8 -0
  45. package/dist/agents/cow-clone.d.ts.map +1 -0
  46. package/dist/agents/handoff.d.ts +19 -0
  47. package/dist/agents/handoff.d.ts.map +1 -0
  48. package/dist/agents/manager.d.ts +68 -0
  49. package/dist/agents/manager.d.ts.map +1 -0
  50. package/dist/agents/omp-binary.d.ts +7 -0
  51. package/dist/agents/omp-binary.d.ts.map +1 -0
  52. package/dist/agents/rm.d.ts +15 -0
  53. package/dist/agents/rm.d.ts.map +1 -0
  54. package/dist/agents/semaphore.d.ts +7 -0
  55. package/dist/agents/semaphore.d.ts.map +1 -0
  56. package/dist/agents/session-export.d.ts +9 -0
  57. package/dist/agents/session-export.d.ts.map +1 -0
  58. package/dist/agents/thinking-transfer.d.ts +39 -0
  59. package/dist/agents/thinking-transfer.d.ts.map +1 -0
  60. package/dist/agents/transports/herdr-transport.d.ts +10 -0
  61. package/dist/agents/transports/herdr-transport.d.ts.map +1 -0
  62. package/dist/agents/transports/localterm-transport.d.ts +7 -0
  63. package/dist/agents/transports/localterm-transport.d.ts.map +1 -0
  64. package/dist/agents/transports/process-transport.d.ts +7 -0
  65. package/dist/agents/transports/process-transport.d.ts.map +1 -0
  66. package/dist/agents/transports/process-utils.d.ts +29 -0
  67. package/dist/agents/transports/process-utils.d.ts.map +1 -0
  68. package/dist/agents/transports/screen-transport.d.ts +7 -0
  69. package/dist/agents/transports/screen-transport.d.ts.map +1 -0
  70. package/dist/agents/transports/tmux-transport.d.ts +7 -0
  71. package/dist/agents/transports/tmux-transport.d.ts.map +1 -0
  72. package/dist/agents/types.d.ts +251 -0
  73. package/dist/agents/types.d.ts.map +1 -0
  74. package/dist/agents/veda-cli.d.ts +22 -0
  75. package/dist/agents/veda-cli.d.ts.map +1 -0
  76. package/dist/agents/veda-cli.js +13 -0
  77. package/dist/agents/veda-cli.js.map +7 -0
  78. package/dist/agents/worktree-manager.d.ts +14 -0
  79. package/dist/agents/worktree-manager.d.ts.map +1 -0
  80. package/dist/agents/worktree-paths.d.ts +5 -0
  81. package/dist/agents/worktree-paths.d.ts.map +1 -0
  82. package/dist/async-settlement.d.ts +4 -0
  83. package/dist/async-settlement.d.ts.map +1 -0
  84. package/dist/audit/details.d.ts +82 -0
  85. package/dist/audit/details.d.ts.map +1 -0
  86. package/dist/audit/index.d.ts +4 -0
  87. package/dist/audit/index.d.ts.map +1 -0
  88. package/dist/audit/projection.d.ts +20 -0
  89. package/dist/audit/projection.d.ts.map +1 -0
  90. package/dist/audit/trace.d.ts +95 -0
  91. package/dist/audit/trace.d.ts.map +1 -0
  92. package/dist/capture/catalog.d.ts +29 -0
  93. package/dist/capture/catalog.d.ts.map +1 -0
  94. package/dist/capture/interceptor.d.ts +21 -0
  95. package/dist/capture/interceptor.d.ts.map +1 -0
  96. package/dist/capture/wrapper.d.ts +15 -0
  97. package/dist/capture/wrapper.d.ts.map +1 -0
  98. package/dist/chunks/chunk-2GQC324T.js +5001 -0
  99. package/dist/chunks/chunk-2GQC324T.js.map +7 -0
  100. package/dist/chunks/chunk-2KEWFW56.js +1229 -0
  101. package/dist/chunks/chunk-2KEWFW56.js.map +7 -0
  102. package/dist/chunks/chunk-3J7BKUNG.js +354 -0
  103. package/dist/chunks/chunk-3J7BKUNG.js.map +7 -0
  104. package/dist/chunks/chunk-4A4MVZQW.js +253 -0
  105. package/dist/chunks/chunk-4A4MVZQW.js.map +7 -0
  106. package/dist/chunks/chunk-4HQDSTHN.js +221 -0
  107. package/dist/chunks/chunk-4HQDSTHN.js.map +7 -0
  108. package/dist/chunks/chunk-4LEDA76O.js +688 -0
  109. package/dist/chunks/chunk-4LEDA76O.js.map +7 -0
  110. package/dist/chunks/chunk-5GTPD4BA.js +1318 -0
  111. package/dist/chunks/chunk-5GTPD4BA.js.map +7 -0
  112. package/dist/chunks/chunk-5IWFSDU5.js +87 -0
  113. package/dist/chunks/chunk-5IWFSDU5.js.map +7 -0
  114. package/dist/chunks/chunk-6N4XGAZY.js +21 -0
  115. package/dist/chunks/chunk-6N4XGAZY.js.map +7 -0
  116. package/dist/chunks/chunk-6QBPSZJ5.js +647 -0
  117. package/dist/chunks/chunk-6QBPSZJ5.js.map +7 -0
  118. package/dist/chunks/chunk-6X6WUU2K.js +73 -0
  119. package/dist/chunks/chunk-6X6WUU2K.js.map +7 -0
  120. package/dist/chunks/chunk-7363CD5A.js +38 -0
  121. package/dist/chunks/chunk-7363CD5A.js.map +7 -0
  122. package/dist/chunks/chunk-77FQHHZD.js +231 -0
  123. package/dist/chunks/chunk-77FQHHZD.js.map +7 -0
  124. package/dist/chunks/chunk-7BIA5BJN.js +112 -0
  125. package/dist/chunks/chunk-7BIA5BJN.js.map +7 -0
  126. package/dist/chunks/chunk-7BOAOKWH.js +64 -0
  127. package/dist/chunks/chunk-7BOAOKWH.js.map +7 -0
  128. package/dist/chunks/chunk-7TB7NXSL.js +58 -0
  129. package/dist/chunks/chunk-7TB7NXSL.js.map +7 -0
  130. package/dist/chunks/chunk-7VIQNUPS.js +17 -0
  131. package/dist/chunks/chunk-7VIQNUPS.js.map +7 -0
  132. package/dist/chunks/chunk-CT2AJ2UI.js +225 -0
  133. package/dist/chunks/chunk-CT2AJ2UI.js.map +7 -0
  134. package/dist/chunks/chunk-DLXPTBPL.js +151 -0
  135. package/dist/chunks/chunk-DLXPTBPL.js.map +7 -0
  136. package/dist/chunks/chunk-ED3BRM6P.js +17 -0
  137. package/dist/chunks/chunk-ED3BRM6P.js.map +7 -0
  138. package/dist/chunks/chunk-G2IBGGBM.js +42 -0
  139. package/dist/chunks/chunk-G2IBGGBM.js.map +7 -0
  140. package/dist/chunks/chunk-GKOFZ76R.js +1596 -0
  141. package/dist/chunks/chunk-GKOFZ76R.js.map +7 -0
  142. package/dist/chunks/chunk-HDJBUXDX.js +1102 -0
  143. package/dist/chunks/chunk-HDJBUXDX.js.map +7 -0
  144. package/dist/chunks/chunk-IGVDD2HT.js +10 -0
  145. package/dist/chunks/chunk-IGVDD2HT.js.map +7 -0
  146. package/dist/chunks/chunk-JHKOG5GS.js +187 -0
  147. package/dist/chunks/chunk-JHKOG5GS.js.map +7 -0
  148. package/dist/chunks/chunk-JP4LIZFT.js +1334 -0
  149. package/dist/chunks/chunk-JP4LIZFT.js.map +7 -0
  150. package/dist/chunks/chunk-JSBTB3P6.js +127 -0
  151. package/dist/chunks/chunk-JSBTB3P6.js.map +7 -0
  152. package/dist/chunks/chunk-KAD7UWT2.js +99 -0
  153. package/dist/chunks/chunk-KAD7UWT2.js.map +7 -0
  154. package/dist/chunks/chunk-KIH3KLZU.js +95 -0
  155. package/dist/chunks/chunk-KIH3KLZU.js.map +7 -0
  156. package/dist/chunks/chunk-KIREBD2V.js +2208 -0
  157. package/dist/chunks/chunk-KIREBD2V.js.map +7 -0
  158. package/dist/chunks/chunk-LMAVZN7J.js +8 -0
  159. package/dist/chunks/chunk-LMAVZN7J.js.map +7 -0
  160. package/dist/chunks/chunk-NCPJZXLM.js +57 -0
  161. package/dist/chunks/chunk-NCPJZXLM.js.map +7 -0
  162. package/dist/chunks/chunk-OJZNMROB.js +195 -0
  163. package/dist/chunks/chunk-OJZNMROB.js.map +7 -0
  164. package/dist/chunks/chunk-OPTP4PSE.js +469 -0
  165. package/dist/chunks/chunk-OPTP4PSE.js.map +7 -0
  166. package/dist/chunks/chunk-QPXSCMTG.js +24 -0
  167. package/dist/chunks/chunk-QPXSCMTG.js.map +7 -0
  168. package/dist/chunks/chunk-ROKMBLGN.js +1265 -0
  169. package/dist/chunks/chunk-ROKMBLGN.js.map +7 -0
  170. package/dist/chunks/chunk-SXMWV447.js +2445 -0
  171. package/dist/chunks/chunk-SXMWV447.js.map +7 -0
  172. package/dist/chunks/chunk-T5ZA5YRU.js +786 -0
  173. package/dist/chunks/chunk-T5ZA5YRU.js.map +7 -0
  174. package/dist/chunks/chunk-T6OAX4FO.js +1835 -0
  175. package/dist/chunks/chunk-T6OAX4FO.js.map +7 -0
  176. package/dist/chunks/chunk-U5FYOMG5.js +119 -0
  177. package/dist/chunks/chunk-U5FYOMG5.js.map +7 -0
  178. package/dist/chunks/chunk-UOSJZXJV.js +142 -0
  179. package/dist/chunks/chunk-UOSJZXJV.js.map +7 -0
  180. package/dist/chunks/chunk-UPCARIJP.js +6627 -0
  181. package/dist/chunks/chunk-UPCARIJP.js.map +7 -0
  182. package/dist/chunks/chunk-VPPIJRNZ.js +50 -0
  183. package/dist/chunks/chunk-VPPIJRNZ.js.map +7 -0
  184. package/dist/chunks/chunk-XU5Z4JCQ.js +297 -0
  185. package/dist/chunks/chunk-XU5Z4JCQ.js.map +7 -0
  186. package/dist/chunks/chunk-YWEXP724.js +427 -0
  187. package/dist/chunks/chunk-YWEXP724.js.map +7 -0
  188. package/dist/chunks/chunk-YZZIKJX6.js +60 -0
  189. package/dist/chunks/chunk-YZZIKJX6.js.map +7 -0
  190. package/dist/chunks/chunk-ZNAJDPT7.js +2203 -0
  191. package/dist/chunks/chunk-ZNAJDPT7.js.map +7 -0
  192. package/dist/chunks/chunk-ZTM45GH5.js +163 -0
  193. package/dist/chunks/chunk-ZTM45GH5.js.map +7 -0
  194. package/dist/commands/fabric.d.ts +17 -0
  195. package/dist/commands/fabric.d.ts.map +1 -0
  196. package/dist/compaction/bounds.d.ts +23 -0
  197. package/dist/compaction/bounds.d.ts.map +1 -0
  198. package/dist/compaction/branch-details.d.ts +83 -0
  199. package/dist/compaction/branch-details.d.ts.map +1 -0
  200. package/dist/compaction/branch-summary.d.ts +9 -0
  201. package/dist/compaction/branch-summary.d.ts.map +1 -0
  202. package/dist/compaction/enrichers.d.ts +10 -0
  203. package/dist/compaction/enrichers.d.ts.map +1 -0
  204. package/dist/compaction/hook.d.ts +98 -0
  205. package/dist/compaction/hook.d.ts.map +1 -0
  206. package/dist/compaction/hook.js +19 -0
  207. package/dist/compaction/hook.js.map +7 -0
  208. package/dist/compaction/instructions.d.ts +38 -0
  209. package/dist/compaction/instructions.d.ts.map +1 -0
  210. package/dist/compaction/normalize.d.ts +83 -0
  211. package/dist/compaction/normalize.d.ts.map +1 -0
  212. package/dist/compaction/projections.d.ts +31 -0
  213. package/dist/compaction/projections.d.ts.map +1 -0
  214. package/dist/compaction/qa.d.ts +27 -0
  215. package/dist/compaction/qa.d.ts.map +1 -0
  216. package/dist/compaction/render.d.ts +10 -0
  217. package/dist/compaction/render.d.ts.map +1 -0
  218. package/dist/compaction/threshold.d.ts +5 -0
  219. package/dist/compaction/threshold.d.ts.map +1 -0
  220. package/dist/compaction/trace-events.d.ts +23 -0
  221. package/dist/compaction/trace-events.d.ts.map +1 -0
  222. package/dist/components/catalog.d.ts +25 -0
  223. package/dist/components/catalog.d.ts.map +1 -0
  224. package/dist/components/effect-scope.d.ts +31 -0
  225. package/dist/components/effect-scope.d.ts.map +1 -0
  226. package/dist/components/loader.d.ts +27 -0
  227. package/dist/components/loader.d.ts.map +1 -0
  228. package/dist/components/model-guidance.d.ts +48 -0
  229. package/dist/components/model-guidance.d.ts.map +1 -0
  230. package/dist/components/provider-component.d.ts +31 -0
  231. package/dist/components/provider-component.d.ts.map +1 -0
  232. package/dist/components/supervisor.d.ts +29 -0
  233. package/dist/components/supervisor.d.ts.map +1 -0
  234. package/dist/components/types.d.ts +140 -0
  235. package/dist/components/types.d.ts.map +1 -0
  236. package/dist/config-migrations.d.ts +11 -0
  237. package/dist/config-migrations.d.ts.map +1 -0
  238. package/dist/config.d.ts +269 -0
  239. package/dist/config.d.ts.map +1 -0
  240. package/dist/core/action-registry.d.ts +159 -0
  241. package/dist/core/action-registry.d.ts.map +1 -0
  242. package/dist/core/action-registry.js +17 -0
  243. package/dist/core/action-registry.js.map +7 -0
  244. package/dist/core/action-repair.d.ts +20 -0
  245. package/dist/core/action-repair.d.ts.map +1 -0
  246. package/dist/core/agent-dir.d.ts +2 -0
  247. package/dist/core/agent-dir.d.ts.map +1 -0
  248. package/dist/core/approval-controller.d.ts +30 -0
  249. package/dist/core/approval-controller.d.ts.map +1 -0
  250. package/dist/core/atomic-write.d.ts +15 -0
  251. package/dist/core/atomic-write.d.ts.map +1 -0
  252. package/dist/core/auto-approval-classifier.d.ts +13 -0
  253. package/dist/core/auto-approval-classifier.d.ts.map +1 -0
  254. package/dist/core/call-preview.d.ts +8 -0
  255. package/dist/core/call-preview.d.ts.map +1 -0
  256. package/dist/core/child-tool-allowlist.d.ts +3 -0
  257. package/dist/core/child-tool-allowlist.d.ts.map +1 -0
  258. package/dist/core/compact-controller.d.ts +42 -0
  259. package/dist/core/compact-controller.d.ts.map +1 -0
  260. package/dist/core/core-override-guidance.d.ts +7 -0
  261. package/dist/core/core-override-guidance.d.ts.map +1 -0
  262. package/dist/core/direct-tool-approval.d.ts +19 -0
  263. package/dist/core/direct-tool-approval.d.ts.map +1 -0
  264. package/dist/core/effect-conflict.d.ts +3 -0
  265. package/dist/core/effect-conflict.d.ts.map +1 -0
  266. package/dist/core/file-lock.d.ts +12 -0
  267. package/dist/core/file-lock.d.ts.map +1 -0
  268. package/dist/core/model-resolution.d.ts +62 -0
  269. package/dist/core/model-resolution.d.ts.map +1 -0
  270. package/dist/core/model-usage.d.ts +8 -0
  271. package/dist/core/model-usage.d.ts.map +1 -0
  272. package/dist/core/omp-bash-error.d.ts +11 -0
  273. package/dist/core/omp-bash-error.d.ts.map +1 -0
  274. package/dist/core/omp-tools.d.ts +9 -0
  275. package/dist/core/omp-tools.d.ts.map +1 -0
  276. package/dist/core/provider-bindings.d.ts +47 -0
  277. package/dist/core/provider-bindings.d.ts.map +1 -0
  278. package/dist/core/proxy-contract.d.ts +18 -0
  279. package/dist/core/proxy-contract.d.ts.map +1 -0
  280. package/dist/core/session-context.d.ts +6 -0
  281. package/dist/core/session-context.d.ts.map +1 -0
  282. package/dist/core/skill-block.d.ts +10 -0
  283. package/dist/core/skill-block.d.ts.map +1 -0
  284. package/dist/core/skill-dir.d.ts +4 -0
  285. package/dist/core/skill-dir.d.ts.map +1 -0
  286. package/dist/core/skill-prompt.d.ts +3 -0
  287. package/dist/core/skill-prompt.d.ts.map +1 -0
  288. package/dist/core/skill-references.d.ts +7 -0
  289. package/dist/core/skill-references.d.ts.map +1 -0
  290. package/dist/core/stable-hash.d.ts +3 -0
  291. package/dist/core/stable-hash.d.ts.map +1 -0
  292. package/dist/core/system-guidance.d.ts +12 -0
  293. package/dist/core/system-guidance.d.ts.map +1 -0
  294. package/dist/core/token-math.d.ts +16 -0
  295. package/dist/core/token-math.d.ts.map +1 -0
  296. package/dist/core/tool-ownership.d.ts +52 -0
  297. package/dist/core/tool-ownership.d.ts.map +1 -0
  298. package/dist/core/tool-result-proxy.d.ts +18 -0
  299. package/dist/core/tool-result-proxy.d.ts.map +1 -0
  300. package/dist/entropy/active.d.ts +7 -0
  301. package/dist/entropy/active.d.ts.map +1 -0
  302. package/dist/entropy/compiled-store.d.ts +16 -0
  303. package/dist/entropy/compiled-store.d.ts.map +1 -0
  304. package/dist/entropy/compiled-surface.d.ts +51 -0
  305. package/dist/entropy/compiled-surface.d.ts.map +1 -0
  306. package/dist/entropy/compiler.d.ts +28 -0
  307. package/dist/entropy/compiler.d.ts.map +1 -0
  308. package/dist/entropy/corpus.d.ts +22 -0
  309. package/dist/entropy/corpus.d.ts.map +1 -0
  310. package/dist/entropy/fingerprint.d.ts +9 -0
  311. package/dist/entropy/fingerprint.d.ts.map +1 -0
  312. package/dist/entropy/index.d.ts +15 -0
  313. package/dist/entropy/index.d.ts.map +1 -0
  314. package/dist/entropy/index.js +172 -0
  315. package/dist/entropy/index.js.map +7 -0
  316. package/dist/entropy/meter.d.ts +10 -0
  317. package/dist/entropy/meter.d.ts.map +1 -0
  318. package/dist/entropy/passes.d.ts +13 -0
  319. package/dist/entropy/passes.d.ts.map +1 -0
  320. package/dist/entropy/pool-store.d.ts +15 -0
  321. package/dist/entropy/pool-store.d.ts.map +1 -0
  322. package/dist/entropy/pool.d.ts +41 -0
  323. package/dist/entropy/pool.d.ts.map +1 -0
  324. package/dist/entropy/presentation.d.ts +13 -0
  325. package/dist/entropy/presentation.d.ts.map +1 -0
  326. package/dist/entropy/sessions.d.ts +47 -0
  327. package/dist/entropy/sessions.d.ts.map +1 -0
  328. package/dist/entropy/surface.d.ts +30 -0
  329. package/dist/entropy/surface.d.ts.map +1 -0
  330. package/dist/entropy/trial.d.ts +35 -0
  331. package/dist/entropy/trial.d.ts.map +1 -0
  332. package/dist/entropy/types.d.ts +158 -0
  333. package/dist/entropy/types.d.ts.map +1 -0
  334. package/dist/execution-service.d.ts +63 -0
  335. package/dist/execution-service.d.ts.map +1 -0
  336. package/dist/fabric-exec-arguments.d.ts +5 -0
  337. package/dist/fabric-exec-arguments.d.ts.map +1 -0
  338. package/dist/fabric-exec-tool.d.ts +8 -0
  339. package/dist/fabric-exec-tool.d.ts.map +1 -0
  340. package/dist/fabric-runtime-state.d.ts +90 -0
  341. package/dist/fabric-runtime-state.d.ts.map +1 -0
  342. package/dist/fabric-runtime-state.js +13060 -0
  343. package/dist/fabric-runtime-state.js.map +7 -0
  344. package/dist/fabric-state.d.ts +89 -0
  345. package/dist/fabric-state.d.ts.map +1 -0
  346. package/dist/failure-progress.d.ts +3 -0
  347. package/dist/failure-progress.d.ts.map +1 -0
  348. package/dist/host-compatibility.d.ts +5 -0
  349. package/dist/host-compatibility.d.ts.map +1 -0
  350. package/dist/index.d.ts +6 -0
  351. package/dist/index.d.ts.map +1 -0
  352. package/dist/index.js +5719 -0
  353. package/dist/index.js.map +7 -0
  354. package/dist/lifecycle/broker.d.ts +30 -0
  355. package/dist/lifecycle/broker.d.ts.map +1 -0
  356. package/dist/lifecycle/delivery-scheduler.d.ts +30 -0
  357. package/dist/lifecycle/delivery-scheduler.d.ts.map +1 -0
  358. package/dist/lifecycle/types.d.ts +91 -0
  359. package/dist/lifecycle/types.d.ts.map +1 -0
  360. package/dist/log-tail.d.ts +11 -0
  361. package/dist/log-tail.d.ts.map +1 -0
  362. package/dist/main-agent.d.ts +70 -0
  363. package/dist/main-agent.d.ts.map +1 -0
  364. package/dist/memory/context.d.ts +112 -0
  365. package/dist/memory/context.d.ts.map +1 -0
  366. package/dist/memory/digest.d.ts +48 -0
  367. package/dist/memory/digest.d.ts.map +1 -0
  368. package/dist/memory/digest.js +7 -0
  369. package/dist/memory/digest.js.map +7 -0
  370. package/dist/memory/discovery.d.ts +43 -0
  371. package/dist/memory/discovery.d.ts.map +1 -0
  372. package/dist/memory/discovery.js +23 -0
  373. package/dist/memory/discovery.js.map +7 -0
  374. package/dist/memory/index.d.ts +107 -0
  375. package/dist/memory/index.d.ts.map +1 -0
  376. package/dist/memory/lineage.d.ts +20 -0
  377. package/dist/memory/lineage.d.ts.map +1 -0
  378. package/dist/memory/normalize.d.ts +170 -0
  379. package/dist/memory/normalize.d.ts.map +1 -0
  380. package/dist/memory/normalize.js +22 -0
  381. package/dist/memory/normalize.js.map +7 -0
  382. package/dist/memory/regex.d.ts +19 -0
  383. package/dist/memory/regex.d.ts.map +1 -0
  384. package/dist/memory/search.d.ts +98 -0
  385. package/dist/memory/search.d.ts.map +1 -0
  386. package/dist/memory/search.js +22 -0
  387. package/dist/memory/search.js.map +7 -0
  388. package/dist/memory/tokenize.d.ts +24 -0
  389. package/dist/memory/tokenize.d.ts.map +1 -0
  390. package/dist/mesh/store.d.ts +78 -0
  391. package/dist/mesh/store.d.ts.map +1 -0
  392. package/dist/output-budget.d.ts +12 -0
  393. package/dist/output-budget.d.ts.map +1 -0
  394. package/dist/prewalk/arm.d.ts +8 -0
  395. package/dist/prewalk/arm.d.ts.map +1 -0
  396. package/dist/prewalk/controller.d.ts +60 -0
  397. package/dist/prewalk/controller.d.ts.map +1 -0
  398. package/dist/prewalk/fs-drift.d.ts +19 -0
  399. package/dist/prewalk/fs-drift.d.ts.map +1 -0
  400. package/dist/prewalk/handoff.d.ts +45 -0
  401. package/dist/prewalk/handoff.d.ts.map +1 -0
  402. package/dist/protocol.d.ts +273 -0
  403. package/dist/protocol.d.ts.map +1 -0
  404. package/dist/protocol.js +46 -0
  405. package/dist/protocol.js.map +7 -0
  406. package/dist/providers/agents-actions.d.ts +3 -0
  407. package/dist/providers/agents-actions.d.ts.map +1 -0
  408. package/dist/providers/agents-provider.d.ts +59 -0
  409. package/dist/providers/agents-provider.d.ts.map +1 -0
  410. package/dist/providers/arg-normalization.d.ts +15 -0
  411. package/dist/providers/arg-normalization.d.ts.map +1 -0
  412. package/dist/providers/captured-tools-provider.d.ts +23 -0
  413. package/dist/providers/captured-tools-provider.d.ts.map +1 -0
  414. package/dist/providers/compact-provider.d.ts +14 -0
  415. package/dist/providers/compact-provider.d.ts.map +1 -0
  416. package/dist/providers/components-provider.d.ts +12 -0
  417. package/dist/providers/components-provider.d.ts.map +1 -0
  418. package/dist/providers/mcp-descriptor-cache.d.ts +47 -0
  419. package/dist/providers/mcp-descriptor-cache.d.ts.map +1 -0
  420. package/dist/providers/mcp-provider.d.ts +27 -0
  421. package/dist/providers/mcp-provider.d.ts.map +1 -0
  422. package/dist/providers/memory-provider.d.ts +35 -0
  423. package/dist/providers/memory-provider.d.ts.map +1 -0
  424. package/dist/providers/memory-provider.js +16 -0
  425. package/dist/providers/memory-provider.js.map +7 -0
  426. package/dist/providers/mesh-provider.d.ts +17 -0
  427. package/dist/providers/mesh-provider.d.ts.map +1 -0
  428. package/dist/providers/omp-bash-cwd.d.ts +31 -0
  429. package/dist/providers/omp-bash-cwd.d.ts.map +1 -0
  430. package/dist/providers/omp-tools-provider.d.ts +15 -0
  431. package/dist/providers/omp-tools-provider.d.ts.map +1 -0
  432. package/dist/providers/schema-provider.d.ts +15 -0
  433. package/dist/providers/schema-provider.d.ts.map +1 -0
  434. package/dist/providers/state-provider.d.ts +16 -0
  435. package/dist/providers/state-provider.d.ts.map +1 -0
  436. package/dist/providers/write-diff-limits.d.ts +5 -0
  437. package/dist/providers/write-diff-limits.d.ts.map +1 -0
  438. package/dist/providers/write-preview.d.ts +3 -0
  439. package/dist/providers/write-preview.d.ts.map +1 -0
  440. package/dist/ref-names.d.ts +2 -0
  441. package/dist/ref-names.d.ts.map +1 -0
  442. package/dist/repairs/active.d.ts +7 -0
  443. package/dist/repairs/active.d.ts.map +1 -0
  444. package/dist/repairs/apply.d.ts +7 -0
  445. package/dist/repairs/apply.d.ts.map +1 -0
  446. package/dist/repairs/catalog-digest.d.ts +5 -0
  447. package/dist/repairs/catalog-digest.d.ts.map +1 -0
  448. package/dist/repairs/classify.d.ts +10 -0
  449. package/dist/repairs/classify.d.ts.map +1 -0
  450. package/dist/repairs/compiler.d.ts +33 -0
  451. package/dist/repairs/compiler.d.ts.map +1 -0
  452. package/dist/repairs/promote.d.ts +4 -0
  453. package/dist/repairs/promote.d.ts.map +1 -0
  454. package/dist/repairs/store.d.ts +10 -0
  455. package/dist/repairs/store.d.ts.map +1 -0
  456. package/dist/repairs/types.d.ts +49 -0
  457. package/dist/repairs/types.d.ts.map +1 -0
  458. package/dist/residency/actor-client.d.ts +16 -0
  459. package/dist/residency/actor-client.d.ts.map +1 -0
  460. package/dist/residency/actor-client.js +9 -0
  461. package/dist/residency/actor-client.js.map +7 -0
  462. package/dist/residency/client.d.ts +44 -0
  463. package/dist/residency/client.d.ts.map +1 -0
  464. package/dist/residency/host.d.ts +3 -0
  465. package/dist/residency/host.d.ts.map +1 -0
  466. package/dist/residency/host.js +25 -0
  467. package/dist/residency/host.js.map +7 -0
  468. package/dist/residency/launcher-owner.d.ts +7 -0
  469. package/dist/residency/launcher-owner.d.ts.map +1 -0
  470. package/dist/residency/launcher.d.ts +3 -0
  471. package/dist/residency/launcher.d.ts.map +1 -0
  472. package/dist/residency/launcher.js +152 -0
  473. package/dist/residency/launcher.js.map +7 -0
  474. package/dist/residency/omp-entry.d.ts +3 -0
  475. package/dist/residency/omp-entry.d.ts.map +1 -0
  476. package/dist/residency/omp-entry.js +41 -0
  477. package/dist/residency/omp-entry.js.map +7 -0
  478. package/dist/residency/protocol.d.ts +119 -0
  479. package/dist/residency/protocol.d.ts.map +1 -0
  480. package/dist/run-display.d.ts +3 -0
  481. package/dist/run-display.d.ts.map +1 -0
  482. package/dist/runtime/core-override-guest-types.d.ts +15 -0
  483. package/dist/runtime/core-override-guest-types.d.ts.map +1 -0
  484. package/dist/runtime/core-override-guest-types.js +291 -0
  485. package/dist/runtime/core-override-guest-types.js.map +7 -0
  486. package/dist/runtime/core-tool-properties.d.ts +6 -0
  487. package/dist/runtime/core-tool-properties.d.ts.map +1 -0
  488. package/dist/runtime/dynamic-guest-types.d.ts +3 -0
  489. package/dist/runtime/dynamic-guest-types.d.ts.map +1 -0
  490. package/dist/runtime/dynamic-guest-types.js +226 -0
  491. package/dist/runtime/dynamic-guest-types.js.map +7 -0
  492. package/dist/runtime/guest-code-repair.d.ts +2 -0
  493. package/dist/runtime/guest-code-repair.d.ts.map +1 -0
  494. package/dist/runtime/guest-stack-map.d.ts +11 -0
  495. package/dist/runtime/guest-stack-map.d.ts.map +1 -0
  496. package/dist/runtime/guest-types.d.ts +35 -0
  497. package/dist/runtime/guest-types.d.ts.map +1 -0
  498. package/dist/runtime/guest-types.js +13 -0
  499. package/dist/runtime/guest-types.js.map +7 -0
  500. package/dist/runtime/node-process-child-source.d.ts +2 -0
  501. package/dist/runtime/node-process-child-source.d.ts.map +1 -0
  502. package/dist/runtime/node-process-runtime.d.ts +10 -0
  503. package/dist/runtime/node-process-runtime.d.ts.map +1 -0
  504. package/dist/runtime/node-process-runtime.js +319 -0
  505. package/dist/runtime/node-process-runtime.js.map +7 -0
  506. package/dist/runtime/orchestration.d.ts +3 -0
  507. package/dist/runtime/orchestration.d.ts.map +1 -0
  508. package/dist/runtime/quickjs-runtime.d.ts +24 -0
  509. package/dist/runtime/quickjs-runtime.d.ts.map +1 -0
  510. package/dist/runtime/quickjs-runtime.js +12 -0
  511. package/dist/runtime/quickjs-runtime.js.map +7 -0
  512. package/dist/runtime/type-checker.d.ts +21 -0
  513. package/dist/runtime/type-checker.d.ts.map +1 -0
  514. package/dist/runtime/type-checker.js +15 -0
  515. package/dist/runtime/type-checker.js.map +7 -0
  516. package/dist/runtime-paths.d.ts +7 -0
  517. package/dist/runtime-paths.d.ts.map +1 -0
  518. package/dist/schema/controller.d.ts +35 -0
  519. package/dist/schema/controller.d.ts.map +1 -0
  520. package/dist/schema/types.d.ts +86 -0
  521. package/dist/schema/types.d.ts.map +1 -0
  522. package/dist/schema/workspace.d.ts +19 -0
  523. package/dist/schema/workspace.d.ts.map +1 -0
  524. package/dist/speculation/eligibility.d.ts +22 -0
  525. package/dist/speculation/eligibility.d.ts.map +1 -0
  526. package/dist/speculation/freshness.d.ts +10 -0
  527. package/dist/speculation/freshness.d.ts.map +1 -0
  528. package/dist/speculation/partial-json.d.ts +9 -0
  529. package/dist/speculation/partial-json.d.ts.map +1 -0
  530. package/dist/speculation/scanner.d.ts +13 -0
  531. package/dist/speculation/scanner.d.ts.map +1 -0
  532. package/dist/speculation/scanner.js +182 -0
  533. package/dist/speculation/scanner.js.map +7 -0
  534. package/dist/speculation/store.d.ts +39 -0
  535. package/dist/speculation/store.d.ts.map +1 -0
  536. package/dist/speculation/stream-tap.d.ts +27 -0
  537. package/dist/speculation/stream-tap.d.ts.map +1 -0
  538. package/dist/speculation/types.d.ts +44 -0
  539. package/dist/speculation/types.d.ts.map +1 -0
  540. package/dist/state/complexity.d.ts +13 -0
  541. package/dist/state/complexity.d.ts.map +1 -0
  542. package/dist/state/evidence-runner.d.ts +17 -0
  543. package/dist/state/evidence-runner.d.ts.map +1 -0
  544. package/dist/state/store.d.ts +76 -0
  545. package/dist/state/store.d.ts.map +1 -0
  546. package/dist/state/types.d.ts +165 -0
  547. package/dist/state/types.d.ts.map +1 -0
  548. package/dist/storage/retention.d.ts +22 -0
  549. package/dist/storage/retention.d.ts.map +1 -0
  550. package/dist/thinking.d.ts +19 -0
  551. package/dist/thinking.d.ts.map +1 -0
  552. package/dist/topology/control-plane.d.ts +58 -0
  553. package/dist/topology/control-plane.d.ts.map +1 -0
  554. package/dist/topology/participant-directory.d.ts +33 -0
  555. package/dist/topology/participant-directory.d.ts.map +1 -0
  556. package/dist/topology/peer-settle.d.ts +51 -0
  557. package/dist/topology/peer-settle.d.ts.map +1 -0
  558. package/dist/topology/records.d.ts +6 -0
  559. package/dist/topology/records.d.ts.map +1 -0
  560. package/dist/topology/types.d.ts +89 -0
  561. package/dist/topology/types.d.ts.map +1 -0
  562. package/dist/type-error-guidance.d.ts +3 -0
  563. package/dist/type-error-guidance.d.ts.map +1 -0
  564. package/dist/ui/arc-group.d.ts +17 -0
  565. package/dist/ui/arc-group.d.ts.map +1 -0
  566. package/dist/ui/code-preview-shell.d.ts +26 -0
  567. package/dist/ui/code-preview-shell.d.ts.map +1 -0
  568. package/dist/ui/code-preview.d.ts +53 -0
  569. package/dist/ui/code-preview.d.ts.map +1 -0
  570. package/dist/ui/controller.d.ts +20 -0
  571. package/dist/ui/controller.d.ts.map +1 -0
  572. package/dist/ui/conversation-chrome.d.ts +15 -0
  573. package/dist/ui/conversation-chrome.d.ts.map +1 -0
  574. package/dist/ui/conversation-chrome.js +10 -0
  575. package/dist/ui/conversation-chrome.js.map +7 -0
  576. package/dist/ui/conversation-native-reader.d.ts +106 -0
  577. package/dist/ui/conversation-native-reader.d.ts.map +1 -0
  578. package/dist/ui/conversation-native-reader.js +784 -0
  579. package/dist/ui/conversation-native-reader.js.map +7 -0
  580. package/dist/ui/conversation-queue-store.d.ts +12 -0
  581. package/dist/ui/conversation-queue-store.d.ts.map +1 -0
  582. package/dist/ui/conversation-queue.d.ts +242 -0
  583. package/dist/ui/conversation-queue.d.ts.map +1 -0
  584. package/dist/ui/conversation-render.d.ts +45 -0
  585. package/dist/ui/conversation-render.d.ts.map +1 -0
  586. package/dist/ui/conversation-shortcut.d.ts +3 -0
  587. package/dist/ui/conversation-shortcut.d.ts.map +1 -0
  588. package/dist/ui/conversation-targets.d.ts +7 -0
  589. package/dist/ui/conversation-targets.d.ts.map +1 -0
  590. package/dist/ui/conversation-targets.js +12 -0
  591. package/dist/ui/conversation-targets.js.map +7 -0
  592. package/dist/ui/conversation-transcript.d.ts +25 -0
  593. package/dist/ui/conversation-transcript.d.ts.map +1 -0
  594. package/dist/ui/conversation.d.ts +170 -0
  595. package/dist/ui/conversation.d.ts.map +1 -0
  596. package/dist/ui/conversation.js +1868 -0
  597. package/dist/ui/conversation.js.map +7 -0
  598. package/dist/ui/core-tool-render.d.ts +20 -0
  599. package/dist/ui/core-tool-render.d.ts.map +1 -0
  600. package/dist/ui/dashboard-detail.d.ts +68 -0
  601. package/dist/ui/dashboard-detail.d.ts.map +1 -0
  602. package/dist/ui/dashboard-fabric-graph.d.ts +50 -0
  603. package/dist/ui/dashboard-fabric-graph.d.ts.map +1 -0
  604. package/dist/ui/dashboard-model.d.ts +111 -0
  605. package/dist/ui/dashboard-model.d.ts.map +1 -0
  606. package/dist/ui/dashboard-presentation.d.ts +6 -0
  607. package/dist/ui/dashboard-presentation.d.ts.map +1 -0
  608. package/dist/ui/dashboard.d.ts +188 -0
  609. package/dist/ui/dashboard.d.ts.map +1 -0
  610. package/dist/ui/dashboard.js +4604 -0
  611. package/dist/ui/dashboard.js.map +7 -0
  612. package/dist/ui/diff-background.d.ts +12 -0
  613. package/dist/ui/diff-background.d.ts.map +1 -0
  614. package/dist/ui/dynamic-border.d.ts +8 -0
  615. package/dist/ui/dynamic-border.d.ts.map +1 -0
  616. package/dist/ui/escape-halt.d.ts +11 -0
  617. package/dist/ui/escape-halt.d.ts.map +1 -0
  618. package/dist/ui/fabric-actor-delivery-selector.d.ts +17 -0
  619. package/dist/ui/fabric-actor-delivery-selector.d.ts.map +1 -0
  620. package/dist/ui/fabric-actor-tool-selector.d.ts +22 -0
  621. package/dist/ui/fabric-actor-tool-selector.d.ts.map +1 -0
  622. package/dist/ui/fabric-code-parser.d.ts +8 -0
  623. package/dist/ui/fabric-code-parser.d.ts.map +1 -0
  624. package/dist/ui/fabric-host-event-selector.d.ts +29 -0
  625. package/dist/ui/fabric-host-event-selector.d.ts.map +1 -0
  626. package/dist/ui/fabric-model-selector.d.ts +64 -0
  627. package/dist/ui/fabric-model-selector.d.ts.map +1 -0
  628. package/dist/ui/fabric-render.d.ts +113 -0
  629. package/dist/ui/fabric-render.d.ts.map +1 -0
  630. package/dist/ui/fabric-thinking-selector.d.ts +26 -0
  631. package/dist/ui/fabric-thinking-selector.d.ts.map +1 -0
  632. package/dist/ui/fabric-title-hint.d.ts +2 -0
  633. package/dist/ui/fabric-title-hint.d.ts.map +1 -0
  634. package/dist/ui/format.d.ts +9 -0
  635. package/dist/ui/format.d.ts.map +1 -0
  636. package/dist/ui/highlight.d.ts +69 -0
  637. package/dist/ui/highlight.d.ts.map +1 -0
  638. package/dist/ui/model-picker.d.ts +46 -0
  639. package/dist/ui/model-picker.d.ts.map +1 -0
  640. package/dist/ui/model-picker.js +17 -0
  641. package/dist/ui/model-picker.js.map +7 -0
  642. package/dist/ui/preview-lines.d.ts +16 -0
  643. package/dist/ui/preview-lines.d.ts.map +1 -0
  644. package/dist/ui/row-balance.d.ts +29 -0
  645. package/dist/ui/row-balance.d.ts.map +1 -0
  646. package/dist/ui/settings.d.ts +57 -0
  647. package/dist/ui/settings.d.ts.map +1 -0
  648. package/dist/ui/settings.js +1908 -0
  649. package/dist/ui/settings.js.map +7 -0
  650. package/dist/ui/shiki-language.d.ts +7 -0
  651. package/dist/ui/shiki-language.d.ts.map +1 -0
  652. package/dist/ui/shiki-theme.d.ts +7 -0
  653. package/dist/ui/shiki-theme.d.ts.map +1 -0
  654. package/dist/ui/snapshot.d.ts +7 -0
  655. package/dist/ui/snapshot.d.ts.map +1 -0
  656. package/dist/ui/spinner.d.ts +6 -0
  657. package/dist/ui/spinner.d.ts.map +1 -0
  658. package/dist/ui/state-file-preview.d.ts +13 -0
  659. package/dist/ui/state-file-preview.d.ts.map +1 -0
  660. package/dist/ui/structured.d.ts +9 -0
  661. package/dist/ui/structured.d.ts.map +1 -0
  662. package/dist/ui/symbol-theme.d.ts +3 -0
  663. package/dist/ui/symbol-theme.d.ts.map +1 -0
  664. package/dist/ui/tool-call-timing.d.ts +2 -0
  665. package/dist/ui/tool-call-timing.d.ts.map +1 -0
  666. package/dist/ui/tool-display.d.ts +8 -0
  667. package/dist/ui/tool-display.d.ts.map +1 -0
  668. package/dist/ui/topology.d.ts +162 -0
  669. package/dist/ui/topology.d.ts.map +1 -0
  670. package/dist/ui/transcript-parser.d.ts +18 -0
  671. package/dist/ui/transcript-parser.d.ts.map +1 -0
  672. package/dist/ui/transcript-reader.d.ts +10 -0
  673. package/dist/ui/transcript-reader.d.ts.map +1 -0
  674. package/dist/ui/transcript-sanitization.d.ts +14 -0
  675. package/dist/ui/transcript-sanitization.d.ts.map +1 -0
  676. package/dist/ui/transcript.d.ts +52 -0
  677. package/dist/ui/transcript.d.ts.map +1 -0
  678. package/dist/ui/types.d.ts +84 -0
  679. package/dist/ui/types.d.ts.map +1 -0
  680. package/dist/ui/widget.d.ts +16 -0
  681. package/dist/ui/widget.d.ts.map +1 -0
  682. package/dist/ui/word-diff/alignment.d.ts +6 -0
  683. package/dist/ui/word-diff/alignment.d.ts.map +1 -0
  684. package/dist/ui/word-diff/change-block.d.ts +18 -0
  685. package/dist/ui/word-diff/change-block.d.ts.map +1 -0
  686. package/dist/ui/word-diff/changed-line.d.ts +14 -0
  687. package/dist/ui/word-diff/changed-line.d.ts.map +1 -0
  688. package/dist/ui/word-diff/emphasis.d.ts +9 -0
  689. package/dist/ui/word-diff/emphasis.d.ts.map +1 -0
  690. package/dist/ui/word-diff/line-emphasis.d.ts +7 -0
  691. package/dist/ui/word-diff/line-emphasis.d.ts.map +1 -0
  692. package/dist/ui/word-diff/line-matching.d.ts +10 -0
  693. package/dist/ui/word-diff/line-matching.d.ts.map +1 -0
  694. package/dist/ui/word-diff/line-similarity.d.ts +16 -0
  695. package/dist/ui/word-diff/line-similarity.d.ts.map +1 -0
  696. package/dist/ui/word-diff/normalize.d.ts +3 -0
  697. package/dist/ui/word-diff/normalize.d.ts.map +1 -0
  698. package/dist/ui/word-diff/parse.d.ts +17 -0
  699. package/dist/ui/word-diff/parse.d.ts.map +1 -0
  700. package/dist/ui/word-diff/range-refinement.d.ts +5 -0
  701. package/dist/ui/word-diff/range-refinement.d.ts.map +1 -0
  702. package/dist/ui/word-diff/ranges.d.ts +11 -0
  703. package/dist/ui/word-diff/ranges.d.ts.map +1 -0
  704. package/dist/ui/word-diff/smart-filter.d.ts +3 -0
  705. package/dist/ui/word-diff/smart-filter.d.ts.map +1 -0
  706. package/dist/ui/word-diff/sparse-line-matching.d.ts +25 -0
  707. package/dist/ui/word-diff/sparse-line-matching.d.ts.map +1 -0
  708. package/dist/ui/word-diff/text-boundaries.d.ts +11 -0
  709. package/dist/ui/word-diff/text-boundaries.d.ts.map +1 -0
  710. package/dist/ui/word-diff/token-alignment.d.ts +9 -0
  711. package/dist/ui/word-diff/token-alignment.d.ts.map +1 -0
  712. package/dist/ui/word-diff/token-text-refinement.d.ts +4 -0
  713. package/dist/ui/word-diff/token-text-refinement.d.ts.map +1 -0
  714. package/dist/ui/word-diff/tokens.d.ts +16 -0
  715. package/dist/ui/word-diff/tokens.d.ts.map +1 -0
  716. package/dist/ui/word-diff/types.d.ts +10 -0
  717. package/dist/ui/word-diff/types.d.ts.map +1 -0
  718. package/dist/util.d.ts +3 -0
  719. package/dist/util.d.ts.map +1 -0
  720. package/dist/worker/options.d.ts +3 -0
  721. package/dist/worker/options.d.ts.map +1 -0
  722. package/dist/worker/options.js +104 -0
  723. package/dist/worker/options.js.map +7 -0
  724. package/dist/worker/run-record.d.ts +22 -0
  725. package/dist/worker/run-record.d.ts.map +1 -0
  726. package/dist/worker/run-record.js +123 -0
  727. package/dist/worker/run-record.js.map +7 -0
  728. package/dist/worker/session-export.d.ts +45 -0
  729. package/dist/worker/session-export.d.ts.map +1 -0
  730. package/dist/worker/session-export.js +91 -0
  731. package/dist/worker/session-export.js.map +7 -0
  732. package/dist/worker.d.ts +3 -0
  733. package/dist/worker.d.ts.map +1 -0
  734. package/dist/worker.js +1061 -0
  735. package/dist/worker.js.map +7 -0
  736. package/docs/agents.md +564 -0
  737. package/docs/architecture.md +139 -0
  738. package/docs/audit-trace.md +116 -0
  739. package/docs/certification.md +134 -0
  740. package/docs/compaction.md +332 -0
  741. package/docs/component-calculus.md +191 -0
  742. package/docs/components.md +329 -0
  743. package/docs/configuration.md +478 -0
  744. package/docs/entropy.md +396 -0
  745. package/docs/interface.md +149 -0
  746. package/docs/memory-recall.md +614 -0
  747. package/docs/programmatic-compaction.md +207 -0
  748. package/docs/provider-component-calculus.md +378 -0
  749. package/docs/providers.md +109 -0
  750. package/docs/repairs.md +69 -0
  751. package/docs/residency-runtime.md +82 -0
  752. package/docs/schema-enforcement.md +166 -0
  753. package/docs/skills.md +48 -0
  754. package/docs/speculation.md +132 -0
  755. package/docs/state-layer.md +197 -0
  756. package/package.json +116 -0
  757. package/skills/fabric-advisor/SKILL.md +29 -0
  758. package/skills/fabric-ambient/SKILL.md +44 -0
  759. package/skills/fabric-ambient/references/setup.md +90 -0
  760. package/skills/fabric-council/SKILL.md +94 -0
  761. package/skills/fabric-exec/SKILL.md +123 -0
  762. package/skills/fabric-exec/references/agents.md +211 -0
  763. package/skills/fabric-exec/references/mcp.md +49 -0
  764. package/skills/fabric-exec/references/mesh.md +51 -0
  765. package/skills/fabric-fusion/SKILL.md +332 -0
  766. package/skills/fabric-guide/SKILL.md +28 -0
  767. package/skills/fabric-rlm/SKILL.md +284 -0
  768. package/skills/fabric-schema/SKILL.md +121 -0
  769. package/skills/fabric-spec/SKILL.md +42 -0
  770. package/skills/fabric-supervisor/SKILL.md +37 -0
  771. package/skills/fabric-swarm/SKILL.md +80 -0
  772. package/skills/fabric-workflow/SKILL.md +133 -0
@@ -0,0 +1,4604 @@
1
+ import {
2
+ FabricModelSelector
3
+ } from "../chunks/chunk-OJZNMROB.js";
4
+ import {
5
+ ompSymbolTheme
6
+ } from "../chunks/chunk-G2IBGGBM.js";
7
+ import {
8
+ INHERIT_VALUE
9
+ } from "../chunks/chunk-7BOAOKWH.js";
10
+ import {
11
+ coreToolTitle,
12
+ formatJsonAsYaml,
13
+ highlightCode,
14
+ highlightFileLines,
15
+ languageFromPath,
16
+ nestedEditDiff,
17
+ renderBoundedLines,
18
+ renderCoreToolBody,
19
+ spinnerFrame
20
+ } from "../chunks/chunk-2GQC324T.js";
21
+ import {
22
+ isActiveStatus,
23
+ orderAgentsByCreation
24
+ } from "../chunks/chunk-QPXSCMTG.js";
25
+ import {
26
+ formatActorDataPreview,
27
+ formatClock,
28
+ formatDuration,
29
+ formatTokens,
30
+ padToWidth,
31
+ safeText,
32
+ wrapPlainText
33
+ } from "../chunks/chunk-KIH3KLZU.js";
34
+ import "../chunks/chunk-HDJBUXDX.js";
35
+ import "../chunks/chunk-DLXPTBPL.js";
36
+ import {
37
+ formatFabricEffectConflict
38
+ } from "../chunks/chunk-LMAVZN7J.js";
39
+ import {
40
+ FABRIC_ACTOR_HOST_EVENTS
41
+ } from "../chunks/chunk-UOSJZXJV.js";
42
+ import {
43
+ THINKING_LEVELS,
44
+ isFabricThinking,
45
+ thinkingLabel
46
+ } from "../chunks/chunk-JSBTB3P6.js";
47
+ import "../chunks/chunk-3J7BKUNG.js";
48
+
49
+ // src/ui/dashboard.ts
50
+ import "@oh-my-pi/pi-tui";
51
+ import {
52
+ Editor,
53
+ getKeybindings as getKeybindings3,
54
+ Key,
55
+ matchesKey,
56
+ truncateToWidth as truncateToWidth4,
57
+ visibleWidth as visibleWidth4
58
+ } from "@oh-my-pi/pi-tui";
59
+
60
+ // src/ui/topology.ts
61
+ import { createHash } from "node:crypto";
62
+ var UNPHASED = Symbol("fabric-run-topology-unphased");
63
+ var SYSTEM_TOPICS = /* @__PURE__ */ new Set([
64
+ "fabric.actor.input",
65
+ "fabric.actor.output",
66
+ "fabric.actor.lifecycle",
67
+ "fabric.compact",
68
+ "fabric.participant.lifecycle",
69
+ "fabric.steer",
70
+ "fabric.control.command",
71
+ "fabric.control.ack"
72
+ ]);
73
+ var IGNORED_ROUTE_TOPICS = /* @__PURE__ */ new Set([
74
+ "fabric.actor.lifecycle",
75
+ "fabric.compact",
76
+ "fabric.control.ack"
77
+ ]);
78
+ var eventData = (event) => typeof event.data === "object" && event.data !== null && !Array.isArray(event.data) ? event.data : void 0;
79
+ var failureEventKinds = /* @__PURE__ */ new Set([
80
+ "error",
81
+ "failed",
82
+ "failure",
83
+ "blocked",
84
+ "reject",
85
+ "rejected"
86
+ ]);
87
+ var routeStatus = (kind) => kind.toLowerCase().split(/[.:/_-]+/).some((part) => failureEventKinds.has(part)) ? "failed" : "completed";
88
+ var projectMeshRoutes = (main, actors, agents, events) => {
89
+ const actorByKey = /* @__PURE__ */ new Map();
90
+ for (const actor of actors) {
91
+ actorByKey.set(actor.id, actor);
92
+ actorByKey.set(actor.name, actor);
93
+ }
94
+ const agentByKey = /* @__PURE__ */ new Map();
95
+ for (const agent of agents) {
96
+ agentByKey.set(agent.id, agent);
97
+ agentByKey.set(agent.name, agent);
98
+ }
99
+ const mainByKey = /* @__PURE__ */ new Map([
100
+ [main.id, main.name],
101
+ [main.name, main.name],
102
+ ["main", main.name]
103
+ ]);
104
+ for (const event of events) {
105
+ if (event.from.kind !== "main") continue;
106
+ mainByKey.set(event.from.id, event.from.name);
107
+ mainByKey.set(event.from.name, event.from.name);
108
+ }
109
+ const routes = /* @__PURE__ */ new Map();
110
+ for (const event of events) {
111
+ if (IGNORED_ROUTE_TOPICS.has(event.topic)) continue;
112
+ const data = eventData(event);
113
+ let targetId;
114
+ let targetName;
115
+ let targetKind;
116
+ const actorInputId = event.topic === "fabric.actor.input" && typeof data?.actorId === "string" ? data.actorId : void 0;
117
+ const controlTarget = event.topic === "fabric.control.command" && typeof data?.targetId === "string" ? data.targetId : void 0;
118
+ const addressed = controlTarget ?? event.to ?? actorInputId;
119
+ const targetMain = addressed ? mainByKey.get(addressed) : void 0;
120
+ const targetActor = addressed ? actorByKey.get(addressed) : void 0;
121
+ const targetAgent = addressed ? agentByKey.get(addressed) : void 0;
122
+ if (targetMain) {
123
+ targetId = addressed;
124
+ targetName = targetMain;
125
+ targetKind = "main";
126
+ } else if (targetActor) {
127
+ targetId = targetActor.id;
128
+ targetName = targetActor.name;
129
+ targetKind = "actor";
130
+ } else if (targetAgent) {
131
+ targetId = targetAgent.id;
132
+ targetName = targetAgent.name;
133
+ targetKind = "agent";
134
+ } else if (addressed) {
135
+ targetId = addressed;
136
+ targetName = addressed;
137
+ targetKind = "agent";
138
+ } else if (event.topic === "fabric.actor.output") {
139
+ targetId = main.id;
140
+ targetName = main.name;
141
+ targetKind = "main";
142
+ } else {
143
+ targetId = event.topic;
144
+ targetName = event.topic;
145
+ targetKind = "topic";
146
+ }
147
+ const key = JSON.stringify([
148
+ event.from.id,
149
+ event.from.kind,
150
+ targetKind,
151
+ targetId,
152
+ event.topic,
153
+ event.kind
154
+ ]);
155
+ const existing = routes.get(key);
156
+ if (existing) {
157
+ existing.count++;
158
+ if (event.createdAt >= existing.lastAt) {
159
+ existing.lastAt = event.createdAt;
160
+ if (event.text) existing.text = event.text;
161
+ else delete existing.text;
162
+ }
163
+ if (routeStatus(event.kind) === "failed") existing.status = "failed";
164
+ continue;
165
+ }
166
+ routes.set(key, {
167
+ id: `route:${createHash("sha256").update(key).digest("hex").slice(0, 20)}`,
168
+ fromId: event.from.id,
169
+ fromName: event.from.name,
170
+ fromKind: event.from.kind,
171
+ targetId,
172
+ targetName,
173
+ targetKind,
174
+ topic: event.topic,
175
+ kind: event.kind,
176
+ status: routeStatus(event.kind),
177
+ count: 1,
178
+ lastAt: event.createdAt,
179
+ ...event.text ? { text: event.text } : {}
180
+ });
181
+ }
182
+ return [...routes.values()].sort((left, right) => right.lastAt - left.lastAt);
183
+ };
184
+ var projectMeshParticipants = (agents, routes, directoryParticipants) => {
185
+ const agentByKey = /* @__PURE__ */ new Map();
186
+ for (const agent of agents) {
187
+ agentByKey.set(agent.id, agent);
188
+ agentByKey.set(agent.name, agent);
189
+ }
190
+ const observed = /* @__PURE__ */ new Map();
191
+ const touch = (id, name, lastSeenAt, participant) => {
192
+ const existing = observed.get(id);
193
+ if (!existing) {
194
+ observed.set(id, {
195
+ id,
196
+ name,
197
+ lastSeenAt,
198
+ ...participant ? { participant } : {}
199
+ });
200
+ return;
201
+ }
202
+ if (lastSeenAt >= existing.lastSeenAt) {
203
+ existing.name = name;
204
+ existing.lastSeenAt = lastSeenAt;
205
+ }
206
+ if (participant) existing.participant = participant;
207
+ };
208
+ for (const participant of directoryParticipants) {
209
+ const name = participant.kind === "root" && participant.sessionId ? `Peer ${participant.sessionId.slice(0, 8)}` : participant.name;
210
+ touch(participant.id, name, participant.updatedAt, participant);
211
+ }
212
+ for (const route of routes) {
213
+ if (route.fromKind === "agent") touch(route.fromId, route.fromName, route.lastAt);
214
+ if (route.targetKind === "agent") touch(route.targetId, route.targetName, route.lastAt);
215
+ }
216
+ return [...observed.values()].map((identity) => {
217
+ const agent = agentByKey.get(identity.id) ?? agentByKey.get(identity.name);
218
+ const routesForParticipant = routes.reduce(
219
+ (count, route) => count + (route.fromKind === "agent" && route.fromId === identity.id || route.targetKind === "agent" && route.targetId === identity.id ? route.count : 0),
220
+ 0
221
+ );
222
+ return {
223
+ id: identity.id,
224
+ entityId: agent ? `agent:${agent.id}` : `participant:${identity.id}`,
225
+ name: agent?.name ?? identity.name,
226
+ status: agent?.status ?? "idle",
227
+ routes: routesForParticipant,
228
+ lastSeenAt: identity.lastSeenAt,
229
+ ...agent ? { agent } : {},
230
+ ...identity.participant ? { participant: identity.participant } : {}
231
+ };
232
+ }).sort(
233
+ (left, right) => Number(isActiveStatus(right.status)) - Number(isActiveStatus(left.status)) || left.name.localeCompare(right.name)
234
+ );
235
+ };
236
+ var projectParticipantTree = (participants) => {
237
+ const byId = new Map(participants.map((participant) => [participant.id, participant]));
238
+ const children = /* @__PURE__ */ new Map();
239
+ const roots = [];
240
+ for (const participant of participants) {
241
+ const parentId = participant.participant?.parentId ?? participant.agent?.parentId;
242
+ if (!parentId || !byId.has(parentId) || parentId === participant.id) {
243
+ roots.push(participant);
244
+ continue;
245
+ }
246
+ const entries = children.get(parentId) ?? [];
247
+ entries.push(participant);
248
+ children.set(parentId, entries);
249
+ }
250
+ const rows = [];
251
+ const visited = /* @__PURE__ */ new Set();
252
+ const visit = (participant, ancestorLast, isLast) => {
253
+ if (visited.has(participant.id)) return;
254
+ visited.add(participant.id);
255
+ rows.push({ participant, ancestorLast, isLast });
256
+ const descendants = (children.get(participant.id) ?? []).filter(
257
+ (candidate) => !visited.has(candidate.id)
258
+ );
259
+ for (let index = 0; index < descendants.length; index++) {
260
+ const descendant = descendants[index];
261
+ if (descendant) {
262
+ visit(descendant, [...ancestorLast, isLast], index === descendants.length - 1);
263
+ }
264
+ }
265
+ };
266
+ for (let index = 0; index < roots.length; index++) {
267
+ const root = roots[index];
268
+ if (root) visit(root, [], index === roots.length - 1);
269
+ }
270
+ for (const participant of participants) {
271
+ if (!visited.has(participant.id)) visit(participant, [], true);
272
+ }
273
+ return rows;
274
+ };
275
+ var projectMeshTopics = (actors, events, now) => {
276
+ const names = /* @__PURE__ */ new Set();
277
+ for (const actor of actors) {
278
+ for (const topic of actor.topics) names.add(topic);
279
+ }
280
+ for (const event of events) {
281
+ if (!SYSTEM_TOPICS.has(event.topic)) names.add(event.topic);
282
+ }
283
+ return [...names].sort((left, right) => left.localeCompare(right)).map((name) => {
284
+ const topicEvents = events.filter((event) => event.topic === name);
285
+ const lastEventAt = topicEvents.reduce(
286
+ (latest, event) => Math.max(latest, event.createdAt),
287
+ 0
288
+ );
289
+ const subscribers = actors.filter((actor) => actor.topics.includes(name)).map((actor) => ({ id: actor.id, name: actor.name, status: actor.status }));
290
+ return {
291
+ id: `topic:${name}`,
292
+ name,
293
+ status: lastEventAt > 0 && now - lastEventAt <= 1e4 ? "running" : "idle",
294
+ system: SYSTEM_TOPICS.has(name),
295
+ subscribers,
296
+ recentEvents: topicEvents.length,
297
+ ...lastEventAt > 0 ? { lastEventAt } : {}
298
+ };
299
+ });
300
+ };
301
+ var buildProjectMeshTopology = (input) => {
302
+ const topics = projectMeshTopics(input.actors, input.events, input.now);
303
+ const routes = projectMeshRoutes(input.main, input.actors, input.agents, input.events);
304
+ const localActorIds = new Set(input.actors.map((actor) => actor.id));
305
+ const directoryParticipants = (input.participants ?? []).filter(
306
+ (participant) => participant.id !== input.main.id && !(participant.kind === "actor" && localActorIds.has(participant.id))
307
+ );
308
+ const participants = projectMeshParticipants(input.agents, routes, directoryParticipants);
309
+ const rows = [
310
+ {
311
+ kind: "meshRoot",
312
+ entityId: `main:${input.main.id}`,
313
+ main: input.main,
314
+ actors: input.actors.length,
315
+ agents: participants.length,
316
+ topics: topics.length,
317
+ state: input.state.length,
318
+ routes: routes.length
319
+ }
320
+ ];
321
+ if (input.actors.length > 0) {
322
+ rows.push({ kind: "meshSection", label: "Persistent actors", count: input.actors.length });
323
+ for (const actor of input.actors) {
324
+ rows.push({ kind: "meshActor", entityId: `actor:${actor.id}`, actor });
325
+ }
326
+ }
327
+ if (participants.length > 0) {
328
+ rows.push({
329
+ kind: "meshSection",
330
+ label: "Project participants",
331
+ count: participants.length
332
+ });
333
+ for (const entry of projectParticipantTree(participants)) {
334
+ rows.push({
335
+ kind: "meshAgent",
336
+ entityId: entry.participant.entityId,
337
+ participant: entry.participant,
338
+ ancestorLast: entry.ancestorLast,
339
+ isLast: entry.isLast
340
+ });
341
+ }
342
+ }
343
+ if (topics.length > 0) {
344
+ rows.push({ kind: "meshSection", label: "Topics", count: topics.length });
345
+ for (const topic of topics) {
346
+ rows.push({ kind: "meshTopic", entityId: topic.id, topic });
347
+ for (let index = 0; index < topic.subscribers.length; index++) {
348
+ const subscriber = topic.subscribers[index];
349
+ if (!subscriber) continue;
350
+ rows.push({
351
+ kind: "meshLink",
352
+ relation: "subscribes",
353
+ sourceId: subscriber.id,
354
+ sourceName: subscriber.name,
355
+ targetId: topic.id,
356
+ targetName: topic.name,
357
+ status: subscriber.status,
358
+ isLast: index === topic.subscribers.length - 1
359
+ });
360
+ }
361
+ }
362
+ }
363
+ if (input.state.length > 0) {
364
+ rows.push({ kind: "meshSection", label: "Shared state", count: input.state.length });
365
+ for (const state of input.state) {
366
+ rows.push({ kind: "meshState", entityId: `state:${state.key}`, state });
367
+ }
368
+ }
369
+ if (routes.length > 0) {
370
+ rows.push({ kind: "meshSection", label: "Recent routes", count: routes.length });
371
+ for (const route of routes) {
372
+ rows.push({ kind: "meshRoute", entityId: route.id, route });
373
+ }
374
+ }
375
+ const entityOrder = rows.flatMap(
376
+ (row) => "entityId" in row ? [row.entityId] : []
377
+ );
378
+ return { participants, topics, routes, rows, entityOrder };
379
+ };
380
+
381
+ // src/ui/dashboard-model.ts
382
+ var entityGroupOrder = [
383
+ "agent",
384
+ "peer",
385
+ "actor",
386
+ "globalActor",
387
+ "tool",
388
+ "extension",
389
+ "mcp",
390
+ "mesh",
391
+ "task",
392
+ "custom",
393
+ "state",
394
+ "component",
395
+ "meshParticipant",
396
+ "meshTopic",
397
+ "meshRoute"
398
+ ];
399
+ var entityGroupLabels = {
400
+ agent: "Agents",
401
+ peer: "Peers",
402
+ actor: "Actors",
403
+ globalActor: "Global templates",
404
+ tool: "Tools",
405
+ extension: "Extensions",
406
+ mcp: "MCP",
407
+ mesh: "Mesh",
408
+ task: "Tasks",
409
+ custom: "Custom items",
410
+ state: "Shared state",
411
+ component: "Components",
412
+ meshParticipant: "Project participants",
413
+ meshTopic: "Topics",
414
+ meshRoute: "Recent routes"
415
+ };
416
+ var entityGroupKind = (entity) => {
417
+ if (entity.kind === "main" || entity.kind === "agent") return "agent";
418
+ if (entity.kind === "peer") return "peer";
419
+ if (entity.kind === "actor") return "actor";
420
+ if (entity.kind === "globalActor") return "globalActor";
421
+ if (entity.kind === "state") return "state";
422
+ if (entity.kind === "component") return "component";
423
+ if (entity.kind === "meshParticipant") return "meshParticipant";
424
+ if (entity.kind === "meshTopic") return "meshTopic";
425
+ if (entity.kind === "meshRoute") return "meshRoute";
426
+ if (entity.kind === "call") return entity.value.entityKind ?? entity.value.kind;
427
+ return entity.value.kind;
428
+ };
429
+ var entityGroupRanks = new Map(
430
+ entityGroupOrder.map((kind, index) => [kind, index])
431
+ );
432
+ var orderEntitiesByGroup = (entities) => entities.map((entity, index) => ({ entity, index })).sort(
433
+ (left, right) => (entityGroupRanks.get(entityGroupKind(left.entity)) ?? Number.MAX_SAFE_INTEGER) - (entityGroupRanks.get(entityGroupKind(right.entity)) ?? Number.MAX_SAFE_INTEGER) || left.index - right.index
434
+ ).map(({ entity }) => entity);
435
+ var groupEntities = (entities) => {
436
+ const indexed = entities.map((entity, index) => ({ entity, index }));
437
+ return entityGroupOrder.flatMap((kind) => {
438
+ const entries = indexed.filter(({ entity }) => entityGroupKind(entity) === kind);
439
+ return entries.length > 0 ? [{ kind, label: entityGroupLabels[kind], entries }] : [];
440
+ });
441
+ };
442
+ var filters = ["all", "active", "completed", "failed"];
443
+ var linkedEntityId = (entityId, id) => Boolean(entityId && (id.startsWith(entityId) || entityId.startsWith(id)));
444
+ var linkedAgent = (call, agent) => linkedEntityId(call.entityId, agent.id);
445
+ var agentLaunchRefs = /* @__PURE__ */ new Set(["agents.run", "agents.spawn"]);
446
+ var mainEntity = (snapshot) => ({
447
+ id: `main:${snapshot.main.id}`,
448
+ kind: "main",
449
+ label: "Main",
450
+ status: snapshot.main.status,
451
+ value: snapshot.main
452
+ });
453
+ var UNPHASED_PANEL_ID = "__fabric_unphased";
454
+ var SESSION_PANEL_ID = "__fabric_session";
455
+ var callsForPanel = (run, panel) => {
456
+ if (!run || panel.kind === "session") return [];
457
+ return run.calls.filter(
458
+ (call) => panel.kind === "unphased" ? !call.phaseId : call.phaseId === panel.id
459
+ );
460
+ };
461
+ var itemsForPanel = (run, panel) => {
462
+ if (!run || panel.kind === "session") return [];
463
+ return run.items.filter(
464
+ (item) => panel.kind === "unphased" ? !item.phaseId : item.phaseId === panel.id
465
+ );
466
+ };
467
+ var entitiesFor = (snapshot, run, panel) => {
468
+ if (!panel || panel.kind === "session") {
469
+ const unlinkedAgents = orderAgentsByCreation(snapshot.agents).filter((agent) => agent.runId !== run?.id && isActiveStatus(agent.status)).map((agent) => ({
470
+ id: `agent:${agent.id}`,
471
+ kind: "agent",
472
+ label: agent.name,
473
+ status: agent.status,
474
+ value: agent
475
+ }));
476
+ const peers = snapshot.peers.map((peer) => ({
477
+ id: `peer:${peer.id}`,
478
+ kind: "peer",
479
+ label: peer.name,
480
+ status: peer.status,
481
+ value: peer
482
+ }));
483
+ const actors = snapshot.actors.map((actor) => ({
484
+ id: `actor:${actor.id}`,
485
+ kind: "actor",
486
+ label: actor.name,
487
+ status: actor.lastError ? "failed" : actor.status,
488
+ value: actor
489
+ }));
490
+ const globalActors = snapshot.globalActors.map((definition) => ({
491
+ id: `globalActor:${definition.id}`,
492
+ kind: "globalActor",
493
+ label: definition.name,
494
+ status: "global",
495
+ value: definition
496
+ }));
497
+ const components = snapshot.componentGraph.components.map((component) => ({
498
+ id: `component:${component.id}`,
499
+ kind: "component",
500
+ label: component.id,
501
+ status: component.state,
502
+ value: component
503
+ }));
504
+ const state = snapshot.state.map((entry) => ({
505
+ id: `state:${entry.key}`,
506
+ kind: "state",
507
+ label: entry.label,
508
+ status: entry.status,
509
+ value: entry
510
+ }));
511
+ return orderEntitiesByGroup([
512
+ mainEntity(snapshot),
513
+ ...unlinkedAgents,
514
+ ...peers,
515
+ ...actors,
516
+ ...globalActors,
517
+ ...components,
518
+ ...state
519
+ ]);
520
+ }
521
+ const calls = callsForPanel(run, panel);
522
+ const panelAgents = orderAgentsByCreation(snapshot.agents).filter((agent) => {
523
+ const ownedByPanel = agent.runId === run?.id && (panel.kind === "unphased" ? !agent.phaseId : agent.phaseId === panel.id);
524
+ return ownedByPanel || !agent.runId && calls.some((call) => linkedAgent(call, agent));
525
+ });
526
+ const linkedAgents = panelAgents.map((agent) => ({
527
+ id: `agent:${agent.id}`,
528
+ kind: "agent",
529
+ label: agent.name,
530
+ status: agent.status,
531
+ value: agent
532
+ }));
533
+ const visibleCalls = calls.filter((call) => {
534
+ const representedAgentLaunch = call.kind === "agent" && agentLaunchRefs.has(call.ref) && panelAgents.some((agent) => linkedAgent(call, agent));
535
+ const representedActorCreation = call.kind === "actor" && call.ref === "agents.create" && snapshot.actors.some((actor) => linkedEntityId(call.entityId, actor.id));
536
+ return !representedAgentLaunch && !representedActorCreation;
537
+ }).map((call) => ({
538
+ id: `call:${call.id}`,
539
+ kind: "call",
540
+ label: call.label,
541
+ status: call.status,
542
+ value: call
543
+ }));
544
+ const items = itemsForPanel(run, panel).map((item) => ({
545
+ id: `item:${item.id}`,
546
+ kind: "item",
547
+ label: item.label,
548
+ status: item.status,
549
+ value: item
550
+ }));
551
+ return orderEntitiesByGroup([
552
+ mainEntity(snapshot),
553
+ ...linkedAgents,
554
+ ...visibleCalls,
555
+ ...items
556
+ ]);
557
+ };
558
+ var projectMeshEntitiesFor = (snapshot, topology) => {
559
+ const model = topology ?? buildProjectMeshTopology({
560
+ main: snapshot.main,
561
+ actors: snapshot.actors,
562
+ agents: snapshot.agents,
563
+ state: snapshot.state,
564
+ events: snapshot.events,
565
+ ...snapshot.participants ? { participants: snapshot.participants } : {},
566
+ now: snapshot.now
567
+ });
568
+ const entities = model.rows.flatMap((row) => {
569
+ if (row.kind === "meshRoot") return [mainEntity(snapshot)];
570
+ if (row.kind === "meshActor") {
571
+ return [{
572
+ id: row.entityId,
573
+ kind: "actor",
574
+ label: row.actor.name,
575
+ status: row.actor.lastError ? "failed" : row.actor.status,
576
+ value: row.actor
577
+ }];
578
+ }
579
+ if (row.kind === "meshAgent") {
580
+ if (row.participant.agent) {
581
+ return [{
582
+ id: row.entityId,
583
+ kind: "agent",
584
+ label: row.participant.agent.name,
585
+ status: row.participant.agent.status,
586
+ value: row.participant.agent
587
+ }];
588
+ }
589
+ return [{
590
+ id: row.entityId,
591
+ kind: "meshParticipant",
592
+ label: row.participant.name,
593
+ status: row.participant.status,
594
+ value: row.participant
595
+ }];
596
+ }
597
+ if (row.kind === "meshTopic") {
598
+ return [{
599
+ id: row.entityId,
600
+ kind: "meshTopic",
601
+ label: row.topic.name,
602
+ status: row.topic.status,
603
+ value: row.topic
604
+ }];
605
+ }
606
+ if (row.kind === "meshState") {
607
+ return [{
608
+ id: row.entityId,
609
+ kind: "state",
610
+ label: row.state.label,
611
+ status: row.state.status,
612
+ value: row.state
613
+ }];
614
+ }
615
+ if (row.kind === "meshRoute") {
616
+ return [{
617
+ id: row.entityId,
618
+ kind: "meshRoute",
619
+ label: `${row.route.fromName} \u2192 ${row.route.targetName}`,
620
+ status: row.route.status,
621
+ value: row.route
622
+ }];
623
+ }
624
+ return [];
625
+ });
626
+ return [
627
+ ...entities,
628
+ ...snapshot.componentGraph.components.map((component) => ({
629
+ id: `component:${component.id}`,
630
+ kind: "component",
631
+ label: component.id,
632
+ status: component.state,
633
+ value: component
634
+ }))
635
+ ];
636
+ };
637
+ var unifiedTopologyEntitiesFor = (snapshot, run, topology) => {
638
+ const orderedAgents = orderAgentsByCreation(snapshot.agents).sort(
639
+ (left, right) => Number(right.runId === run?.id) - Number(left.runId === run?.id) || Number(isActiveStatus(right.status)) - Number(isActiveStatus(left.status))
640
+ );
641
+ const canonical = [
642
+ mainEntity(snapshot),
643
+ ...orderedAgents.map((agent) => ({
644
+ id: `agent:${agent.id}`,
645
+ kind: "agent",
646
+ label: agent.name,
647
+ status: agent.status,
648
+ value: agent
649
+ })),
650
+ ...snapshot.actors.map((actor) => ({
651
+ id: `actor:${actor.id}`,
652
+ kind: "actor",
653
+ label: actor.name,
654
+ status: actor.lastError ? "failed" : actor.status,
655
+ value: actor
656
+ })),
657
+ ...snapshot.peers.map((peer) => ({
658
+ id: `peer:${peer.id}`,
659
+ kind: "peer",
660
+ label: peer.name,
661
+ status: peer.status,
662
+ value: peer
663
+ }))
664
+ ];
665
+ const seen = new Set(canonical.map((entity) => entity.id));
666
+ const seenParticipantIds = /* @__PURE__ */ new Set([
667
+ snapshot.main.id,
668
+ ...snapshot.agents.map((agent) => agent.id),
669
+ ...snapshot.actors.map((actor) => actor.id),
670
+ ...snapshot.peers.map((peer) => peer.id)
671
+ ]);
672
+ for (const entity of projectMeshEntitiesFor(snapshot, topology)) {
673
+ if (seen.has(entity.id)) continue;
674
+ if (entity.kind === "meshParticipant" && seenParticipantIds.has(entity.value.id)) continue;
675
+ seen.add(entity.id);
676
+ canonical.push(entity);
677
+ }
678
+ return canonical;
679
+ };
680
+ var entitiesForOverview = (snapshot, run, panel, view, projectMesh) => {
681
+ if (view === "topology") return unifiedTopologyEntitiesFor(snapshot, run, projectMesh);
682
+ return entitiesFor(snapshot, run, panel);
683
+ };
684
+ var panelStatus = (entities, fallback) => {
685
+ if (entities.some((entity) => ["failed", "timed_out", "error"].includes(entity.status))) {
686
+ return "failed";
687
+ }
688
+ if (entities.some((entity) => entity.status === "blocked")) return "blocked";
689
+ if (entities.some((entity) => isActiveStatus(entity.status))) return "running";
690
+ if (entities.length > 0 && entities.every(
691
+ (entity) => ["completed", "done", "stopped", "cancelled", "global", "idle", "state"].includes(
692
+ entity.status
693
+ )
694
+ )) {
695
+ return "completed";
696
+ }
697
+ return fallback;
698
+ };
699
+ var withPanelProgress = (snapshot, run, panel, projectedEntities) => {
700
+ const entities = projectedEntities ?? entitiesFor(snapshot, run, panel);
701
+ const progressEntities = panel.kind === "session" ? entities : entities.filter((entity) => entity.kind !== "main");
702
+ const status = panel.kind === "session" ? progressEntities.some(
703
+ (entity) => ["failed", "timed_out", "error"].includes(entity.status)
704
+ ) ? "failed" : progressEntities.some((entity) => isActiveStatus(entity.status)) ? "running" : "idle" : panelStatus(progressEntities, panel.status);
705
+ const agents = progressEntities.filter((entity) => entity.kind === "agent");
706
+ const tokens = agents.reduce(
707
+ (sum, entity) => sum + (entity.kind === "agent" && entity.value.usage ? entity.value.usage.input + entity.value.usage.output : 0),
708
+ 0
709
+ );
710
+ const starts = progressEntities.flatMap((entity) => {
711
+ if (entity.kind === "agent" || entity.kind === "call") return [entity.value.startedAt ?? 0];
712
+ if (entity.kind === "item") return [entity.value.createdAt];
713
+ return [];
714
+ }).filter((value) => value > 0);
715
+ const startedAt = starts.length > 0 ? Math.min(...starts) : void 0;
716
+ const hasActive = progressEntities.some((entity) => isActiveStatus(entity.status));
717
+ const finishes = progressEntities.flatMap((entity) => {
718
+ if (entity.kind === "agent" || entity.kind === "call") return [entity.value.finishedAt ?? 0];
719
+ if (entity.kind === "item") return [entity.value.finishedAt ?? 0];
720
+ return [];
721
+ }).filter((value) => value > 0);
722
+ const finishedAt = hasActive ? snapshot.now : finishes.length > 0 ? Math.max(...finishes) : void 0;
723
+ return {
724
+ ...panel,
725
+ status,
726
+ completed: progressEntities.filter(
727
+ (entity) => entity.status === "completed" || entity.status === "done"
728
+ ).length,
729
+ total: Math.max(panel.total, progressEntities.length),
730
+ ...agents.length > 0 ? { agents: agents.length } : {},
731
+ ...tokens > 0 ? { tokens } : {},
732
+ ...startedAt && finishedAt ? { elapsedMs: Math.max(0, finishedAt - startedAt) } : {}
733
+ };
734
+ };
735
+ var activityEntitiesByPanel = (snapshot, run) => {
736
+ const calls = /* @__PURE__ */ new Map();
737
+ const items = /* @__PURE__ */ new Map();
738
+ const agents = /* @__PURE__ */ new Map();
739
+ const keyFor = (phaseId) => phaseId ?? UNPHASED_PANEL_ID;
740
+ for (const call of run.calls) {
741
+ const key = keyFor(call.phaseId);
742
+ const bucket = calls.get(key) ?? [];
743
+ bucket.push(call);
744
+ calls.set(key, bucket);
745
+ }
746
+ for (const item of run.items) {
747
+ const key = keyFor(item.phaseId);
748
+ const bucket = items.get(key) ?? [];
749
+ bucket.push(item);
750
+ items.set(key, bucket);
751
+ }
752
+ const detachedAgents = [];
753
+ for (const agent of snapshot.agents) {
754
+ if (agent.runId === run.id) {
755
+ const key = keyFor(agent.phaseId);
756
+ const bucket = agents.get(key) ?? /* @__PURE__ */ new Map();
757
+ bucket.set(agent.id, agent);
758
+ agents.set(key, bucket);
759
+ } else if (!agent.runId) {
760
+ detachedAgents.push(agent);
761
+ }
762
+ }
763
+ if (detachedAgents.length > 0) {
764
+ for (const [key, panelCalls] of calls) {
765
+ for (const call of panelCalls) {
766
+ for (const agent of detachedAgents) {
767
+ if (!linkedAgent(call, agent)) continue;
768
+ const bucket = agents.get(key) ?? /* @__PURE__ */ new Map();
769
+ bucket.set(agent.id, agent);
770
+ agents.set(key, bucket);
771
+ }
772
+ }
773
+ }
774
+ }
775
+ const keys = /* @__PURE__ */ new Set([
776
+ UNPHASED_PANEL_ID,
777
+ ...run.phases.map((phase) => phase.id)
778
+ ]);
779
+ const projected = /* @__PURE__ */ new Map();
780
+ for (const key of keys) {
781
+ const panelAgents = [...agents.get(key)?.values() ?? []];
782
+ const agentEntities = panelAgents.map((agent) => ({
783
+ id: `agent:${agent.id}`,
784
+ kind: "agent",
785
+ label: agent.name,
786
+ status: agent.status,
787
+ value: agent
788
+ }));
789
+ const callEntities = (calls.get(key) ?? []).filter((call) => {
790
+ const representedAgentLaunch = call.kind === "agent" && agentLaunchRefs.has(call.ref) && panelAgents.some((agent) => linkedAgent(call, agent));
791
+ const representedActorCreation = call.kind === "actor" && call.ref === "agents.create" && snapshot.actors.some((actor) => linkedEntityId(call.entityId, actor.id));
792
+ return !representedAgentLaunch && !representedActorCreation;
793
+ }).map((call) => ({
794
+ id: `call:${call.id}`,
795
+ kind: "call",
796
+ label: call.label,
797
+ status: call.status,
798
+ value: call
799
+ }));
800
+ const itemEntities = (items.get(key) ?? []).map((item) => ({
801
+ id: `item:${item.id}`,
802
+ kind: "item",
803
+ label: item.label,
804
+ status: item.status,
805
+ value: item
806
+ }));
807
+ projected.set(key, [...agentEntities, ...callEntities, ...itemEntities]);
808
+ }
809
+ return projected;
810
+ };
811
+ var phasePanels = (snapshot, run) => {
812
+ const panels = [];
813
+ const activityEntities = run ? activityEntitiesByPanel(snapshot, run) : /* @__PURE__ */ new Map();
814
+ if (run) {
815
+ const runActivity = {
816
+ id: UNPHASED_PANEL_ID,
817
+ name: "Run activity",
818
+ status: run.status,
819
+ completed: 0,
820
+ total: 0,
821
+ kind: "unphased"
822
+ };
823
+ if ((activityEntities.get(UNPHASED_PANEL_ID)?.length ?? 0) > 0) panels.push(runActivity);
824
+ }
825
+ panels.push(
826
+ ...run?.phases.map((phase) => ({
827
+ id: phase.id,
828
+ name: phase.name,
829
+ status: phase.status,
830
+ completed: 0,
831
+ total: phase.total ?? 0,
832
+ phase,
833
+ kind: "phase"
834
+ })) ?? []
835
+ );
836
+ const session = {
837
+ id: SESSION_PANEL_ID,
838
+ name: "Project participants & shared state",
839
+ status: "idle",
840
+ completed: 0,
841
+ total: 0,
842
+ kind: "session"
843
+ };
844
+ const sessionEntities = entitiesFor(snapshot, run, session);
845
+ if (sessionEntities.length > 0 || panels.length === 0) panels.push(session);
846
+ return panels.map(
847
+ (panel) => withPanelProgress(
848
+ snapshot,
849
+ run,
850
+ panel,
851
+ panel.kind === "session" ? sessionEntities : activityEntities.get(panel.id) ?? []
852
+ )
853
+ );
854
+ };
855
+ var matchesFilter = (status, filter) => {
856
+ if (filter === "all") return true;
857
+ if (filter === "active") return isActiveStatus(status);
858
+ if (filter === "completed") return status === "completed" || status === "done";
859
+ return status === "failed" || status === "timed_out" || status === "blocked" || status === "error";
860
+ };
861
+ var tokensFor = (snapshot, run) => snapshot.agents.filter((agent) => !run || agent.runId === run.id).reduce(
862
+ (sum, agent) => sum + (agent.usage ? agent.usage.input + agent.usage.output : 0),
863
+ 0
864
+ );
865
+
866
+ // src/ui/dashboard-presentation.ts
867
+ var statusGlyph = (status) => {
868
+ if (status === "completed" || status === "done") return "\u2713";
869
+ if (status === "failed" || status === "timed_out" || status === "error") return "\u2717";
870
+ if (status === "blocked") return "!";
871
+ if (status === "stopped" || status === "cancelled") return "\u25A0";
872
+ if (status === "queued" || status === "pending" || status === "ready") return "\u25CB";
873
+ if (status === "idle" || status === "state") return "\xB7";
874
+ if (status === "global") return "\u25C7";
875
+ return spinnerFrame();
876
+ };
877
+ var colorStatus = (theme, status, value) => {
878
+ if (status === "completed" || status === "done") return theme.fg("success", value);
879
+ if (status === "failed" || status === "timed_out" || status === "error") {
880
+ return theme.fg("error", value);
881
+ }
882
+ if (status === "blocked" || status === "warning") return theme.fg("warning", value);
883
+ if (status === "running" || status === "in_progress") return theme.fg("accent", value);
884
+ if (status === "global") return theme.fg("muted", value);
885
+ return theme.fg("dim", value);
886
+ };
887
+ var entityTail = (entity, now) => {
888
+ if (entity.kind === "main") {
889
+ const main = entity.value;
890
+ return [
891
+ "host OMP",
892
+ main.model,
893
+ main.thinking,
894
+ main.pendingMessages ? "messages queued" : void 0,
895
+ main.local ? void 0 : "remote"
896
+ ].filter((value) => Boolean(value)).join(" \xB7 ");
897
+ }
898
+ if (entity.kind === "agent") {
899
+ const agent = entity.value;
900
+ const narrative = safeText(agent.error ?? agent.text).slice(0, 140);
901
+ const summary = agent.status === "blocked" && narrative ? `needs input: ${narrative}` : (agent.status === "failed" || agent.status === "timed_out") && narrative ? `error: ${narrative}` : agent.status === "completed" && narrative ? `result: ${narrative}` : agent.currentTool ?? (agent.status === "running" ? "thinking" : void 0);
902
+ const parts = [
903
+ summary,
904
+ agent.runner,
905
+ agent.model,
906
+ agent.usage ? `${formatTokens(agent.usage.input + agent.usage.output)} tok` : void 0,
907
+ agent.toolCalls !== void 0 ? `${agent.toolCalls} tools` : void 0,
908
+ agent.startedAt ? formatDuration((agent.finishedAt ?? now) - agent.startedAt) : void 0
909
+ ];
910
+ return parts.filter((value) => Boolean(value)).join(" \xB7 ");
911
+ }
912
+ if (entity.kind === "actor") {
913
+ const actor = entity.value;
914
+ return [
915
+ actor.runner,
916
+ actor.model ?? actor.worker?.model,
917
+ actor.worker?.currentTool,
918
+ actor.worker?.usage ? `${formatTokens(actor.worker.usage.input + actor.worker.usage.output)} tok` : void 0,
919
+ `${actor.messages} msg`,
920
+ actor.queued > 0 ? `q:${actor.queued}` : void 0
921
+ ].filter((value) => Boolean(value)).join(" \xB7 ");
922
+ }
923
+ if (entity.kind === "globalActor") {
924
+ const def = entity.value;
925
+ return [
926
+ "global template",
927
+ def.runner,
928
+ def.model ?? "inherit",
929
+ def.responseMode === "directive" ? "directive" : void 0,
930
+ def.delivery !== "mailbox" ? def.delivery : void 0
931
+ ].filter((value) => Boolean(value)).join(" \xB7 ");
932
+ }
933
+ if (entity.kind === "call") {
934
+ const call = entity.value;
935
+ return [
936
+ call.ref,
937
+ call.progress,
938
+ call.metrics?.tokens !== void 0 ? `${formatTokens(call.metrics.tokens)} tok` : void 0,
939
+ call.metrics?.toolCalls !== void 0 ? `${call.metrics.toolCalls} tools` : void 0,
940
+ formatDuration((call.finishedAt ?? now) - call.startedAt)
941
+ ].filter((value) => Boolean(value)).join(" \xB7 ");
942
+ }
943
+ if (entity.kind === "item") {
944
+ const item = entity.value;
945
+ return [
946
+ item.current ?? item.detail,
947
+ item.total !== void 0 ? `${item.completed ?? 0}/${item.total}` : void 0
948
+ ].filter((value) => Boolean(value)).join(" \xB7 ");
949
+ }
950
+ if (entity.kind === "peer") {
951
+ const peer = entity.value;
952
+ return [peer.sessionId, peer.model, `${formatDuration(Math.max(0, now - peer.updatedAt))} ago`].filter((value) => Boolean(value)).join(" \xB7 ");
953
+ }
954
+ if (entity.kind === "meshParticipant") {
955
+ const participant = entity.value;
956
+ return [
957
+ participant.participant ? `project ${participant.participant.kind}` : "observed mesh agent",
958
+ `${participant.routes} route${participant.routes === 1 ? "" : "s"}`,
959
+ `${formatDuration(Math.max(0, now - participant.lastSeenAt))} ago`
960
+ ].join(" \xB7 ");
961
+ }
962
+ if (entity.kind === "meshTopic") {
963
+ const topic = entity.value;
964
+ return [
965
+ `${topic.subscribers.length} subscriber${topic.subscribers.length === 1 ? "" : "s"}`,
966
+ topic.recentEvents > 0 ? `${topic.recentEvents} recent event${topic.recentEvents === 1 ? "" : "s"}` : void 0,
967
+ topic.lastEventAt ? `${formatDuration(Math.max(0, now - topic.lastEventAt))} ago` : void 0
968
+ ].filter((value) => Boolean(value)).join(" \xB7 ");
969
+ }
970
+ if (entity.kind === "meshRoute") {
971
+ const route = entity.value;
972
+ return [
973
+ route.kind,
974
+ route.topic,
975
+ route.count > 1 ? `\xD7${route.count}` : void 0,
976
+ `${formatDuration(Math.max(0, now - route.lastAt))} ago`
977
+ ].filter((value) => Boolean(value)).join(" \xB7 ");
978
+ }
979
+ if (entity.kind === "component") {
980
+ return [
981
+ entity.value.guarantee,
982
+ entity.value.parentId ? `child of ${entity.value.parentId}` : void 0,
983
+ (entity.value.effects?.length ?? 0) > 0 ? `${entity.value.effects.length} effects` : void 0,
984
+ entity.value.requirements.length > 0 ? `${entity.value.requirements.length} requirements` : void 0,
985
+ entity.value.provisions.length > 0 ? `${entity.value.provisions.length} provisions` : void 0
986
+ ].filter((value) => Boolean(value)).join(" \xB7 ");
987
+ }
988
+ return [entity.value.owner, entity.value.detail, `v${entity.value.version}`].filter((value) => Boolean(value)).join(" \xB7 ");
989
+ };
990
+
991
+ // src/ui/dashboard-detail.ts
992
+ import { Markdown, truncateToWidth as truncateToWidth2, wrapTextWithAnsi, visibleWidth as visibleWidth2 } from "@oh-my-pi/pi-tui";
993
+
994
+ // src/ui/state-file-preview.ts
995
+ import fs from "node:fs";
996
+ import path from "node:path";
997
+ import { truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
998
+ var MAX_FILE_BYTES = 64 * 1024;
999
+ var MAX_FILE_LINES = 240;
1000
+ var CACHE_LIMIT = 64;
1001
+ var cache = /* @__PURE__ */ new Map();
1002
+ var candidatePath = (entry) => {
1003
+ const value = entry.value;
1004
+ if (value && typeof value === "object" && !Array.isArray(value)) {
1005
+ const record = value;
1006
+ const candidate = record.file ?? record.path;
1007
+ if (typeof candidate === "string" && candidate.trim()) return candidate.trim();
1008
+ }
1009
+ return entry.key.startsWith("state/complexity/") ? entry.key.slice("state/complexity/".length) : void 0;
1010
+ };
1011
+ var inside = (root, candidate) => {
1012
+ const relative = path.relative(root, candidate);
1013
+ return relative === "" || !relative.startsWith(`..${path.sep}`) && relative !== "..";
1014
+ };
1015
+ var loadStateFilePreview = (entry, cwd) => {
1016
+ const candidate = candidatePath(entry);
1017
+ if (!candidate || path.isAbsolute(candidate) || !cwd) return void 0;
1018
+ try {
1019
+ const root = fs.realpathSync(cwd);
1020
+ const absolute = fs.realpathSync(path.resolve(root, candidate));
1021
+ if (!inside(root, absolute)) return void 0;
1022
+ const stat = fs.statSync(absolute);
1023
+ if (!stat.isFile()) return void 0;
1024
+ const cacheKey = `${absolute}\0${stat.mtimeMs}\0${stat.size}`;
1025
+ const cached = cache.get(cacheKey);
1026
+ if (cached) {
1027
+ cache.delete(cacheKey);
1028
+ cache.set(cacheKey, cached);
1029
+ return cached;
1030
+ }
1031
+ const bytes = Math.min(stat.size, MAX_FILE_BYTES);
1032
+ const descriptor = fs.openSync(absolute, "r");
1033
+ const buffer = Buffer.alloc(bytes);
1034
+ try {
1035
+ if (bytes > 0) fs.readSync(descriptor, buffer, 0, bytes, 0);
1036
+ } finally {
1037
+ fs.closeSync(descriptor);
1038
+ }
1039
+ if (buffer.includes(0)) return void 0;
1040
+ const decoded = buffer.toString("utf8").replace(/\r\n?/g, "\n");
1041
+ const allLines = decoded.split("\n");
1042
+ const boundedLines = allLines.slice(0, MAX_FILE_LINES);
1043
+ const preview = {
1044
+ path: (path.relative(root, absolute) || path.basename(absolute)).split(path.sep).join("/"),
1045
+ absolutePath: absolute,
1046
+ language: languageFromPath(absolute) ?? "text",
1047
+ content: boundedLines.join("\n"),
1048
+ lines: boundedLines,
1049
+ truncated: stat.size > bytes || allLines.length > boundedLines.length
1050
+ };
1051
+ cache.set(cacheKey, preview);
1052
+ while (cache.size > CACHE_LIMIT) cache.delete(cache.keys().next().value);
1053
+ return preview;
1054
+ } catch {
1055
+ return void 0;
1056
+ }
1057
+ };
1058
+ var renderStateFilePreview = (preview, theme, width, maxLines, invalidate) => {
1059
+ if (width <= 0 || maxLines <= 0) return [];
1060
+ const shown = preview.lines.slice(0, maxLines);
1061
+ const fileLines = highlightFileLines(
1062
+ preview.absolutePath,
1063
+ preview.language,
1064
+ 0,
1065
+ shown.length,
1066
+ invalidate
1067
+ );
1068
+ const fileVerified = fileLines !== null && fileLines.every((line, index) => line.raw === (shown[index] ?? "").replace(/\t/g, " "));
1069
+ const highlighted = fileVerified ? fileLines.map((line) => line.ansi || " ") : highlightCode(shown.join("\n"), preview.language, invalidate) ?? shown.map((line) => theme.fg("mdCodeBlock", safeText(line) || " "));
1070
+ const digits = String(Math.max(1, shown.length)).length;
1071
+ const output = highlighted.map((line, index) => {
1072
+ const gutter = theme.fg("dim", `${String(index + 1).padStart(digits)} \u2502 `);
1073
+ return truncateToWidth(gutter + line, width, "");
1074
+ });
1075
+ if ((preview.truncated || preview.lines.length > shown.length) && output.length < maxLines) {
1076
+ const omitted = Math.max(0, preview.lines.length - shown.length);
1077
+ const label = omitted > 0 ? `\u2026 ${omitted}+ lines omitted` : "\u2026 file truncated";
1078
+ output.push(truncateToWidth(theme.fg("dim", label), width, ""));
1079
+ }
1080
+ return output.filter((line) => visibleWidth(line) <= width);
1081
+ };
1082
+
1083
+ // src/ui/dashboard-detail.ts
1084
+ var isSymbolTheme = (value) => value !== null && typeof value === "object";
1085
+ var transcriptMarkdownTheme = (theme, invalidate) => {
1086
+ const rawSymbols = Reflect.get(theme, "symbols");
1087
+ const symbols = isSymbolTheme(rawSymbols) ? rawSymbols : ompSymbolTheme;
1088
+ const format = (color, text) => theme.fg(color, text);
1089
+ const style = (name, text) => {
1090
+ const fn = Reflect.get(theme, name);
1091
+ return typeof fn === "function" ? fn.call(theme, text) : text;
1092
+ };
1093
+ return {
1094
+ symbols,
1095
+ heading: (text) => format("mdHeading", text),
1096
+ link: (text) => format("mdLink", text),
1097
+ linkUrl: (text) => format("mdLinkUrl", text),
1098
+ code: (text) => format("mdCode", text),
1099
+ codeBlock: (text) => format("mdCodeBlock", text),
1100
+ codeBlockBorder: (text) => format("mdCodeBlockBorder", text),
1101
+ quote: (text) => format("mdQuote", text),
1102
+ quoteBorder: (text) => format("mdQuoteBorder", text),
1103
+ hr: (text) => format("mdHr", text),
1104
+ listBullet: (text) => format("mdListBullet", text),
1105
+ bold: (text) => style("bold", text),
1106
+ italic: (text) => style("italic", text),
1107
+ underline: (text) => style("underline", text),
1108
+ strikethrough: (text) => style("strikethrough", text),
1109
+ highlightCode: (code, lang) => highlightCode(code, lang ?? "", invalidate) ?? code.split("\n").map((line) => format("mdCodeBlock", line))
1110
+ };
1111
+ };
1112
+ var TRANSCRIPT_EXPANDED_TOOL_LINES = 40;
1113
+ var TRANSCRIPT_STRUCTURED_LINES = 40;
1114
+ var safeMarkdownText = (value) => value.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "").replace(/\r\n?/g, "\n").replace(/[\u0000-\u0008\u000b-\u000c\u000e-\u001f\u007f-\u009f]/g, " ");
1115
+ var DashboardDetailRenderer = class {
1116
+ constructor(tui, theme, snapshot, options) {
1117
+ this.tui = tui;
1118
+ this.theme = theme;
1119
+ this.snapshot = snapshot;
1120
+ this.agentTranscript = options.agentTranscript;
1121
+ this.actorTranscript = options.actorTranscript;
1122
+ this.codePreviewSettings = options.codePreviewSettings;
1123
+ this.actorDefaultTools = options.actorDefaultTools;
1124
+ }
1125
+ detailView = "summary";
1126
+ detailScroll = 0;
1127
+ detailMaxScroll = 0;
1128
+ transcriptPageAnchor;
1129
+ transcriptFollowing = true;
1130
+ transcriptToolsExpanded = false;
1131
+ actionHint = "";
1132
+ toolToggleHint = "";
1133
+ transcriptMarkdown = /* @__PURE__ */ new Map();
1134
+ highlightInvalidate = () => this.tui.requestRender();
1135
+ agentTranscript;
1136
+ actorTranscript;
1137
+ codePreviewSettings;
1138
+ actorDefaultTools;
1139
+ render(width, snapshot, entity, state, actionHint, toolToggleHint) {
1140
+ this.detailView = state.view;
1141
+ this.detailScroll = state.scroll;
1142
+ this.transcriptPageAnchor = state.pageAnchor;
1143
+ this.transcriptFollowing = state.transcriptFollowing;
1144
+ this.transcriptToolsExpanded = state.transcriptToolsExpanded;
1145
+ this.actionHint = actionHint;
1146
+ this.toolToggleHint = toolToggleHint;
1147
+ const lines = this.renderDetail(width, snapshot, entity);
1148
+ return {
1149
+ lines,
1150
+ scroll: this.detailScroll,
1151
+ maxScroll: this.detailMaxScroll,
1152
+ pageAnchor: this.transcriptPageAnchor
1153
+ };
1154
+ }
1155
+ invalidate() {
1156
+ this.transcriptMarkdown.clear();
1157
+ }
1158
+ detailActionHint(_entity) {
1159
+ return this.actionHint;
1160
+ }
1161
+ transcriptToolToggleHint() {
1162
+ return this.toolToggleHint;
1163
+ }
1164
+ transcriptTarget(entity) {
1165
+ if (entity.kind === "agent" || entity.kind === "actor") return entity.value;
1166
+ return void 0;
1167
+ }
1168
+ hasTranscript(entity) {
1169
+ return entity.kind === "agent" && this.agentTranscript !== void 0 || entity.kind === "actor" && this.actorTranscript !== void 0;
1170
+ }
1171
+ transcriptFor(entity) {
1172
+ if (entity.kind === "agent") {
1173
+ return this.agentTranscript?.(entity.value, this.transcriptFollowing);
1174
+ }
1175
+ if (entity.kind === "actor") {
1176
+ return this.actorTranscript?.(entity.value, this.transcriptFollowing);
1177
+ }
1178
+ return void 0;
1179
+ }
1180
+ renderDetail(width, snapshot, entity) {
1181
+ if (width < 24) return this.renderNarrowDetail(width, snapshot, entity);
1182
+ const innerWidth = width - 2;
1183
+ const transcriptView = (entity.kind === "agent" || entity.kind === "actor") && this.detailView === "transcript";
1184
+ const actionLines = wrapPlainText(this.detailActionHint(entity), Math.max(1, innerWidth - 2), 3);
1185
+ const viewLabel = transcriptView ? ` \xB7 transcript \xB7 ${isActiveStatus(entity.status) ? "live" : entity.status}` : "";
1186
+ const kindLabel = entity.kind === "main" ? "main agent" : entity.kind === "peer" ? "peer session" : entity.kind === "meshParticipant" ? "project participant" : entity.kind === "meshTopic" ? "topic" : entity.kind === "meshRoute" ? "route" : entity.kind;
1187
+ const lines = [this.topBorder(width, `${kindLabel} \xB7 ${entity.label}${viewLabel}`)];
1188
+ const content = transcriptView ? this.transcriptLines(entity, innerWidth) : this.detailLines(entity, innerWidth, snapshot.now, snapshot.main.cwd ?? process.cwd());
1189
+ const terminalRows = this.tui.terminal?.rows ?? process.stdout.rows ?? 28;
1190
+ const maxBody = Math.max(1, Math.min(24, terminalRows - 8 - actionLines.length));
1191
+ const maxScroll = Math.max(0, content.length - maxBody);
1192
+ this.detailMaxScroll = maxScroll;
1193
+ if (transcriptView && this.transcriptFollowing) {
1194
+ this.detailScroll = maxScroll;
1195
+ } else if (transcriptView && this.transcriptPageAnchor) {
1196
+ this.detailScroll = this.transcriptPageAnchor === "end" ? maxScroll : 0;
1197
+ this.transcriptPageAnchor = void 0;
1198
+ } else {
1199
+ this.detailScroll = Math.max(0, Math.min(this.detailScroll, maxScroll));
1200
+ }
1201
+ const visible = content.slice(this.detailScroll, this.detailScroll + maxBody);
1202
+ for (const line of visible) lines.push(this.row(width, line));
1203
+ while (lines.length < maxBody + 1) lines.push(this.row(width, ""));
1204
+ lines.push(this.middleBorder(width));
1205
+ const range = content.length > maxBody ? ` \xB7 ${this.detailScroll + 1}-${Math.min(content.length, this.detailScroll + maxBody)}/${content.length}` : "";
1206
+ const navigation = transcriptView ? `\u2191\u2193/jk lazy scroll \xB7 ${this.transcriptToolToggleHint()} \xB7 g page top \xB7 G follow:${this.transcriptFollowing ? "on" : "off"}/live tail \xB7 t summary \xB7 esc back${range}` : `\u2191\u2193/jk scroll \xB7 ${this.hasTranscript(entity) ? "t transcript \xB7 " : ""}esc back${range}`;
1207
+ lines.push(this.row(width, this.theme.fg("dim", navigation)));
1208
+ for (const actionLine of actionLines) {
1209
+ lines.push(this.row(width, this.theme.fg("muted", ` ${actionLine}`)));
1210
+ }
1211
+ lines.push(this.bottomBorder(width));
1212
+ return lines.map((line) => truncateToWidth2(line, width, ""));
1213
+ }
1214
+ transcriptLines(entity, width) {
1215
+ const transcript = this.transcriptFor(entity);
1216
+ const transcriptCwd = entity.kind === "agent" ? entity.value.cwd : entity.kind === "actor" ? entity.value.worker?.cwd : void 0;
1217
+ if (!transcript || transcript.entries.length === 0) {
1218
+ return [
1219
+ this.theme.fg(
1220
+ "dim",
1221
+ isActiveStatus(entity.status) ? "Waiting for streamed agent activity\u2026" : "No retained transcript is available for this agent or actor."
1222
+ )
1223
+ ];
1224
+ }
1225
+ const lines = [];
1226
+ if (transcript.hasMore ?? transcript.truncated) {
1227
+ lines.push(this.theme.fg("dim", "\u2191 older activity available \xB7 scroll past the top to load"));
1228
+ }
1229
+ let firstTool = true;
1230
+ for (const entry of transcript.entries) {
1231
+ if (entry.kind === "tool") {
1232
+ if (this.transcriptToolsExpanded && !firstTool) lines.push("");
1233
+ firstTool = false;
1234
+ lines.push(...this.transcriptToolLines(entry, width, transcriptCwd));
1235
+ continue;
1236
+ }
1237
+ const glyph = entry.kind === "assistant" ? this.theme.fg("accent", "\u25C6") : entry.kind === "user" ? this.theme.fg("muted", "\u203A") : entry.kind === "error" ? this.theme.fg("error", "\u2717") : colorStatus(
1238
+ this.theme,
1239
+ entry.status ?? "completed",
1240
+ statusGlyph(entry.status ?? "completed")
1241
+ );
1242
+ lines.push(
1243
+ truncateToWidth2(
1244
+ `${glyph} ${this.theme.fg(
1245
+ entry.kind === "assistant" ? "accent" : "muted",
1246
+ safeText(entry.label)
1247
+ )}`,
1248
+ width,
1249
+ ""
1250
+ )
1251
+ );
1252
+ if (!entry.text) continue;
1253
+ if (entry.kind === "assistant" || entry.kind === "user") {
1254
+ lines.push(
1255
+ ...this.markdownTranscriptLines(
1256
+ this.transcriptTarget(entity)?.id ?? entity.id,
1257
+ entry.id,
1258
+ entry.text,
1259
+ width
1260
+ )
1261
+ );
1262
+ continue;
1263
+ }
1264
+ for (const paragraph of entry.text.split("\n")) {
1265
+ const wrapped = wrapPlainText(paragraph, Math.max(1, width - 2), 1e4);
1266
+ for (const line of wrapped) lines.push(truncateToWidth2(` ${line}`, width, ""));
1267
+ }
1268
+ }
1269
+ if (transcript.hasNewer) {
1270
+ lines.push(this.theme.fg("dim", "\u2193 newer activity available \xB7 scroll past the bottom to load"));
1271
+ }
1272
+ return lines;
1273
+ }
1274
+ transcriptToolLines(entry, width, transcriptCwd) {
1275
+ const depth = Math.max(0, entry.depth ?? 0);
1276
+ const padding = " ".repeat(depth);
1277
+ const bodyPadding = `${padding} `;
1278
+ const glyph = colorStatus(
1279
+ this.theme,
1280
+ entry.status ?? "completed",
1281
+ statusGlyph(entry.status ?? "completed")
1282
+ );
1283
+ const status = entry.status === "running" ? " \xB7 running" : entry.status === "failed" ? " \xB7 failed" : "";
1284
+ const audit = this.transcriptToolAudit(entry);
1285
+ const context = this.codePreviewSettings ? {
1286
+ cwd: transcriptCwd ?? this.snapshot().main.cwd ?? process.cwd(),
1287
+ settings: this.codePreviewSettings,
1288
+ invalidate: this.highlightInvalidate
1289
+ } : void 0;
1290
+ const title = context ? coreToolTitle(audit, this.theme, context) : null;
1291
+ const headline = title ?? this.theme.fg("toolTitle", this.theme.bold(entry.toolName ?? entry.label));
1292
+ const collapsedSummary = !this.transcriptToolsExpanded && entry.text ? ` \xB7 ${safeText(entry.text).replace(/\s+/g, " ").trim()}` : "";
1293
+ const lines = [
1294
+ truncateToWidth2(
1295
+ `${padding}${glyph} ${headline}${this.theme.fg("dim", `${status}${collapsedSummary}`)}`,
1296
+ width,
1297
+ ""
1298
+ )
1299
+ ];
1300
+ if (!this.transcriptToolsExpanded) return lines;
1301
+ const rendered = context ? renderCoreToolBody(audit, this.theme, {
1302
+ ...context,
1303
+ expanded: true,
1304
+ maxLines: TRANSCRIPT_EXPANDED_TOOL_LINES
1305
+ }) : null;
1306
+ if (rendered) {
1307
+ for (const row of renderBoundedLines(
1308
+ rendered.lines,
1309
+ this.theme,
1310
+ this.codePreviewSettings?.diffIntensity ?? "off"
1311
+ ).render(Math.max(1, width - visibleWidth2(bodyPadding)))) {
1312
+ lines.push(truncateToWidth2(`${bodyPadding}${row}`, width, ""));
1313
+ }
1314
+ if (rendered.hidden > 0) {
1315
+ lines.push(this.theme.fg("dim", `${bodyPadding}\u2026 ${rendered.hidden} more lines`));
1316
+ }
1317
+ return lines;
1318
+ }
1319
+ if (entry.args && Object.keys(entry.args).length > 0) {
1320
+ lines.push(...this.transcriptStructuredLines("input", entry.args, width, bodyPadding));
1321
+ } else if (entry.text) {
1322
+ for (const row of wrapPlainText(
1323
+ entry.text,
1324
+ Math.max(1, width - visibleWidth2(bodyPadding)),
1325
+ 1e4
1326
+ )) {
1327
+ lines.push(truncateToWidth2(`${bodyPadding}${row}`, width, ""));
1328
+ }
1329
+ }
1330
+ if (entry.result !== void 0) {
1331
+ lines.push(...this.transcriptStructuredLines("result", entry.result, width, bodyPadding));
1332
+ }
1333
+ return lines;
1334
+ }
1335
+ transcriptToolAudit(entry) {
1336
+ const rawName = entry.toolName ?? entry.label;
1337
+ const normalizedName = rawName.toLowerCase();
1338
+ const tool = normalizedName === "glob" ? "find" : ["read", "write", "edit", "bash", "grep", "find", "ls"].includes(normalizedName) ? normalizedName : rawName;
1339
+ const rawArgs = entry.args ?? {};
1340
+ const args = { ...rawArgs };
1341
+ if (typeof rawArgs.file_path === "string" && typeof args.path !== "string") {
1342
+ args.path = rawArgs.file_path;
1343
+ }
1344
+ if (tool === "edit" && !Array.isArray(args.edits)) {
1345
+ const oldText = typeof rawArgs.old_string === "string" ? rawArgs.old_string : void 0;
1346
+ const newText = typeof rawArgs.new_string === "string" ? rawArgs.new_string : void 0;
1347
+ if (oldText !== void 0 && newText !== void 0) args.edits = [{ oldText, newText }];
1348
+ }
1349
+ return {
1350
+ ref: typeof tool === "string" ? `omp.${tool}` : `tool.${rawName}`,
1351
+ provider: "omp",
1352
+ tool,
1353
+ ...Object.keys(args).length > 0 ? { args } : {},
1354
+ ...entry.result !== void 0 ? { result: entry.result } : {},
1355
+ ...entry.status !== "running" ? { success: entry.status !== "failed" } : {}
1356
+ };
1357
+ }
1358
+ transcriptStructuredLines(label, value, width, padding) {
1359
+ const yaml = formatJsonAsYaml(value) ?? safeText(value);
1360
+ if (!yaml) return [];
1361
+ const yamlLines = yaml.split("\n");
1362
+ const shownYamlLines = yamlLines.slice(0, TRANSCRIPT_STRUCTURED_LINES);
1363
+ const highlighted = highlightCode(shownYamlLines.join("\n"), "yaml", this.highlightInvalidate) ?? shownYamlLines.map((line) => this.theme.fg("mdCodeBlock", line || " "));
1364
+ const lines = [truncateToWidth2(`${padding}${this.theme.fg("dim", `${label}:`)}`, width, "")];
1365
+ const nestedPadding = `${padding} `;
1366
+ for (const row of highlighted) {
1367
+ for (const wrapped of wrapTextWithAnsi(row, Math.max(1, width - visibleWidth2(nestedPadding)))) {
1368
+ lines.push(truncateToWidth2(`${nestedPadding}${wrapped}`, width, ""));
1369
+ if (lines.length > TRANSCRIPT_STRUCTURED_LINES) break;
1370
+ }
1371
+ if (lines.length > TRANSCRIPT_STRUCTURED_LINES) break;
1372
+ }
1373
+ const hiddenLines = Math.max(0, yamlLines.length - shownYamlLines.length);
1374
+ if (hiddenLines > 0) {
1375
+ lines.push(this.theme.fg("dim", `${nestedPadding}\u2026 ${hiddenLines} more lines`));
1376
+ }
1377
+ return lines;
1378
+ }
1379
+ markdownTranscriptLines(agentId, entryId, text, width) {
1380
+ return this.markdownLines(`transcript:${agentId}:${entryId}`, text, width);
1381
+ }
1382
+ markdownLines(key, text, width, indent = 2) {
1383
+ const markdown = safeMarkdownText(text);
1384
+ if (!markdown.trim()) return [];
1385
+ let cached = this.transcriptMarkdown.get(key);
1386
+ if (!cached || cached.text !== markdown) {
1387
+ cached = {
1388
+ text: markdown,
1389
+ component: new Markdown(
1390
+ markdown,
1391
+ 0,
1392
+ 0,
1393
+ transcriptMarkdownTheme(this.theme, () => {
1394
+ this.transcriptMarkdown.delete(key);
1395
+ this.tui.requestRender();
1396
+ })
1397
+ )
1398
+ };
1399
+ this.transcriptMarkdown.delete(key);
1400
+ this.transcriptMarkdown.set(key, cached);
1401
+ while (this.transcriptMarkdown.size > 128) {
1402
+ const oldest = this.transcriptMarkdown.keys().next().value;
1403
+ if (!oldest) break;
1404
+ this.transcriptMarkdown.delete(oldest);
1405
+ }
1406
+ }
1407
+ const padding = " ".repeat(Math.max(0, indent));
1408
+ return cached.component.render(Math.max(1, width - visibleWidth2(padding))).map((line) => truncateToWidth2(`${padding}${line}`, width, ""));
1409
+ }
1410
+ detailLines(entity, width, now, cwd) {
1411
+ const lines = [];
1412
+ const field = (label, value) => {
1413
+ const text = safeText(value);
1414
+ if (!text) return;
1415
+ const prefix = `${this.theme.fg("dim", `${label}:`)} `;
1416
+ const wrapped = wrapPlainText(text, Math.max(1, width - visibleWidth2(prefix)), 12);
1417
+ if (wrapped[0]) lines.push(truncateToWidth2(prefix + wrapped[0], width));
1418
+ for (const continuation of wrapped.slice(1)) {
1419
+ lines.push(truncateToWidth2(" ".repeat(visibleWidth2(prefix)) + continuation, width));
1420
+ }
1421
+ };
1422
+ const markdownField = (label, value, key) => {
1423
+ if (!value?.trim()) return;
1424
+ lines.push(this.theme.fg("dim", `${label}:`));
1425
+ lines.push(...this.markdownLines(`detail:${entity.id}:${key}`, value, width));
1426
+ };
1427
+ const structuredField = (label, value) => {
1428
+ if (value === void 0) return;
1429
+ const yaml = formatJsonAsYaml(value);
1430
+ if (yaml === void 0) {
1431
+ field(label, value);
1432
+ return;
1433
+ }
1434
+ lines.push(this.theme.fg("dim", `${label}:`));
1435
+ const highlighted = highlightCode(yaml, "yaml", this.highlightInvalidate) ?? yaml.split("\n").map((line) => this.theme.fg("mdCodeBlock", line || " "));
1436
+ for (const highlightedLine of highlighted) {
1437
+ for (const wrapped of wrapTextWithAnsi(highlightedLine, Math.max(1, width - 2))) {
1438
+ lines.push(truncateToWidth2(` ${wrapped}`, width, ""));
1439
+ }
1440
+ }
1441
+ };
1442
+ const stringOutputField = (label, value) => {
1443
+ if (typeof value !== "string") return;
1444
+ markdownField(label, value, label.toLowerCase());
1445
+ };
1446
+ const objectOutputField = (label, value) => {
1447
+ if (typeof value.output === "string" || typeof value.text === "string" || typeof value.content === "string") {
1448
+ stringOutputField(label, value.output ?? value.text ?? value.content);
1449
+ return;
1450
+ }
1451
+ structuredField(label, value);
1452
+ };
1453
+ const outputField = (label, value) => {
1454
+ if (value === void 0) return;
1455
+ if (typeof value === "string") {
1456
+ stringOutputField(label, value);
1457
+ return;
1458
+ }
1459
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
1460
+ objectOutputField(label, value);
1461
+ return;
1462
+ }
1463
+ structuredField(label, value);
1464
+ };
1465
+ const coreCallPreview = (call) => {
1466
+ const settings = this.codePreviewSettings;
1467
+ const tool = call.ref.startsWith("omp.") ? call.ref.slice(4) : "";
1468
+ if (!settings || !["bash", "read", "write", "edit", "grep", "find", "ls"].includes(tool)) {
1469
+ return false;
1470
+ }
1471
+ const success = call.status === "completed" ? true : call.status === "failed" ? false : void 0;
1472
+ const audit = {
1473
+ ref: call.ref,
1474
+ provider: "omp",
1475
+ tool,
1476
+ ...call.args !== void 0 ? { args: call.args } : {},
1477
+ ...call.result !== void 0 ? { result: call.result } : {},
1478
+ ...call.preview !== void 0 ? { preview: call.preview } : {},
1479
+ ...success !== void 0 ? { success } : {},
1480
+ startedAt: call.startedAt,
1481
+ ...call.finishedAt !== void 0 ? { endedAt: call.finishedAt } : {}
1482
+ };
1483
+ const context = {
1484
+ cwd: this.snapshot().main.cwd ?? process.cwd(),
1485
+ settings,
1486
+ invalidate: this.highlightInvalidate
1487
+ };
1488
+ const title = coreToolTitle(audit, this.theme, context);
1489
+ const rendered = renderCoreToolBody(audit, this.theme, {
1490
+ ...context,
1491
+ expanded: true,
1492
+ maxLines: 200
1493
+ });
1494
+ if (!rendered) return false;
1495
+ lines.push(this.theme.fg("dim", "Preview:"));
1496
+ const body = renderBoundedLines(
1497
+ [...title ? [title] : [], ...rendered.lines],
1498
+ this.theme,
1499
+ settings.diffIntensity
1500
+ ).render(Math.max(1, width - 2));
1501
+ for (const row of body) lines.push(truncateToWidth2(` ${row}`, width, ""));
1502
+ if (rendered.hidden > 0) {
1503
+ lines.push(this.theme.fg("muted", ` \u2026 ${rendered.hidden} more lines`));
1504
+ }
1505
+ return true;
1506
+ };
1507
+ const argumentField = (call) => {
1508
+ const args = call.args;
1509
+ if (!args || Object.keys(args).length === 0) return;
1510
+ const stringValue = (key) => typeof args[key] === "string" ? args[key] : void 0;
1511
+ if (call.ref === "omp.bash") {
1512
+ const command = stringValue("command");
1513
+ if (command) {
1514
+ markdownField("Command", `\`\`\`bash
1515
+ ${command}
1516
+ \`\`\``, "command");
1517
+ }
1518
+ }
1519
+ const edits = Array.isArray(args.edits) ? args.edits : [];
1520
+ if (call.ref === "omp.edit" && edits.length > 0) {
1521
+ lines.push(this.theme.fg("dim", "Edits:"));
1522
+ const diff = nestedEditDiff(
1523
+ {
1524
+ ref: call.ref,
1525
+ tool: call.ref.split(".")[1] ?? call.ref,
1526
+ args
1527
+ },
1528
+ this.theme,
1529
+ this.highlightInvalidate
1530
+ );
1531
+ if (diff) {
1532
+ for (const line of diff) lines.push(truncateToWidth2(` ${line}`, width, ""));
1533
+ } else {
1534
+ structuredField("Edits", edits);
1535
+ }
1536
+ }
1537
+ const content = stringValue("content");
1538
+ if (call.ref === "omp.write" && content !== void 0) {
1539
+ const path2 = stringValue("path") ?? "";
1540
+ const extension = path2.includes(".") ? path2.split(".").at(-1) : "";
1541
+ markdownField("Content", "```" + (extension || "text") + "\n" + content + "\n```", "content");
1542
+ }
1543
+ const renderedKeys = /* @__PURE__ */ new Set(["command", "edits", "content"]);
1544
+ const remaining = Object.fromEntries(
1545
+ Object.entries(args).filter(([key]) => !renderedKeys.has(key))
1546
+ );
1547
+ if (Object.keys(remaining).length > 0) structuredField("Input", remaining);
1548
+ };
1549
+ field("Status", entity.status);
1550
+ if (entity.kind === "main") {
1551
+ const main = entity.value;
1552
+ field("ID", main.id);
1553
+ field("Scope", "user-facing OMP session");
1554
+ field("Runner", main.runner);
1555
+ field("Model", main.model);
1556
+ field("Thinking", main.thinking);
1557
+ field("Transport", main.transport);
1558
+ field("Session", main.sessionId);
1559
+ field("Working directory", main.cwd);
1560
+ field("Pending messages", main.pendingMessages ? "yes" : "no");
1561
+ field("Local owner", main.local ? "yes" : "no");
1562
+ field(
1563
+ "Elapsed",
1564
+ main.startedAt ? formatDuration(Math.max(0, now - main.startedAt)) : void 0
1565
+ );
1566
+ } else if (entity.kind === "peer") {
1567
+ const peer = entity.value;
1568
+ field("ID", peer.id);
1569
+ field("Scope", "concurrent root OMP session");
1570
+ field("Runner", peer.runner);
1571
+ field("Model", peer.model);
1572
+ field("Thinking", peer.thinking);
1573
+ field("Transport", peer.transport);
1574
+ field("Session", peer.sessionId);
1575
+ field("Working directory", peer.cwd);
1576
+ field("Pending messages", peer.pendingMessages ? "yes" : "no");
1577
+ field("Last heartbeat", new Date(peer.updatedAt).toLocaleString());
1578
+ field("Elapsed", formatDuration(Math.max(0, now - peer.startedAt)));
1579
+ } else if (entity.kind === "agent") {
1580
+ const agent = entity.value;
1581
+ field("ID", agent.id);
1582
+ field("Runner", agent.runner);
1583
+ field("Residency", agent.residency ?? "session");
1584
+ field("Model", agent.model);
1585
+ field("Thinking", agent.thinking);
1586
+ field("Transport", agent.transport);
1587
+ field("Activity", agent.currentTool);
1588
+ field("Elapsed", agent.startedAt ? formatDuration((agent.finishedAt ?? now) - agent.startedAt) : void 0);
1589
+ field("Usage", agent.usage ? `${formatTokens(agent.usage.input + agent.usage.output)} tokens \xB7 ${agent.toolCalls ?? 0} tools \xB7 ${agent.turns ?? 0} turns \xB7 $${agent.usage.cost.toFixed(4)}` : void 0);
1590
+ markdownField("Task", agent.task, "task");
1591
+ field("Branch", agent.branch);
1592
+ field("Worktree", agent.worktree);
1593
+ field("Attach", agent.attachCommand);
1594
+ field("Error", agent.error);
1595
+ markdownField("Result", agent.text, "result");
1596
+ structuredField("Value", agent.value);
1597
+ } else if (entity.kind === "actor") {
1598
+ const actor = entity.value;
1599
+ field("ID", actor.id);
1600
+ field("Runner", actor.runner);
1601
+ field("Residency", actor.residency ?? "session");
1602
+ field("Execution owner", actor.ownerHostId);
1603
+ field("Runtime", actor.local === false ? "remote shared owner" : "local owner");
1604
+ field("Session model", actor.binding?.model ?? "inherit project");
1605
+ field("Project model", actor.projectDefaults?.model ?? "inherit Fabric");
1606
+ field("Effective model", actor.model ?? "Fabric default");
1607
+ field("Active worker model", actor.worker?.model);
1608
+ field("Session thinking", actor.binding?.thinking ?? "inherit project");
1609
+ field("Project thinking", actor.projectDefaults?.thinking ?? "inherit Fabric");
1610
+ field("Effective reasoning", actor.thinking ?? "Fabric default");
1611
+ field("Active worker thinking", actor.worker?.thinking);
1612
+ field("Delivery", `${actor.delivery} \xB7 ${actor.responseMode}`);
1613
+ field("Trigger turn", actor.triggerTurn ? "yes" : "no");
1614
+ field("Activity", actor.worker?.currentTool);
1615
+ field("Transport", actor.worker?.transport);
1616
+ field(
1617
+ "Usage",
1618
+ actor.worker?.usage ? `${formatTokens(actor.worker.usage.input + actor.worker.usage.output)} tokens \xB7 ${actor.worker.toolCalls ?? 0} tools` : void 0
1619
+ );
1620
+ field("Host events", actor.events.join(", "));
1621
+ field("Tools", actor.tools?.join(", ") ?? `inherited (${this.actorDefaultTools.join(", ")})`);
1622
+ field("Topics", actor.topics.join(", "));
1623
+ field("Queue", actor.queued);
1624
+ field("Last error", actor.lastError);
1625
+ field("Instructions", actor.instructions);
1626
+ if (actor.recentMessages.length > 0) {
1627
+ lines.push("");
1628
+ lines.push(this.theme.fg("accent", "Recent mailbox"));
1629
+ for (const message of actor.recentMessages) {
1630
+ const text = message.text ?? message.error ?? message.action ?? formatActorDataPreview(message.data) ?? "data";
1631
+ field(
1632
+ `${message.direction === "in" ? "\u2192" : "\u2190"} ${formatClock(message.createdAt)} ${message.source}`,
1633
+ text
1634
+ );
1635
+ }
1636
+ }
1637
+ } else if (entity.kind === "call") {
1638
+ const call = entity.value;
1639
+ field("Reference", call.ref);
1640
+ field("ID", call.id);
1641
+ field("Kind", call.entityKind ?? call.kind);
1642
+ field("Progress", call.progress);
1643
+ field("Elapsed", formatDuration((call.finishedAt ?? now) - call.startedAt));
1644
+ field("Tokens", call.metrics?.tokens);
1645
+ field("Tool calls", call.metrics?.toolCalls);
1646
+ field("Cost", call.metrics?.cost);
1647
+ field("Entity", call.entityId);
1648
+ const renderedCorePreview = coreCallPreview(call);
1649
+ if (!renderedCorePreview) argumentField(call);
1650
+ field("Error", call.error);
1651
+ if (!renderedCorePreview) outputField("Output", call.result);
1652
+ } else if (entity.kind === "item") {
1653
+ const item = entity.value;
1654
+ field("ID", item.id);
1655
+ field("Kind", item.kind);
1656
+ field("Progress", item.total !== void 0 ? `${item.completed ?? 0}/${item.total}` : void 0);
1657
+ field("Current", item.current);
1658
+ field("Detail", item.detail);
1659
+ structuredField("Data", item.data);
1660
+ } else if (entity.kind === "globalActor") {
1661
+ const def = entity.value;
1662
+ field("Scope", "global template");
1663
+ field("ID", def.id);
1664
+ field("Runner", def.runner);
1665
+ field("Residency", def.residency ?? "session");
1666
+ field("Delivery", `${def.delivery} \xB7 ${def.responseMode}`);
1667
+ field("Model", def.model ?? "inherit");
1668
+ field("Thinking", def.thinking ?? "inherit");
1669
+ field("Host events", def.events.join(", "));
1670
+ field("Topics", def.topics.join(", "));
1671
+ field("Trigger turn", def.triggerTurn ? "yes" : "no");
1672
+ field("Coalesce", def.coalesce ? "yes" : "no");
1673
+ field("Created", new Date(def.createdAt).toLocaleString());
1674
+ field("Updated", new Date(def.updatedAt).toLocaleString());
1675
+ field("Instructions", def.instructions);
1676
+ } else if (entity.kind === "meshParticipant") {
1677
+ const participant = entity.value;
1678
+ const canonical = participant.participant;
1679
+ field("Scope", canonical ? `project ${canonical.kind}` : "observed mesh agent");
1680
+ field("Identity", participant.id);
1681
+ field("Root", canonical?.rootId);
1682
+ field("Parent", canonical?.parentId);
1683
+ field("Owner host", canonical?.ownerHostId);
1684
+ field("Owner identity", canonical?.ownerIdentityId);
1685
+ field("Residency", canonical?.residency ?? "session");
1686
+ field("Runner", canonical?.runner);
1687
+ field("Transport", canonical?.transport);
1688
+ field("Capabilities", canonical?.capabilities.join(", "));
1689
+ field("Local", canonical ? canonical.local ? "yes" : "no" : void 0);
1690
+ field("Observed routes", participant.routes);
1691
+ field("Last activity", new Date(participant.lastSeenAt).toLocaleString());
1692
+ field("Current work", canonical?.currentTool);
1693
+ } else if (entity.kind === "meshTopic") {
1694
+ const topic = entity.value;
1695
+ field("Scope", "project mesh topic");
1696
+ field("ID", topic.id);
1697
+ field("System topic", topic.system ? "yes" : "no");
1698
+ field("Subscribers", topic.subscribers.map((subscriber) => subscriber.name).join(", "));
1699
+ field("Recent events", topic.recentEvents);
1700
+ field(
1701
+ "Last activity",
1702
+ topic.lastEventAt ? new Date(topic.lastEventAt).toLocaleString() : void 0
1703
+ );
1704
+ } else if (entity.kind === "meshRoute") {
1705
+ const route = entity.value;
1706
+ field("Scope", "recent project mesh route");
1707
+ field("From", `${route.fromName} (${route.fromKind}:${route.fromId})`);
1708
+ field("To", `${route.targetName} (${route.targetKind}:${route.targetId})`);
1709
+ field("Topic", route.topic);
1710
+ field("Event kind", route.kind);
1711
+ field("Deliveries", route.count);
1712
+ field("Last activity", new Date(route.lastAt).toLocaleString());
1713
+ markdownField("Payload text", route.text, "route-text");
1714
+ } else if (entity.kind === "component") {
1715
+ const component = entity.value;
1716
+ field("Definition", component.component);
1717
+ field("Parent", component.parentId);
1718
+ field("Guarantee", component.guarantee);
1719
+ const componentEffects = component.effects ?? [];
1720
+ const visibleEffects = componentEffects.slice(0, 8).map(
1721
+ (effect) => `${effect.label}: ${effect.kind}/${effect.ordering} [${effect.resources.join(", ")}]`
1722
+ );
1723
+ if (componentEffects.length > visibleEffects.length) {
1724
+ visibleEffects.push(`+${componentEffects.length - visibleEffects.length} more`);
1725
+ }
1726
+ field("Effects", visibleEffects.join("; "));
1727
+ field("Effect conflicts", component.effectConflicts?.map(
1728
+ (conflict) => formatFabricEffectConflict(
1729
+ conflict.withComponent,
1730
+ conflict.resources,
1731
+ conflict.reason
1732
+ )
1733
+ ).join("; "));
1734
+ field("Requirements", component.requirements.join(", "));
1735
+ field("Provisions", component.provisions.join(", "));
1736
+ field("Missing", component.missing.join(", "));
1737
+ field("Optional missing", component.optionalMissing.join(", "));
1738
+ field("Target digest", component.targetDigest);
1739
+ field("Error", component.error);
1740
+ field("Updated", new Date(component.updatedAt).toLocaleString());
1741
+ } else {
1742
+ const entry = entity.value;
1743
+ field("Key", entry.key);
1744
+ field("Owner", entry.owner);
1745
+ field("Version", entry.version);
1746
+ field("Updated", new Date(entry.updatedAt).toLocaleString());
1747
+ field("Detail", entry.detail);
1748
+ const filePreview = loadStateFilePreview(entry, cwd);
1749
+ if (filePreview) {
1750
+ field("File", filePreview.path);
1751
+ lines.push(this.theme.fg("dim", "Preview:"));
1752
+ lines.push(...renderStateFilePreview(
1753
+ filePreview,
1754
+ this.theme,
1755
+ width,
1756
+ 120,
1757
+ this.highlightInvalidate
1758
+ ));
1759
+ }
1760
+ structuredField("Value", entry.value);
1761
+ }
1762
+ return lines.length > 0 ? lines : [this.theme.fg("dim", "No details")];
1763
+ }
1764
+ renderNarrowDetail(width, snapshot, entity) {
1765
+ const transcriptView = (entity.kind === "agent" || entity.kind === "actor") && this.detailView === "transcript";
1766
+ const content = transcriptView ? this.transcriptLines(entity, width) : this.detailLines(entity, width, snapshot.now, snapshot.main.cwd ?? process.cwd());
1767
+ const terminalRows = this.tui.terminal?.rows ?? process.stdout.rows ?? 28;
1768
+ const maxBody = Math.max(1, terminalRows - 2);
1769
+ this.detailMaxScroll = Math.max(0, content.length - maxBody);
1770
+ if (transcriptView && this.transcriptFollowing) {
1771
+ this.detailScroll = this.detailMaxScroll;
1772
+ } else if (transcriptView && this.transcriptPageAnchor) {
1773
+ this.detailScroll = this.transcriptPageAnchor === "end" ? this.detailMaxScroll : 0;
1774
+ this.transcriptPageAnchor = void 0;
1775
+ } else {
1776
+ this.detailScroll = Math.max(0, Math.min(this.detailScroll, this.detailMaxScroll));
1777
+ }
1778
+ const title = `${entity.label}${transcriptView ? " \xB7 transcript" : ""}`;
1779
+ const hint = transcriptView ? `${this.transcriptToolToggleHint()} \xB7 g page top \xB7 G follow:${this.transcriptFollowing ? "on" : "off"}/tail \xB7 t summary \xB7 esc` : `${this.hasTranscript(entity) ? "t transcript \xB7 " : ""}esc`;
1780
+ return [title, ...content.slice(this.detailScroll, this.detailScroll + maxBody), hint].map((line) => truncateToWidth2(line, width, "")).filter((line) => visibleWidth2(line) > 0);
1781
+ }
1782
+ topBorder(width, title) {
1783
+ const border = (value) => this.theme.fg("borderMuted", value);
1784
+ const safeTitle = truncateToWidth2(safeText(title), Math.max(0, width - 6));
1785
+ const styledTitle = ` ${this.theme.fg("accent", safeTitle)} `;
1786
+ const remaining = Math.max(0, width - 2 - visibleWidth2(styledTitle));
1787
+ const left = Math.floor(remaining / 2);
1788
+ const right = remaining - left;
1789
+ return `${border(`\u256D${"\u2500".repeat(left)}`)}${styledTitle}${border(`${"\u2500".repeat(right)}\u256E`)}`;
1790
+ }
1791
+ middleBorder(width) {
1792
+ return this.theme.fg("borderMuted", `\u251C${"\u2500".repeat(Math.max(0, width - 2))}\u2524`);
1793
+ }
1794
+ bottomBorder(width) {
1795
+ return this.theme.fg("borderMuted", `\u2570${"\u2500".repeat(Math.max(0, width - 2))}\u256F`);
1796
+ }
1797
+ row(width, content) {
1798
+ const innerWidth = Math.max(0, width - 2);
1799
+ return `${this.theme.fg("borderMuted", "\u2502")}${padToWidth(content, innerWidth)}${this.theme.fg(
1800
+ "borderMuted",
1801
+ "\u2502"
1802
+ )}`;
1803
+ }
1804
+ };
1805
+
1806
+ // src/ui/dashboard-fabric-graph.ts
1807
+ import { Ellipsis as Ellipsis2 } from "@oh-my-pi/pi-tui";
1808
+ import { truncateToWidth as truncateToWidth3, visibleWidth as visibleWidth3 } from "@oh-my-pi/pi-tui";
1809
+ var kindRank = {
1810
+ agent: 0,
1811
+ actor: 1,
1812
+ participant: 2,
1813
+ component: 3,
1814
+ peer: 4,
1815
+ group: 5,
1816
+ topic: 6,
1817
+ state: 7,
1818
+ route: 8,
1819
+ main: 9
1820
+ };
1821
+ var activeRank = (status) => isActiveStatus(status) && status !== "blocked" ? 0 : status === "blocked" ? 1 : 2;
1822
+ var nodeKind = (entity) => {
1823
+ if (entity.kind === "component") return "component";
1824
+ if (entity.kind === "meshParticipant") return "participant";
1825
+ if (entity.kind === "meshTopic") return "topic";
1826
+ if (entity.kind === "meshRoute") return "route";
1827
+ if (entity.kind === "globalActor" || entity.kind === "call" || entity.kind === "item") {
1828
+ return "state";
1829
+ }
1830
+ return entity.kind;
1831
+ };
1832
+ var rawIdentity = (entity) => {
1833
+ if (entity.kind === "main" || entity.kind === "peer" || entity.kind === "agent" || entity.kind === "actor") {
1834
+ return [entity.value.id, entity.value.name];
1835
+ }
1836
+ if (entity.kind === "meshParticipant") {
1837
+ return [entity.value.id, entity.value.name, entity.value.participant?.sessionId];
1838
+ }
1839
+ if (entity.kind === "meshTopic") return [entity.value.id, entity.value.name];
1840
+ if (entity.kind === "state") return [entity.value.key, entity.value.label];
1841
+ if (entity.kind === "meshRoute") return [entity.value.id];
1842
+ if (entity.kind === "component") {
1843
+ return [entity.value.id, entity.id];
1844
+ }
1845
+ return [entity.id, entity.label];
1846
+ };
1847
+ var graphLabel = (value, maxWidth) => {
1848
+ let output = "";
1849
+ let width = 0;
1850
+ for (const char of value) {
1851
+ const charWidth = visibleWidth3(char);
1852
+ if (width + charWidth > maxWidth) {
1853
+ while (width + 1 > maxWidth && output.length > 0) {
1854
+ const parts = [...output];
1855
+ const removed = parts.pop();
1856
+ output = parts.join("");
1857
+ width -= removed ? visibleWidth3(removed) : 0;
1858
+ }
1859
+ return output + "\u2026";
1860
+ }
1861
+ output += char;
1862
+ width += charWidth;
1863
+ }
1864
+ return output;
1865
+ };
1866
+ var graphGlyph = (node, animation) => {
1867
+ if (node.stale) return animation.reducedMotion ? "\xB7" : ["\u25A7", "\u25AB", "\xB7", " "][Math.floor(animation.now / 240) % 4];
1868
+ const frame = Math.floor(animation.now / 160);
1869
+ const active = isActiveStatus(node.status);
1870
+ if (node.kind === "main") return active && !animation.reducedMotion ? ["\u25C7", "\u25C8", "\u25C6", "\u25C8"][frame % 4] : "\u25C6";
1871
+ if (node.kind === "actor") {
1872
+ if ((node.queued ?? 0) > 0 && !animation.reducedMotion) return ["\u25C7", "\u25C8", "\u25C6", "\u25C8"][frame % 4];
1873
+ return "\u25C7";
1874
+ }
1875
+ if (node.kind === "peer") return "\u25C8";
1876
+ if (node.kind === "group") return "\u25B1";
1877
+ if (node.kind === "topic") {
1878
+ const hot = node.activityAt !== void 0 && animation.now - node.activityAt <= 1e4;
1879
+ return hot && !animation.reducedMotion ? ["\u25CE", "\u25C9", "\u29BF", "\u25C9"][frame % 4] : "\u25CE";
1880
+ }
1881
+ if (node.kind === "state") {
1882
+ if (/certified|committed|complete/.test(node.status) && !animation.reducedMotion) {
1883
+ return ["\u25EB", "\u25A3", "\u2726", "\u25A3"][Math.floor(animation.now / 280) % 4];
1884
+ }
1885
+ return "\u25EB";
1886
+ }
1887
+ if (node.kind === "participant") return "\u25A7";
1888
+ if (node.kind === "component") return "\u2B21";
1889
+ if (node.kind === "agent" && !animation.reducedMotion) {
1890
+ const spawnAge = node.startedAt === void 0 ? Number.POSITIVE_INFINITY : animation.now - node.startedAt;
1891
+ if (spawnAge >= 0 && spawnAge <= 1600) {
1892
+ return ["\xB7", "\u25AA", "\u25AB", "\u25A3", "\u25A0"][Math.min(4, Math.floor(spawnAge / 320))];
1893
+ }
1894
+ if (active) return ["\u25A0", "\u25A3", "\u25AA", "\u25A3"][frame % 4];
1895
+ }
1896
+ return "\u25A0";
1897
+ };
1898
+ var PARTICIPANTS_GROUP_ID = "group:participants";
1899
+ var MESH_GROUP_ID = "group:mesh";
1900
+ var TOPICS_GROUP_ID = "group:mesh:topics";
1901
+ var STATE_GROUP_ID = "group:mesh:state";
1902
+ var COMPONENTS_GROUP_ID = "group:components";
1903
+ var topologyParticipantGroup = (kind) => {
1904
+ if (kind === "actor") return { id: "actors", label: "Actors", order: 2 };
1905
+ if (kind === "agent") return { id: "agents", label: "Agents", order: 1 };
1906
+ return { id: "sessions", label: "Sessions", order: 0 };
1907
+ };
1908
+ var titleSegment = (value) => value.length === 0 ? value : value[0].toUpperCase() + value.slice(1);
1909
+ var namespaceParts = (value) => value.split(/[.:/]+/).map((part) => part.trim()).filter(Boolean);
1910
+ var topologyTopicGroupPath = (name) => {
1911
+ const parts = namespaceParts(name);
1912
+ if (parts[0] === "fabric") {
1913
+ return [
1914
+ { id: "fabric", label: "Fabric" },
1915
+ ...parts.length > 2 && parts[1] ? [{ id: `fabric:${parts[1]}`, label: titleSegment(parts[1]) }] : []
1916
+ ];
1917
+ }
1918
+ return [
1919
+ { id: "project", label: "Project topics" },
1920
+ ...parts.length > 1 && parts[0] ? [{ id: `project:${parts[0]}`, label: parts[0] }] : []
1921
+ ];
1922
+ };
1923
+ var topologyStateGroupPath = (key) => {
1924
+ const parts = key.split("/").map((part) => part.trim()).filter(Boolean);
1925
+ if (parts[0] === "state") {
1926
+ const path3 = [{ id: "world", label: "World state" }];
1927
+ if (parts[1] === "complexity") {
1928
+ let prefix2 = "world:complexity";
1929
+ path3.push({ id: prefix2, label: "Complexity" });
1930
+ for (const directory of parts.slice(2, -1)) {
1931
+ prefix2 += `:${directory}`;
1932
+ path3.push({ id: prefix2, label: directory });
1933
+ }
1934
+ } else {
1935
+ let prefix2 = "world";
1936
+ for (const directory of parts.slice(1, -1)) {
1937
+ prefix2 += `:${directory}`;
1938
+ path3.push({ id: prefix2, label: titleSegment(directory) });
1939
+ }
1940
+ }
1941
+ return path3;
1942
+ }
1943
+ if (parts[0] === "schema") {
1944
+ const path3 = [{ id: "schema", label: "Schema" }];
1945
+ const family = parts[1];
1946
+ if (family === "hypothesis") path3.push({ id: "schema:hypotheses", label: "Hypotheses" });
1947
+ else if (family === "certificate") path3.push({ id: "schema:certificates", label: "Certificates" });
1948
+ else {
1949
+ let prefix2 = "schema";
1950
+ for (const directory of parts.slice(1, -1)) {
1951
+ prefix2 += `:${directory}`;
1952
+ path3.push({ id: prefix2, label: titleSegment(directory) });
1953
+ }
1954
+ }
1955
+ return path3;
1956
+ }
1957
+ const path2 = [{ id: "project", label: "Project state" }];
1958
+ let prefix = "project";
1959
+ for (const directory of parts.slice(0, -1)) {
1960
+ prefix += `:${directory}`;
1961
+ path2.push({ id: prefix, label: directory });
1962
+ }
1963
+ return path2;
1964
+ };
1965
+ var parentReference = (entity) => {
1966
+ if (entity.kind === "agent") return entity.value.parentId ?? entity.value.actorId;
1967
+ if (entity.kind === "meshParticipant") return entity.value.participant?.parentId;
1968
+ if (entity.kind === "meshRoute") return entity.value.fromId;
1969
+ return void 0;
1970
+ };
1971
+ var buildLayout = (snapshot, entities, selectedRun, mesh) => {
1972
+ const aliases = /* @__PURE__ */ new Map();
1973
+ const entityById = new Map(entities.map((entity) => [entity.id, entity]));
1974
+ for (const entity of entities) {
1975
+ for (const identity of rawIdentity(entity)) {
1976
+ if (identity) aliases.set(identity, entity.id);
1977
+ }
1978
+ }
1979
+ const mainId = entities.find((entity) => entity.kind === "main")?.id ?? `main:${snapshot.main.id}`;
1980
+ aliases.set(snapshot.main.id, mainId);
1981
+ aliases.set(snapshot.main.name, mainId);
1982
+ aliases.set("main", mainId);
1983
+ const groups = /* @__PURE__ */ new Map();
1984
+ const ensureGroup = (id, label, parentId, order) => {
1985
+ if (!groups.has(id)) {
1986
+ groups.set(id, {
1987
+ id,
1988
+ label,
1989
+ status: "idle",
1990
+ kind: "group",
1991
+ parentId,
1992
+ order,
1993
+ x: 0,
1994
+ y: 0
1995
+ });
1996
+ }
1997
+ return id;
1998
+ };
1999
+ const ensurePath = (rootId, path2) => {
2000
+ let parentId = rootId;
2001
+ for (let index = 0; index < path2.length; index++) {
2002
+ const segment = path2[index];
2003
+ const id = `${rootId}:${segment.id}`;
2004
+ parentId = ensureGroup(id, segment.label, parentId, index);
2005
+ }
2006
+ return parentId;
2007
+ };
2008
+ const participantCategory = (entity) => {
2009
+ if (entity.kind === "actor") return topologyParticipantGroup("actor");
2010
+ if (entity.kind === "agent") return topologyParticipantGroup("agent");
2011
+ if (entity.kind === "peer") return topologyParticipantGroup("peer");
2012
+ return topologyParticipantGroup(
2013
+ entity.kind === "meshParticipant" ? entity.value.participant?.kind ?? "root" : "root"
2014
+ );
2015
+ };
2016
+ const nodes = entities.filter((entity) => entity.kind !== "meshRoute").map((entity) => {
2017
+ const parentRef = parentReference(entity);
2018
+ const explicitParentId = parentRef ? aliases.get(parentRef) : void 0;
2019
+ let parentId = explicitParentId;
2020
+ if (entity.kind !== "main") {
2021
+ if (entity.kind === "component") {
2022
+ parentId = ensureGroup(COMPONENTS_GROUP_ID, "Components", mainId, 2);
2023
+ } else if (["agent", "actor", "peer", "meshParticipant"].includes(entity.kind) && (!parentId || parentId === mainId)) {
2024
+ ensureGroup(PARTICIPANTS_GROUP_ID, "Participants", mainId, 0);
2025
+ const category = participantCategory(entity);
2026
+ parentId = ensureGroup(
2027
+ `${PARTICIPANTS_GROUP_ID}:${category.id}`,
2028
+ category.label,
2029
+ PARTICIPANTS_GROUP_ID,
2030
+ category.order
2031
+ );
2032
+ } else if (entity.kind === "meshTopic") {
2033
+ ensureGroup(MESH_GROUP_ID, "Mesh", mainId, 1);
2034
+ ensureGroup(TOPICS_GROUP_ID, "Topics", MESH_GROUP_ID, 0);
2035
+ parentId = ensurePath(TOPICS_GROUP_ID, topologyTopicGroupPath(entity.value.name));
2036
+ } else if (entity.kind === "state") {
2037
+ ensureGroup(MESH_GROUP_ID, "Mesh", mainId, 1);
2038
+ ensureGroup(STATE_GROUP_ID, "State", MESH_GROUP_ID, 1);
2039
+ parentId = ensurePath(STATE_GROUP_ID, topologyStateGroupPath(entity.value.key));
2040
+ } else if (!parentId) {
2041
+ parentId = mainId;
2042
+ }
2043
+ }
2044
+ const activityAt = entity.kind === "meshTopic" ? entity.value.lastEventAt : void 0;
2045
+ const startedAt = entity.kind === "agent" ? entity.value.startedAt : void 0;
2046
+ const queued = entity.kind === "actor" ? entity.value.queued : void 0;
2047
+ const stale = entity.kind === "meshParticipant" ? entity.value.participant?.stale : entity.kind === "agent" ? entity.value.stale : void 0;
2048
+ return {
2049
+ id: entity.id,
2050
+ label: entity.kind === "main" ? "Main" : entity.kind === "state" && entity.value.label === entity.value.key ? entity.value.key.split("/").at(-1) ?? entity.value.label : entity.label,
2051
+ status: entity.status,
2052
+ kind: nodeKind(entity),
2053
+ ...parentId ? { parentId } : {},
2054
+ ...activityAt !== void 0 ? { activityAt } : {},
2055
+ ...startedAt !== void 0 ? { startedAt } : {},
2056
+ ...queued !== void 0 ? { queued } : {},
2057
+ ...stale !== void 0 ? { stale } : {},
2058
+ x: 0,
2059
+ y: 0
2060
+ };
2061
+ });
2062
+ nodes.push(...groups.values());
2063
+ const nodeById = new Map(nodes.map((node) => [node.id, node]));
2064
+ const children = /* @__PURE__ */ new Map();
2065
+ for (const node of nodes) {
2066
+ if (!node.parentId || node.parentId === node.id || !nodeById.has(node.parentId)) continue;
2067
+ const bucket = children.get(node.parentId) ?? [];
2068
+ bucket.push(node);
2069
+ children.set(node.parentId, bucket);
2070
+ }
2071
+ const inSelectedRun = (node) => {
2072
+ const entity = entityById.get(node.id);
2073
+ return Boolean(selectedRun && entity?.kind === "agent" && entity.value.runId === selectedRun.id);
2074
+ };
2075
+ for (const bucket of children.values()) {
2076
+ bucket.sort(
2077
+ (left, right) => activeRank(left.status) - activeRank(right.status) || Number(inSelectedRun(right)) - Number(inSelectedRun(left)) || (left.order ?? 0) - (right.order ?? 0) || kindRank[left.kind] - kindRank[right.kind] || left.label.localeCompare(right.label)
2078
+ );
2079
+ }
2080
+ let nextLeafY = 0;
2081
+ const visited = /* @__PURE__ */ new Set();
2082
+ const place = (node, depth) => {
2083
+ if (visited.has(node.id)) return node.y;
2084
+ visited.add(node.id);
2085
+ node.x = depth * 20;
2086
+ const descendants = (children.get(node.id) ?? []).filter((child) => !visited.has(child.id));
2087
+ if (descendants.length === 0) {
2088
+ node.y = nextLeafY;
2089
+ nextLeafY += 2;
2090
+ return node.y;
2091
+ }
2092
+ const childRows = descendants.map((child) => place(child, depth + 1));
2093
+ node.y = (childRows[0] + childRows[childRows.length - 1]) / 2;
2094
+ return node.y;
2095
+ };
2096
+ const main = nodeById.get(mainId);
2097
+ if (main) place(main, 0);
2098
+ for (const node of nodes) {
2099
+ if (!visited.has(node.id)) place(node, 1);
2100
+ }
2101
+ const mainY = main?.y ?? 0;
2102
+ for (const node of nodes) node.y = Math.round(node.y - mainY);
2103
+ const edges = [];
2104
+ for (const node of nodes) {
2105
+ if (node.parentId && nodeById.has(node.parentId) && node.parentId !== node.id) {
2106
+ edges.push({ from: node.parentId, to: node.id, kind: node.kind === "route" ? "route" : "structure" });
2107
+ }
2108
+ }
2109
+ for (const topic of mesh.topics) {
2110
+ const target = aliases.get(topic.id) ?? aliases.get(topic.name);
2111
+ if (!target) continue;
2112
+ for (const subscriber of topic.subscribers) {
2113
+ const source = aliases.get(subscriber.id) ?? aliases.get(subscriber.name);
2114
+ if (source && source !== target) edges.push({ from: source, to: target, kind: "subscription" });
2115
+ }
2116
+ }
2117
+ for (const entity of entities) {
2118
+ if (entity.kind !== "state" || !entity.value.owner) continue;
2119
+ const owner = aliases.get(entity.value.owner);
2120
+ const target = aliases.get(entity.value.key) ?? aliases.get(entity.value.label);
2121
+ if (owner && target && owner !== target) {
2122
+ edges.push({ from: owner, to: target, kind: "subscription" });
2123
+ }
2124
+ }
2125
+ for (const dependency of snapshot.componentGraph.edges) {
2126
+ const source = aliases.get(dependency.from);
2127
+ const target = aliases.get(dependency.to);
2128
+ if (source && target && source !== target) {
2129
+ edges.push({ from: source, to: target, kind: "subscription" });
2130
+ }
2131
+ }
2132
+ for (const route of mesh.routes) {
2133
+ const source = aliases.get(route.fromId) ?? aliases.get(route.fromName);
2134
+ const target = aliases.get(route.targetId) ?? aliases.get(route.targetName) ?? aliases.get(route.topic);
2135
+ if (source && target && source !== target) {
2136
+ edges.push({ from: source, to: target, kind: "route", route });
2137
+ }
2138
+ }
2139
+ const positions = new Map(nodes.map((node) => [node.id, { x: node.x, y: node.y }]));
2140
+ for (const edge of edges) {
2141
+ if (!edge.route) continue;
2142
+ const from = nodeById.get(edge.from);
2143
+ const to = nodeById.get(edge.to);
2144
+ if (!from || !to) continue;
2145
+ positions.set(edge.route.id, {
2146
+ x: Math.round((from.x + to.x) / 2),
2147
+ y: Math.round((from.y + to.y) / 2)
2148
+ });
2149
+ }
2150
+ return { nodes, edges, positions };
2151
+ };
2152
+ var lineChar = (mask) => {
2153
+ const chars = {
2154
+ 1: "\u2502",
2155
+ 2: "\u2500",
2156
+ 3: "\u2514",
2157
+ 4: "\u2502",
2158
+ 5: "\u2502",
2159
+ 6: "\u250C",
2160
+ 7: "\u251C",
2161
+ 8: "\u2500",
2162
+ 9: "\u2518",
2163
+ 10: "\u2500",
2164
+ 11: "\u2534",
2165
+ 12: "\u2510",
2166
+ 13: "\u2524",
2167
+ 14: "\u252C",
2168
+ 15: "\u253C"
2169
+ };
2170
+ return chars[mask] ?? "\xB7";
2171
+ };
2172
+ var styleForStatus = (status) => {
2173
+ if (["failed", "timed_out", "error", "quarantined"].includes(status)) return "error";
2174
+ if (["blocked", "waiting"].includes(status)) return "warning";
2175
+ if (isActiveStatus(status)) return "success";
2176
+ return "dim";
2177
+ };
2178
+ var topologyTreeRouteNodeIds = (nodes, fromId, toId) => {
2179
+ if (fromId === toId) return [fromId];
2180
+ const ancestry = (start) => {
2181
+ const path2 = [];
2182
+ const seen = /* @__PURE__ */ new Set();
2183
+ let current = start;
2184
+ while (current && !seen.has(current)) {
2185
+ path2.push(current);
2186
+ seen.add(current);
2187
+ current = nodes.get(current)?.parentId;
2188
+ }
2189
+ return path2;
2190
+ };
2191
+ const fromAncestors = ancestry(fromId);
2192
+ const fromSet = new Set(fromAncestors);
2193
+ const toAncestors = ancestry(toId);
2194
+ const common = toAncestors.find((id) => fromSet.has(id));
2195
+ if (!common) return [fromId, toId];
2196
+ return [
2197
+ ...fromAncestors.slice(0, fromAncestors.indexOf(common) + 1),
2198
+ ...toAncestors.slice(0, toAncestors.indexOf(common)).reverse()
2199
+ ];
2200
+ };
2201
+ var routeGlyph = (route) => {
2202
+ if (route.status === "failed") return "!";
2203
+ const kind = route.kind.toLowerCase();
2204
+ if (kind.includes("certif")) return "\u2726";
2205
+ if (kind.includes("commit")) return "\u25C6";
2206
+ if (kind.includes("control") || kind.includes("steer")) return "\u21AF";
2207
+ if (kind.includes("message") || kind.includes("directive")) return "\u2709";
2208
+ return "\u2022";
2209
+ };
2210
+ var routeStyle = (route) => route.status === "failed" ? "error" : route.kind.toLowerCase().includes("certif") ? "warning" : "accent";
2211
+ var renderCanvas = (theme, layout, selectedEntityId, width, height, camera, animation) => {
2212
+ const originX = Math.round(camera.x - width / 2);
2213
+ const originY = Math.round(camera.y - height / 2);
2214
+ const cells = Array.from(
2215
+ { length: height },
2216
+ () => Array.from({ length: width }, () => ({ char: " ", style: "plain" }))
2217
+ );
2218
+ const masks = Array.from({ length: height }, () => Array(width).fill(0));
2219
+ const nodeById = new Map(layout.nodes.map((node) => [node.id, node]));
2220
+ const selectedRoute = layout.edges.find((edge) => edge.route?.id === selectedEntityId)?.route;
2221
+ const related = new Set(selectedEntityId ? [selectedEntityId] : []);
2222
+ for (const edge of layout.edges) {
2223
+ if (edge.from === selectedEntityId || edge.to === selectedEntityId || edge.route?.id === selectedEntityId) {
2224
+ related.add(edge.from);
2225
+ related.add(edge.to);
2226
+ if (edge.route) related.add(edge.route.id);
2227
+ }
2228
+ }
2229
+ const setCell = (x, y, char, style) => {
2230
+ const sx = x - originX;
2231
+ const sy = y - originY;
2232
+ if (sx < 0 || sx >= width || sy < 0 || sy >= height) return;
2233
+ cells[sy][sx] = { char, style };
2234
+ };
2235
+ const addMask = (x, y, mask) => {
2236
+ const sx = x - originX;
2237
+ const sy = y - originY;
2238
+ if (sx < 0 || sx >= width || sy < 0 || sy >= height) return;
2239
+ masks[sy][sx] = (masks[sy][sx] ?? 0) | mask;
2240
+ };
2241
+ const horizontal = (x1, x2, y) => {
2242
+ if (y < originY || y >= originY + height) return;
2243
+ const worldStart = Math.min(x1, x2);
2244
+ const worldEnd = Math.max(x1, x2);
2245
+ const start = Math.max(worldStart, originX);
2246
+ const end = Math.min(worldEnd, originX + width - 1);
2247
+ for (let x = start; x <= end; x++) {
2248
+ addMask(x, y, (x > worldStart ? 8 : 0) | (x < worldEnd ? 2 : 0));
2249
+ }
2250
+ };
2251
+ const vertical = (x, y1, y2) => {
2252
+ if (x < originX || x >= originX + width) return;
2253
+ const worldStart = Math.min(y1, y2);
2254
+ const worldEnd = Math.max(y1, y2);
2255
+ const start = Math.max(worldStart, originY);
2256
+ const end = Math.min(worldEnd, originY + height - 1);
2257
+ for (let y = start; y <= end; y++) {
2258
+ addMask(x, y, (y > worldStart ? 1 : 0) | (y < worldEnd ? 4 : 0));
2259
+ }
2260
+ };
2261
+ const edgePathPoints = (from, to) => {
2262
+ const fromEnd = from.x + Math.min(16, visibleWidth3(safeText(from.label)) + 3);
2263
+ const toStart = to.x - 2;
2264
+ const bend = Math.max(fromEnd + 1, Math.floor((fromEnd + toStart) / 2));
2265
+ const points = [];
2266
+ const appendLine = (x1, y1, x2, y2) => {
2267
+ const dx = Math.sign(x2 - x1);
2268
+ const dy = Math.sign(y2 - y1);
2269
+ const steps = Math.max(Math.abs(x2 - x1), Math.abs(y2 - y1));
2270
+ for (let step = points.length === 0 ? 0 : 1; step <= steps; step++) {
2271
+ points.push({ x: x1 + dx * step, y: y1 + dy * step });
2272
+ }
2273
+ };
2274
+ appendLine(fromEnd, from.y, bend, from.y);
2275
+ appendLine(bend, from.y, bend, to.y);
2276
+ appendLine(bend, to.y, toStart, to.y);
2277
+ return points;
2278
+ };
2279
+ const treePathPoints = (from, to) => {
2280
+ const ids = topologyTreeRouteNodeIds(nodeById, from.id, to.id);
2281
+ const points = [];
2282
+ for (let index = 0; index < ids.length - 1; index++) {
2283
+ const left = nodeById.get(ids[index]);
2284
+ const right = nodeById.get(ids[index + 1]);
2285
+ if (!left || !right) continue;
2286
+ const segment = right.parentId === left.id ? edgePathPoints(left, right) : left.parentId === right.id ? edgePathPoints(right, left).reverse() : edgePathPoints(left, right);
2287
+ const previous = points.at(-1);
2288
+ const first = segment[0];
2289
+ if (previous && first && previous.x === first.x && previous.y === first.y) segment.shift();
2290
+ points.push(...segment);
2291
+ }
2292
+ return points;
2293
+ };
2294
+ for (const edge of layout.edges) {
2295
+ if (edge.kind !== "structure") continue;
2296
+ const from = nodeById.get(edge.from);
2297
+ const to = nodeById.get(edge.to);
2298
+ if (!from || !to) continue;
2299
+ const fromEnd = from.x + Math.min(16, visibleWidth3(safeText(from.label)) + 3);
2300
+ const toStart = to.x - 2;
2301
+ const bend = Math.max(fromEnd + 1, Math.floor((fromEnd + toStart) / 2));
2302
+ horizontal(fromEnd, bend, from.y);
2303
+ vertical(bend, from.y, to.y);
2304
+ horizontal(bend, toStart, to.y);
2305
+ }
2306
+ for (let y = 0; y < height; y++) {
2307
+ for (let x = 0; x < width; x++) {
2308
+ const mask = masks[y]?.[x] ?? 0;
2309
+ if (mask) cells[y][x] = { char: lineChar(mask), style: "edge" };
2310
+ }
2311
+ }
2312
+ const traffic = /* @__PURE__ */ new Map();
2313
+ for (const edge of layout.edges) {
2314
+ if (edge.kind === "structure") continue;
2315
+ const from = nodeById.get(edge.from);
2316
+ const to = nodeById.get(edge.to);
2317
+ if (!from || !to) continue;
2318
+ if (!edge.route) {
2319
+ if (edge.from !== selectedEntityId && edge.to !== selectedEntityId) continue;
2320
+ const points = treePathPoints(from, to);
2321
+ for (let index = 0; index < points.length; index += 2) {
2322
+ const point = points[index];
2323
+ setCell(point.x, point.y, "\xB7", "accent");
2324
+ }
2325
+ continue;
2326
+ }
2327
+ const key = `${edge.from}\0${edge.to}`;
2328
+ const group = traffic.get(key) ?? { from, to, routes: [] };
2329
+ group.routes.push(edge.route);
2330
+ traffic.set(key, group);
2331
+ }
2332
+ for (const group of traffic.values()) {
2333
+ const points = treePathPoints(group.from, group.to);
2334
+ if (points.length === 0) continue;
2335
+ const selected = group.routes.find((route2) => route2.id === selectedEntityId);
2336
+ const replay = group.routes.find((route2) => route2.id === animation.replayRouteId);
2337
+ const newest = group.routes.reduce((latest, route2) => route2.lastAt > latest.lastAt ? route2 : latest);
2338
+ const route = replay ?? selected ?? newest;
2339
+ const age = Math.max(0, animation.now - route.lastAt);
2340
+ const connected = group.from.id === selectedEntityId || group.to.id === selectedEntityId;
2341
+ const visible = Boolean(replay || selected || connected || animation.showHistory || age <= 6e4);
2342
+ if (!visible) continue;
2343
+ const fresh = Boolean(replay || age <= 1e4);
2344
+ const style = selected || replay ? routeStyle(route) : fresh ? "accent" : "dim";
2345
+ const stride = fresh ? 1 : 2;
2346
+ for (let index = 0; index < points.length; index += stride) {
2347
+ const point = points[index];
2348
+ const trail = fresh && !animation.reducedMotion && index % 3 === 0 ? "\u2501" : fresh ? "\xB7" : "\u254C";
2349
+ setCell(point.x, point.y, trail, style);
2350
+ }
2351
+ const packetActive = !animation.reducedMotion && Boolean(replay || age <= 2e3);
2352
+ if (packetActive) {
2353
+ const duration = 1200;
2354
+ const phase = replay ? animation.now % duration / duration : Math.min(0.999, age / 2e3);
2355
+ const packetIndex = Math.min(points.length - 1, Math.floor(phase * points.length));
2356
+ const point = points[packetIndex];
2357
+ setCell(point.x, point.y, routeGlyph(route), routeStyle(route));
2358
+ if (route.kind.toLowerCase().includes("certif")) {
2359
+ const ripple = points[Math.max(0, points.length - 1 - packetIndex)];
2360
+ setCell(ripple.x, ripple.y, "\u2726", "warning");
2361
+ } else if (route.status === "failed") {
2362
+ const impact = points.at(-1);
2363
+ setCell(impact.x, impact.y, Math.floor(animation.now / 120) % 2 === 0 ? "\u2573" : "!", "error");
2364
+ }
2365
+ const label = graphLabel(animation.replayLabel ?? route.kind, 18);
2366
+ let offset = 2;
2367
+ for (const char of label) {
2368
+ setCell(point.x + offset, point.y, char, routeStyle(route));
2369
+ offset += visibleWidth3(char);
2370
+ }
2371
+ } else {
2372
+ const count = group.routes.reduce((total, candidate) => total + candidate.count, 0);
2373
+ if (count > 1) {
2374
+ const point = points[Math.floor(points.length / 2)];
2375
+ const label = `\xD7${count}`;
2376
+ for (let index = 0; index < label.length; index++) {
2377
+ setCell(point.x + index, point.y, label[index], style);
2378
+ }
2379
+ }
2380
+ }
2381
+ }
2382
+ for (const node of layout.nodes) {
2383
+ const selected = node.id === selectedEntityId;
2384
+ const spotlighted = !selectedRoute || related.has(node.id);
2385
+ const glyph = selected ? "\u25A3" : graphGlyph(node, animation);
2386
+ const label = graphLabel(safeText(node.label), 14);
2387
+ const nodeStyle = selected ? "accent" : !spotlighted ? "dim" : styleForStatus(node.status);
2388
+ setCell(node.x, node.y, glyph, nodeStyle);
2389
+ setCell(node.x + 1, node.y, " ", "plain");
2390
+ let offset = 0;
2391
+ for (const char of label) {
2392
+ setCell(node.x + 2 + offset, node.y, char, selected ? "accent" : spotlighted ? "muted" : "dim");
2393
+ offset += visibleWidth3(char);
2394
+ }
2395
+ }
2396
+ const apply = (style, value) => {
2397
+ if (style === "edge") return theme.fg("borderMuted", value);
2398
+ if (style === "dim") return theme.fg("dim", value);
2399
+ if (style === "muted") return theme.fg("muted", value);
2400
+ if (style === "accent") return theme.fg("accent", theme.bold(value));
2401
+ if (style === "success") return theme.fg("success", value);
2402
+ if (style === "warning") return theme.fg("warning", value);
2403
+ if (style === "error") return theme.fg("error", value);
2404
+ return value;
2405
+ };
2406
+ return cells.map((row) => {
2407
+ let rendered = "";
2408
+ let style = row[0]?.style ?? "plain";
2409
+ let run = "";
2410
+ for (const cell of row) {
2411
+ if (cell.style !== style) {
2412
+ rendered += apply(style, run);
2413
+ style = cell.style;
2414
+ run = "";
2415
+ }
2416
+ run += cell.char;
2417
+ }
2418
+ rendered += apply(style, run);
2419
+ return truncateToWidth3(rendered, width, "");
2420
+ });
2421
+ };
2422
+ var wrapInspector = (theme, label, value, width) => {
2423
+ const clean = safeText(value);
2424
+ const first = truncateToWidth3(clean, Math.max(1, width - label.length - 1), Ellipsis2.Unicode);
2425
+ return [theme.fg("muted", `${label} ${first}`)];
2426
+ };
2427
+ var inspectorLines = (theme, entity, snapshot, run, width, height, invalidate) => {
2428
+ const inner = Math.max(1, width - 2);
2429
+ const border = (value) => theme.fg("borderMuted", value);
2430
+ const content = [];
2431
+ if (entity) {
2432
+ content.push(theme.fg("accent", theme.bold(truncateToWidth3(safeText(entity.label), inner - 2, Ellipsis2.Unicode))));
2433
+ content.push(colorStatus(theme, entity.status, `${statusGlyph(entity.status)} ${entity.kind} \xB7 ${entity.status}`));
2434
+ content.push("");
2435
+ content.push(theme.fg("dim", truncateToWidth3(safeText(entityTail(entity, snapshot.now)), inner - 2, Ellipsis2.Unicode)));
2436
+ if (entity.kind === "agent") {
2437
+ const agentRun = snapshot.runs.find((candidate) => candidate.id === entity.value.runId) ?? run;
2438
+ const phase = agentRun?.phases.find((candidate) => candidate.id === entity.value.phaseId);
2439
+ if (agentRun) content.push(theme.fg("muted", `run ${safeText(agentRun.name)}`));
2440
+ if (phase) content.push(theme.fg("muted", `phase ${safeText(phase.name)}`));
2441
+ if (entity.value.currentTool) content.push(theme.fg("muted", `tool ${safeText(entity.value.currentTool)}`));
2442
+ if (entity.value.model) content.push(theme.fg("muted", `model ${safeText(entity.value.model)}`));
2443
+ if (entity.value.task) content.push(...wrapInspector(theme, "task", entity.value.task, inner - 2));
2444
+ } else if (entity.kind === "actor") {
2445
+ content.push(theme.fg("muted", `runner ${entity.value.runner}`));
2446
+ content.push(theme.fg("muted", `queue ${entity.value.queued}`));
2447
+ if (entity.value.topics.length > 0) content.push(theme.fg("muted", `${entity.value.topics.length} subscriptions`));
2448
+ } else if (entity.kind === "component") {
2449
+ content.push(theme.fg("muted", `definition ${safeText(entity.value.component)}`));
2450
+ content.push(theme.fg("muted", `guarantee ${entity.value.guarantee}`));
2451
+ if (entity.value.parentId) {
2452
+ content.push(theme.fg("muted", `parent ${safeText(entity.value.parentId)}`));
2453
+ }
2454
+ if (entity.value.effects?.length) {
2455
+ content.push(theme.fg("muted", `effects ${entity.value.effects.length}`));
2456
+ }
2457
+ if (entity.value.effectConflicts?.length) {
2458
+ content.push(theme.fg("warning", `conflicts ${entity.value.effectConflicts.length}`));
2459
+ }
2460
+ if (entity.value.requirements.length > 0) {
2461
+ content.push(theme.fg("muted", `requires ${entity.value.requirements.join(", ")}`));
2462
+ }
2463
+ if (entity.value.provisions.length > 0) {
2464
+ content.push(theme.fg("muted", `provides ${entity.value.provisions.join(", ")}`));
2465
+ }
2466
+ const cycles = snapshot.componentGraph.cycles.filter(
2467
+ (cycle) => cycle.includes(entity.value.id)
2468
+ );
2469
+ if (cycles.length > 0) {
2470
+ content.push(theme.fg("warning", `cycles ${cycles.map((cycle) => cycle.join(" \u2192 ")).join("; ")}`));
2471
+ }
2472
+ if (entity.value.error) content.push(theme.fg("error", safeText(entity.value.error)));
2473
+ } else if (entity.kind === "meshTopic") {
2474
+ content.push(theme.fg("muted", `${entity.value.subscribers.length} subscribers`));
2475
+ content.push(theme.fg("muted", `${entity.value.recentEvents} recent events`));
2476
+ } else if (entity.kind === "meshRoute") {
2477
+ content.push(theme.fg("muted", `${safeText(entity.value.fromName)} \u2192 ${safeText(entity.value.targetName)}`));
2478
+ content.push(theme.fg("muted", `kind ${safeText(entity.value.kind)}`));
2479
+ content.push(theme.fg("muted", `topic ${safeText(entity.value.topic)}`));
2480
+ content.push(theme.fg("muted", `count ${entity.value.count}`));
2481
+ } else if (entity.kind === "state") {
2482
+ content.push(theme.fg("muted", `version ${entity.value.version}`));
2483
+ if (entity.value.owner) content.push(theme.fg("muted", `owner ${safeText(entity.value.owner)}`));
2484
+ const filePreview = loadStateFilePreview(entity.value, snapshot.main.cwd ?? process.cwd());
2485
+ if (filePreview) {
2486
+ content.push("");
2487
+ content.push(theme.fg("muted", `file ${safeText(filePreview.path)}`));
2488
+ content.push(...renderStateFilePreview(
2489
+ filePreview,
2490
+ theme,
2491
+ Math.max(1, inner - 2),
2492
+ Math.max(0, height - content.length - 3),
2493
+ invalidate
2494
+ ));
2495
+ }
2496
+ }
2497
+ } else {
2498
+ content.push(theme.fg("dim", "No node selected"));
2499
+ }
2500
+ const title = " selected ";
2501
+ const rows = [border(`\u256D${title}${"\u2500".repeat(Math.max(0, inner - visibleWidth3(title)))}\u256E`)];
2502
+ for (let index = 0; index < height - 2; index++) {
2503
+ rows.push(`${border("\u2502")}${padToWidth(` ${content[index] ?? ""}`, inner)}${border("\u2502")}`);
2504
+ }
2505
+ rows.push(border(`\u2570${"\u2500".repeat(inner)}\u256F`));
2506
+ return rows.slice(0, height);
2507
+ };
2508
+ var graphContextEntities = (allEntities, entities) => {
2509
+ const byRawId = /* @__PURE__ */ new Map();
2510
+ for (const entity of allEntities) {
2511
+ for (const identity of rawIdentity(entity)) {
2512
+ if (identity) byRawId.set(identity, entity);
2513
+ }
2514
+ }
2515
+ const visible = new Map(entities.map((entity) => [entity.id, entity]));
2516
+ for (const entity of entities) {
2517
+ let parentRef = parentReference(entity);
2518
+ const visited = /* @__PURE__ */ new Set();
2519
+ while (parentRef && !visited.has(parentRef)) {
2520
+ visited.add(parentRef);
2521
+ const parent = byRawId.get(parentRef);
2522
+ if (!parent) break;
2523
+ visible.set(parent.id, parent);
2524
+ parentRef = parentReference(parent);
2525
+ }
2526
+ }
2527
+ return allEntities.filter((entity) => visible.has(entity.id));
2528
+ };
2529
+ var renderFabricTopologyPanel = ({
2530
+ theme,
2531
+ filter,
2532
+ selectedEntityId,
2533
+ snapshot,
2534
+ run,
2535
+ mesh,
2536
+ allEntities,
2537
+ entities,
2538
+ width,
2539
+ height,
2540
+ camera,
2541
+ animation,
2542
+ invalidate
2543
+ }) => {
2544
+ const graphEntities = graphContextEntities(allEntities, entities);
2545
+ const layout = buildLayout(snapshot, graphEntities, run, mesh);
2546
+ const selectableIds = new Set(entities.map((entity) => entity.id));
2547
+ const selected = entities.find((entity) => entity.id === selectedEntityId) ?? entities[0];
2548
+ const inspectorWidth = width >= 92 ? Math.min(36, Math.max(30, Math.floor(width * 0.3))) : 0;
2549
+ const graphWidth = Math.max(1, width - inspectorWidth);
2550
+ const graph = renderCanvas(theme, layout, selected?.id, graphWidth, height, camera, animation);
2551
+ const inspector = inspectorWidth > 0 ? inspectorLines(theme, selected, snapshot, run, inspectorWidth, height, invalidate) : [];
2552
+ const lines = inspectorWidth > 0 ? graph.map(
2553
+ (line, index) => `${padToWidth(line, graphWidth)}${inspector[index] ?? ""}`
2554
+ ) : graph;
2555
+ const active = entities.filter((entity) => isActiveStatus(entity.status)).length;
2556
+ const originX = Math.round(camera.x - graphWidth / 2);
2557
+ const originY = Math.round(camera.y - height / 2);
2558
+ const hiddenLeft = layout.nodes.filter((node) => node.x < originX).length;
2559
+ const hiddenRight = layout.nodes.filter((node) => node.x + 2 > originX + graphWidth).length;
2560
+ const hiddenUp = layout.nodes.filter((node) => node.y < originY).length;
2561
+ const hiddenDown = layout.nodes.filter((node) => node.y >= originY + height).length;
2562
+ const offCanvas = new Set(
2563
+ layout.nodes.filter(
2564
+ (node) => node.x < originX || node.x + 2 > originX + graphWidth || node.y < originY || node.y >= originY + height
2565
+ ).map((node) => node.id)
2566
+ ).size;
2567
+ const directions = [
2568
+ hiddenLeft > 0 ? "\u2190" : "",
2569
+ hiddenRight > 0 ? "\u2192" : "",
2570
+ hiddenUp > 0 ? "\u2191" : "",
2571
+ hiddenDown > 0 ? "\u2193" : ""
2572
+ ].join("");
2573
+ if (lines.length > 0 && height > 1) {
2574
+ const legend = [
2575
+ offCanvas > 0 ? `${directions} ${offCanvas} off-canvas` : void 0,
2576
+ `${active} active`,
2577
+ "\u25C6 Main",
2578
+ "\u25A0 agent",
2579
+ "\u25C7 actor",
2580
+ "\u25CE topic",
2581
+ "\u25B1 group",
2582
+ animation.replayRouteId ? "\u25B6 replay" : animation.showHistory ? "history" : "live decay",
2583
+ "\u2B21 component",
2584
+ animation.reducedMotion ? "reduced motion" : void 0,
2585
+ filter !== "all" ? `${entities.length}/${allEntities.length} ${filter}` : void 0
2586
+ ].filter((value) => Boolean(value)).join(" \xB7 ");
2587
+ const graphLegend = padToWidth(theme.fg("dim", truncateToWidth3(legend, graphWidth, "")), graphWidth);
2588
+ lines[0] = truncateToWidth3(
2589
+ graphLegend + (inspectorWidth > 0 ? inspector[0] ?? "" : ""),
2590
+ width,
2591
+ ""
2592
+ );
2593
+ }
2594
+ const selectedPosition = selected ? layout.positions.get(selected.id) : void 0;
2595
+ return {
2596
+ lines,
2597
+ positions: new Map(
2598
+ [...layout.positions].filter(([id]) => selectableIds.has(id))
2599
+ ),
2600
+ ...selectedPosition ? { selectedPosition } : {}
2601
+ };
2602
+ };
2603
+ var directionalGraphTarget = (positions, currentId, direction) => {
2604
+ const current = currentId ? positions.get(currentId) : void 0;
2605
+ if (!current) return positions.keys().next().value;
2606
+ let best;
2607
+ for (const [id, point] of positions) {
2608
+ if (id === currentId) continue;
2609
+ const dx = point.x - current.x;
2610
+ const dy = point.y - current.y;
2611
+ const primary = direction === "left" ? -dx : direction === "right" ? dx : direction === "up" ? -dy : dy;
2612
+ if (primary <= 0) continue;
2613
+ const secondary = direction === "left" || direction === "right" ? Math.abs(dy) : Math.abs(dx);
2614
+ const score = primary + secondary * 2.4;
2615
+ if (!best || score < best.score) best = { id, score };
2616
+ }
2617
+ return best?.id;
2618
+ };
2619
+
2620
+ // src/ui/fabric-host-event-selector.ts
2621
+ import { Container, getKeybindings, Spacer, Text } from "@oh-my-pi/pi-tui";
2622
+ var COMMON_HOST_EVENTS = [
2623
+ "input",
2624
+ "turn_end",
2625
+ "agent_end",
2626
+ "tool_error",
2627
+ "session_compact"
2628
+ ];
2629
+ var commonHostEvents = new Set(COMMON_HOST_EVENTS);
2630
+ var MAX_VISIBLE_HOST_EVENTS = 12;
2631
+ var HOST_EVENT_ORDER = [
2632
+ ...COMMON_HOST_EVENTS,
2633
+ ...FABRIC_ACTOR_HOST_EVENTS.filter((event) => !commonHostEvents.has(event))
2634
+ ];
2635
+ var EVENT_LABELS = {
2636
+ input: "raw user or extension input",
2637
+ turn_end: "each completed LLM turn",
2638
+ agent_end: "a low-level agent run ended",
2639
+ tool_error: "synthetic notification for a failed tool",
2640
+ session_compact: "context was compacted",
2641
+ resources_discover: "skills, prompts, and themes are discovered",
2642
+ session_start: "a session starts, reloads, or is restored",
2643
+ session_switch: "the active session changed",
2644
+ session_before_switch: "before a new or resumed session replaces this one",
2645
+ session_before_branch: "before a session branch",
2646
+ session_branch: "after a session branch",
2647
+ session_before_compact: "before context compaction",
2648
+ "session.compacting": "context compaction is being prepared",
2649
+ session_shutdown: "before this session runtime shuts down",
2650
+ session_before_tree: "before session-tree navigation",
2651
+ session_tree: "after session-tree navigation",
2652
+ goal_updated: "the active goal changed",
2653
+ before_agent_start: "expanded prompt and system context before the agent loop",
2654
+ agent_start: "a low-level agent run started",
2655
+ session_stop: "the main session is settling",
2656
+ turn_start: "an LLM turn started",
2657
+ message_start: "a user, assistant, or tool message started",
2658
+ message_update: "an assistant streaming update",
2659
+ message_end: "a user, assistant, or tool message completed",
2660
+ context: "assembled messages before an LLM request",
2661
+ before_provider_request: "provider payload assembled before sending",
2662
+ after_provider_response: "provider response received",
2663
+ tool_execution_start: "tool execution started",
2664
+ tool_call: "validated tool call before execution",
2665
+ tool_execution_update: "streaming tool progress",
2666
+ tool_result: "final tool result before message persistence",
2667
+ tool_execution_end: "tool execution completed",
2668
+ user_bash: "a user ! or !! shell command was submitted"
2669
+ };
2670
+ var FabricHostEventSelector = class extends Container {
2671
+ theme;
2672
+ onSelectCallback;
2673
+ onCancelCallback;
2674
+ listContainer = new Container();
2675
+ enabled;
2676
+ selectedIndex = 0;
2677
+ focused = false;
2678
+ constructor(options) {
2679
+ super();
2680
+ this.theme = options.theme;
2681
+ this.onSelectCallback = options.onSelect;
2682
+ this.onCancelCallback = options.onCancel;
2683
+ this.enabled = new Set(options.currentValue);
2684
+ this.addChild(
2685
+ new Text(
2686
+ this.theme.fg(
2687
+ "muted",
2688
+ options.headerText ?? "Toggle the host events this actor subscribes to."
2689
+ ),
2690
+ 0,
2691
+ 0
2692
+ )
2693
+ );
2694
+ this.addChild(new Spacer(1));
2695
+ this.addChild(this.listContainer);
2696
+ this.addChild(new Spacer(1));
2697
+ this.updateList();
2698
+ }
2699
+ handleInput(keyData) {
2700
+ const kb = getKeybindings();
2701
+ if (kb.matches(keyData, "tui.select.up")) {
2702
+ this.selectedIndex = this.selectedIndex === 0 ? HOST_EVENT_ORDER.length - 1 : this.selectedIndex - 1;
2703
+ this.updateList();
2704
+ } else if (kb.matches(keyData, "tui.select.down")) {
2705
+ this.selectedIndex = this.selectedIndex === HOST_EVENT_ORDER.length - 1 ? 0 : this.selectedIndex + 1;
2706
+ this.updateList();
2707
+ } else if (keyData === " ") {
2708
+ const event = HOST_EVENT_ORDER[this.selectedIndex];
2709
+ if (event) {
2710
+ if (this.enabled.has(event)) this.enabled.delete(event);
2711
+ else this.enabled.add(event);
2712
+ this.updateList();
2713
+ }
2714
+ } else if (kb.matches(keyData, "tui.select.confirm")) {
2715
+ this.onSelectCallback(HOST_EVENT_ORDER.filter((event) => this.enabled.has(event)));
2716
+ } else if (kb.matches(keyData, "tui.select.cancel")) {
2717
+ this.onCancelCallback();
2718
+ }
2719
+ }
2720
+ updateList() {
2721
+ this.listContainer.clear();
2722
+ const total = HOST_EVENT_ORDER.length;
2723
+ const startIndex = Math.max(
2724
+ 0,
2725
+ Math.min(
2726
+ this.selectedIndex - Math.floor(MAX_VISIBLE_HOST_EVENTS / 2),
2727
+ total - MAX_VISIBLE_HOST_EVENTS
2728
+ )
2729
+ );
2730
+ const endIndex = Math.min(startIndex + MAX_VISIBLE_HOST_EVENTS, total);
2731
+ if (startIndex > 0) {
2732
+ this.listContainer.addChild(
2733
+ new Text(this.theme.fg("dim", ` \u2191 ${startIndex} earlier events`), 0, 0)
2734
+ );
2735
+ }
2736
+ for (let index = startIndex; index < endIndex; index++) {
2737
+ const event = HOST_EVENT_ORDER[index];
2738
+ const selected = index === this.selectedIndex;
2739
+ const checked = this.enabled.has(event);
2740
+ const box = checked ? this.theme.fg("success", "[x]") : this.theme.fg("dim", "[ ]");
2741
+ const label = `${box} ${event} \xB7 ${this.theme.fg("muted", EVENT_LABELS[event] ?? event)}`;
2742
+ const line = selected ? `${this.theme.fg("accent", "\u2192 ")}${this.theme.fg("accent", label)}` : ` ${label}`;
2743
+ this.listContainer.addChild(new Text(line, 0, 0));
2744
+ }
2745
+ if (endIndex < total) {
2746
+ this.listContainer.addChild(
2747
+ new Text(this.theme.fg("dim", ` \u2193 ${total - endIndex} later events`), 0, 0)
2748
+ );
2749
+ }
2750
+ this.listContainer.addChild(new Spacer(1));
2751
+ this.listContainer.addChild(
2752
+ new Text(this.theme.fg("muted", " space toggle \xB7 enter apply \xB7 esc cancel"), 0, 0)
2753
+ );
2754
+ }
2755
+ };
2756
+
2757
+ // src/ui/fabric-actor-delivery-selector.ts
2758
+ import "@oh-my-pi/pi-tui";
2759
+ import {
2760
+ Container as Container2,
2761
+ SelectList,
2762
+ Spacer as Spacer2,
2763
+ Text as Text2
2764
+ } from "@oh-my-pi/pi-tui";
2765
+ var LAYOUT = {
2766
+ minPrimaryColumnWidth: 18,
2767
+ maxPrimaryColumnWidth: 34
2768
+ };
2769
+ var POLICIES = [
2770
+ { value: "mailbox", label: "Mailbox only", description: "keep output in actor history", delivery: "mailbox", triggerTurn: false },
2771
+ { value: "steer-passive", label: "Steer \xB7 passive", description: "deliver now without starting idle Main", delivery: "steer", triggerTurn: false },
2772
+ { value: "steer-active", label: "Steer \xB7 resume Main", description: "deliver now and start Main when idle", delivery: "steer", triggerTurn: true },
2773
+ { value: "followUp-passive", label: "Follow-up \xB7 passive", description: "deliver after the run without starting idle Main", delivery: "followUp", triggerTurn: false },
2774
+ { value: "followUp-active", label: "Follow-up \xB7 resume Main", description: "deliver after the run and start Main when idle", delivery: "followUp", triggerTurn: true },
2775
+ { value: "next-turn", label: "Next user turn", description: "defer until the next user prompt", delivery: "nextTurn", triggerTurn: false }
2776
+ ];
2777
+ var selectListTheme = (theme) => ({
2778
+ symbols: theme.symbols,
2779
+ selectedPrefix: (text) => theme.fg("accent", text),
2780
+ selectedText: (text) => theme.fg("accent", text),
2781
+ description: (text) => theme.fg("muted", text),
2782
+ scrollInfo: (text) => theme.fg("muted", text),
2783
+ noMatch: (text) => theme.fg("muted", text)
2784
+ });
2785
+ var FabricActorDeliverySelector = class extends Container2 {
2786
+ selectList;
2787
+ focused = false;
2788
+ constructor(options) {
2789
+ super();
2790
+ const current = POLICIES.find(
2791
+ (policy) => policy.delivery === options.currentValue.delivery && policy.triggerTurn === options.currentValue.triggerTurn
2792
+ )?.value;
2793
+ const items = POLICIES.map((policy) => ({
2794
+ value: policy.value,
2795
+ label: `${policy.label}${policy.value === current ? " \u2713" : ""}`,
2796
+ description: policy.description
2797
+ }));
2798
+ this.addChild(
2799
+ new Text2(
2800
+ options.theme.fg(
2801
+ "muted",
2802
+ options.headerText ?? "Choose how actor output enters Main and whether it starts a turn."
2803
+ ),
2804
+ 0,
2805
+ 0
2806
+ )
2807
+ );
2808
+ this.addChild(new Spacer2(1));
2809
+ this.selectList = new SelectList(items, items.length, selectListTheme(options.theme), LAYOUT);
2810
+ const startIndex = items.findIndex((item) => item.value === current);
2811
+ if (startIndex >= 0) this.selectList.setSelectedIndex(startIndex);
2812
+ this.selectList.onSelect = (item) => {
2813
+ const policy = POLICIES.find((candidate) => candidate.value === item.value);
2814
+ if (policy) options.onSelect({ delivery: policy.delivery, triggerTurn: policy.triggerTurn });
2815
+ };
2816
+ this.selectList.onCancel = options.onCancel;
2817
+ this.addChild(this.selectList);
2818
+ this.addChild(new Spacer2(1));
2819
+ }
2820
+ handleInput(data) {
2821
+ this.selectList.handleInput(data);
2822
+ }
2823
+ };
2824
+
2825
+ // src/ui/fabric-actor-tool-selector.ts
2826
+ import { Container as Container3, getKeybindings as getKeybindings2, Spacer as Spacer3, Text as Text3 } from "@oh-my-pi/pi-tui";
2827
+ var ACTOR_TOOL_ORDER = ["read", "grep", "find", "ls", "bash", "edit", "write"];
2828
+ var TOOL_LABELS = {
2829
+ read: "read files",
2830
+ grep: "search file contents",
2831
+ find: "find files by name",
2832
+ ls: "list directories",
2833
+ bash: "execute shell commands",
2834
+ edit: "edit existing files",
2835
+ write: "write files"
2836
+ };
2837
+ var FabricActorToolSelector = class extends Container3 {
2838
+ theme;
2839
+ onSelectCallback;
2840
+ onCancelCallback;
2841
+ listContainer = new Container3();
2842
+ enabled;
2843
+ selectedIndex = 0;
2844
+ focused = false;
2845
+ constructor(options) {
2846
+ super();
2847
+ this.theme = options.theme;
2848
+ this.onSelectCallback = options.onSelect;
2849
+ this.onCancelCallback = options.onCancel;
2850
+ this.enabled = new Set(options.currentValue);
2851
+ this.addChild(
2852
+ new Text3(
2853
+ this.theme.fg("muted", options.headerText ?? "Select the optional tools available to this actor."),
2854
+ 0,
2855
+ 0
2856
+ )
2857
+ );
2858
+ this.addChild(new Spacer3(1));
2859
+ this.addChild(this.listContainer);
2860
+ this.addChild(new Spacer3(1));
2861
+ this.updateList();
2862
+ }
2863
+ handleInput(keyData) {
2864
+ const kb = getKeybindings2();
2865
+ if (kb.matches(keyData, "tui.select.up")) {
2866
+ this.selectedIndex = this.selectedIndex === 0 ? ACTOR_TOOL_ORDER.length - 1 : this.selectedIndex - 1;
2867
+ this.updateList();
2868
+ } else if (kb.matches(keyData, "tui.select.down")) {
2869
+ this.selectedIndex = this.selectedIndex === ACTOR_TOOL_ORDER.length - 1 ? 0 : this.selectedIndex + 1;
2870
+ this.updateList();
2871
+ } else if (keyData === " ") {
2872
+ const tool = ACTOR_TOOL_ORDER[this.selectedIndex];
2873
+ if (tool) {
2874
+ if (this.enabled.has(tool)) this.enabled.delete(tool);
2875
+ else this.enabled.add(tool);
2876
+ this.updateList();
2877
+ }
2878
+ } else if (kb.matches(keyData, "tui.select.confirm")) {
2879
+ const selected = ACTOR_TOOL_ORDER.filter((tool) => this.enabled.has(tool));
2880
+ const custom = [...this.enabled].filter(
2881
+ (tool) => !ACTOR_TOOL_ORDER.includes(tool)
2882
+ );
2883
+ this.onSelectCallback([...selected, ...custom]);
2884
+ } else if (kb.matches(keyData, "tui.select.cancel")) {
2885
+ this.onCancelCallback();
2886
+ }
2887
+ }
2888
+ updateList() {
2889
+ this.listContainer.clear();
2890
+ for (let index = 0; index < ACTOR_TOOL_ORDER.length; index++) {
2891
+ const tool = ACTOR_TOOL_ORDER[index];
2892
+ const selected = index === this.selectedIndex;
2893
+ const checked = this.enabled.has(tool);
2894
+ const box = checked ? this.theme.fg("success", "[x]") : this.theme.fg("dim", "[ ]");
2895
+ const label = `${box} ${tool} \xB7 ${this.theme.fg("muted", TOOL_LABELS[tool])}`;
2896
+ const line = selected ? `${this.theme.fg("accent", "\u2192 ")}${this.theme.fg("accent", label)}` : ` ${label}`;
2897
+ this.listContainer.addChild(new Text3(line, 0, 0));
2898
+ }
2899
+ this.listContainer.addChild(new Spacer3(1));
2900
+ this.listContainer.addChild(
2901
+ new Text3(this.theme.fg("muted", " space toggle \xB7 enter apply \xB7 esc cancel"), 0, 0)
2902
+ );
2903
+ }
2904
+ };
2905
+
2906
+ // src/ui/fabric-thinking-selector.ts
2907
+ import "@oh-my-pi/pi-tui";
2908
+ import {
2909
+ Container as Container4,
2910
+ SelectList as SelectList2,
2911
+ Spacer as Spacer4,
2912
+ Text as Text4
2913
+ } from "@oh-my-pi/pi-tui";
2914
+ var LAYOUT2 = {
2915
+ minPrimaryColumnWidth: 8,
2916
+ maxPrimaryColumnWidth: 24
2917
+ };
2918
+ var selectListTheme2 = (theme) => ({
2919
+ symbols: theme.symbols,
2920
+ selectedPrefix: (text) => theme.fg("accent", text),
2921
+ selectedText: (text) => theme.fg("accent", text),
2922
+ description: (text) => theme.fg("muted", text),
2923
+ scrollInfo: (text) => theme.fg("muted", text),
2924
+ noMatch: (text) => theme.fg("muted", text)
2925
+ });
2926
+ var FabricThinkingSelector = class extends Container4 {
2927
+ selectList;
2928
+ onSelectCallback;
2929
+ focused = false;
2930
+ constructor(options) {
2931
+ super();
2932
+ this.onSelectCallback = options.onSelect;
2933
+ const headerText = options.headerText ?? "Thinking level for this actor. Pick Inherit to use the Fabric default.";
2934
+ const inheritName = options.inheritName ?? "Use the Fabric default thinking level";
2935
+ const items = [
2936
+ {
2937
+ value: INHERIT_VALUE,
2938
+ label: `Inherit${options.currentValue === INHERIT_VALUE ? " \u2713" : ""}`,
2939
+ description: inheritName
2940
+ },
2941
+ ...THINKING_LEVELS.map((level) => ({
2942
+ value: level,
2943
+ label: `${thinkingLabel(level)}${options.currentValue === level ? " \u2713" : ""}`
2944
+ }))
2945
+ ];
2946
+ const startIndex = items.findIndex((item) => item.value === options.currentValue);
2947
+ this.addChild(new Text4(options.theme.fg("muted", headerText), 0, 0));
2948
+ this.addChild(new Spacer4(1));
2949
+ this.selectList = new SelectList2(items, items.length, selectListTheme2(options.theme), LAYOUT2);
2950
+ if (startIndex >= 0) this.selectList.setSelectedIndex(startIndex);
2951
+ this.selectList.onSelect = (item) => this.onSelectCallback(item.value);
2952
+ this.selectList.onCancel = options.onCancel;
2953
+ this.addChild(this.selectList);
2954
+ this.addChild(new Spacer4(1));
2955
+ }
2956
+ handleInput(data) {
2957
+ this.selectList.handleInput(data);
2958
+ }
2959
+ };
2960
+
2961
+ // src/ui/dashboard.ts
2962
+ var editorTheme = (theme) => ({
2963
+ symbols: ompSymbolTheme,
2964
+ borderColor: (value) => theme.fg("borderMuted", value),
2965
+ selectList: {
2966
+ symbols: ompSymbolTheme,
2967
+ selectedPrefix: (text) => theme.fg("accent", text),
2968
+ selectedText: (text) => theme.fg("accent", text),
2969
+ description: (text) => theme.fg("muted", text),
2970
+ scrollInfo: (text) => theme.fg("muted", text),
2971
+ noMatch: (text) => theme.fg("muted", text)
2972
+ }
2973
+ });
2974
+ var DASHBOARD_OVERLAY_HEIGHT_PERCENT = 90;
2975
+ var DASHBOARD_OVERLAY_VERTICAL_MARGIN = 1;
2976
+ var dashboardOverlayRows = (terminalRows) => Math.max(
2977
+ 1,
2978
+ Math.min(
2979
+ Math.floor(terminalRows * DASHBOARD_OVERLAY_HEIGHT_PERCENT / 100),
2980
+ terminalRows - DASHBOARD_OVERLAY_VERTICAL_MARGIN * 2
2981
+ )
2982
+ );
2983
+ var FabricDashboard = class {
2984
+ constructor(tui, theme, snapshot, done, options = {}) {
2985
+ this.tui = tui;
2986
+ this.theme = theme;
2987
+ this.snapshot = snapshot;
2988
+ this.done = done;
2989
+ this.focused = true;
2990
+ this.modelSource = options.modelSource;
2991
+ this.codePreviewSettings = options.codePreviewSettings;
2992
+ this.keybindings = options.keybindings;
2993
+ this.claudeModelSource = options.claudeModelSource;
2994
+ this.onAgentSteer = options.onAgentSteer;
2995
+ this.onAgentFollowUp = options.onAgentFollowUp;
2996
+ this.onAgentStop = options.onAgentStop;
2997
+ this.onConversation = options.onConversation;
2998
+ this.onTargetMessage = options.onTargetMessage;
2999
+ this.agentTranscript = options.agentTranscript;
3000
+ this.actorTranscript = options.actorTranscript;
3001
+ this.loadOlderTranscript = options.loadOlderTranscript;
3002
+ this.loadNewerTranscript = options.loadNewerTranscript;
3003
+ this.loadLatestTranscript = options.loadLatestTranscript;
3004
+ this.onActorModel = options.onActorModel;
3005
+ this.onActorThinking = options.onActorThinking;
3006
+ this.onActorEvents = options.onActorEvents;
3007
+ this.onActorDeliveryPolicy = options.onActorDeliveryPolicy;
3008
+ this.onGlobalDeliveryPolicy = options.onGlobalDeliveryPolicy;
3009
+ this.onActorTools = options.onActorTools;
3010
+ this.actorDefaultTools = options.actorDefaultTools ?? [];
3011
+ this.onClearMessages = options.onClearMessages;
3012
+ this.onActorInstructions = options.onActorInstructions;
3013
+ this.onGlobalInstructions = options.onGlobalInstructions;
3014
+ this.onImportActor = options.onImportActor;
3015
+ this.onExportActor = options.onExportActor;
3016
+ this.onRemoveGlobalActor = options.onRemoveGlobalActor;
3017
+ this.detailRenderer = new DashboardDetailRenderer(tui, theme, snapshot, {
3018
+ agentTranscript: this.agentTranscript,
3019
+ actorTranscript: this.actorTranscript,
3020
+ codePreviewSettings: this.codePreviewSettings,
3021
+ actorDefaultTools: this.actorDefaultTools
3022
+ });
3023
+ }
3024
+ focused = false;
3025
+ pane = "phases";
3026
+ overviewView = "activity";
3027
+ graphPositions = /* @__PURE__ */ new Map();
3028
+ graphCamera = { x: 0, y: 0 };
3029
+ graphCameraTarget = { x: 0, y: 0 };
3030
+ graphVelocity = { x: 0, y: 0 };
3031
+ graphCameraInitialized = false;
3032
+ graphAnimation;
3033
+ graphAnimationAt = 0;
3034
+ graphEffectsAnimation;
3035
+ graphReducedMotion = false;
3036
+ graphShowHistory = false;
3037
+ graphReplayIndex;
3038
+ graphReplayPlaying = false;
3039
+ graphReplaySpeed = 1;
3040
+ graphReplayAdvancedAt = 0;
3041
+ graphReplayLength = 0;
3042
+ graphReplayLabel;
3043
+ phaseIndex = 0;
3044
+ entityIndex = 0;
3045
+ runIndex = 0;
3046
+ selectedRunId;
3047
+ runSelectionTouched = false;
3048
+ selectedEntityId;
3049
+ filter = "all";
3050
+ phaseSelectionTouched = false;
3051
+ selectedPhaseId;
3052
+ detailId;
3053
+ detailScroll = 0;
3054
+ detailMaxScroll = 0;
3055
+ transcriptPageAnchor;
3056
+ transcriptToolsExpanded = false;
3057
+ detailSelectionRestore;
3058
+ detailView = "summary";
3059
+ transcriptFollowing = true;
3060
+ detailRenderer;
3061
+ highlightInvalidate = () => this.tui.requestRender();
3062
+ mode = "overview";
3063
+ picker;
3064
+ editor;
3065
+ editorActorName;
3066
+ agentMessageTarget;
3067
+ pendingStop;
3068
+ modelSource;
3069
+ claudeModelSource;
3070
+ onAgentSteer;
3071
+ onAgentFollowUp;
3072
+ onAgentStop;
3073
+ onConversation;
3074
+ onTargetMessage;
3075
+ agentTranscript;
3076
+ actorTranscript;
3077
+ loadOlderTranscript;
3078
+ loadNewerTranscript;
3079
+ loadLatestTranscript;
3080
+ onActorModel;
3081
+ onActorThinking;
3082
+ onActorEvents;
3083
+ onActorDeliveryPolicy;
3084
+ onGlobalDeliveryPolicy;
3085
+ onActorTools;
3086
+ actorDefaultTools;
3087
+ onClearMessages;
3088
+ onActorInstructions;
3089
+ onGlobalInstructions;
3090
+ onImportActor;
3091
+ onExportActor;
3092
+ onRemoveGlobalActor;
3093
+ codePreviewSettings;
3094
+ keybindings;
3095
+ pickerActorName;
3096
+ handleInput(data) {
3097
+ if (this.mode === "help") {
3098
+ if (data === "?" || matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl("c"))) {
3099
+ this.mode = this.detailId ? "detail" : "overview";
3100
+ }
3101
+ this.tui.requestRender();
3102
+ return;
3103
+ }
3104
+ if (this.mode === "agentMessageEditor" && this.editor) {
3105
+ if (getKeybindings3().matches(data, "tui.select.cancel")) {
3106
+ this.closeAgentMessageEditor();
3107
+ } else {
3108
+ this.editor.handleInput(data);
3109
+ }
3110
+ this.tui.requestRender();
3111
+ return;
3112
+ }
3113
+ if (this.mode === "instructionsEditor" && this.editor) {
3114
+ if (getKeybindings3().matches(data, "tui.select.cancel")) {
3115
+ this.closeInstructionsEditor();
3116
+ } else {
3117
+ this.editor.handleInput(data);
3118
+ }
3119
+ this.tui.requestRender();
3120
+ return;
3121
+ }
3122
+ if ((this.mode === "modelPicker" || this.mode === "thinkingPicker" || this.mode === "deliveryPicker" || this.mode === "eventsPicker" || this.mode === "toolsPicker") && this.picker) {
3123
+ this.picker.handleInput(data);
3124
+ this.tui.requestRender();
3125
+ return;
3126
+ }
3127
+ const snapshot = this.snapshot();
3128
+ const run = this.selectRun(snapshot);
3129
+ const panels = phasePanels(snapshot, run);
3130
+ this.syncPhase(run, panels);
3131
+ const panel = panels[this.phaseIndex];
3132
+ const projectMesh = this.projectMesh(snapshot);
3133
+ const allEntities = entitiesForOverview(
3134
+ snapshot,
3135
+ run,
3136
+ panel,
3137
+ this.overviewView,
3138
+ projectMesh
3139
+ );
3140
+ const entities = allEntities.filter(
3141
+ (entity) => entity.kind === "main" || matchesFilter(entity.status, this.filter)
3142
+ );
3143
+ this.syncEntitySelection(entities, this.overviewView !== "activity");
3144
+ if (data === "C" && this.onConversation) {
3145
+ const entity = this.detailId ? allEntities.find((candidate) => candidate.id === this.detailId) : entities[this.entityIndex];
3146
+ const target = entity ? this.messageTarget(entity) : void 0;
3147
+ if (target) this.onConversation(target.id);
3148
+ return;
3149
+ }
3150
+ if (data === "?") {
3151
+ this.mode = "help";
3152
+ this.tui.requestRender();
3153
+ return;
3154
+ }
3155
+ if (this.detailId) {
3156
+ if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl("c")) || matchesKey(data, Key.left) || data === "h") {
3157
+ this.closeDetail();
3158
+ } else if (data === "t") {
3159
+ const detail = allEntities.find((entity) => entity.id === this.detailId);
3160
+ if (detail && this.hasTranscript(detail)) {
3161
+ this.detailView = this.detailView === "summary" ? "transcript" : "summary";
3162
+ this.detailScroll = 0;
3163
+ this.transcriptPageAnchor = void 0;
3164
+ this.transcriptFollowing = true;
3165
+ }
3166
+ } else if (this.detailView === "transcript" && this.matchesTranscriptToolToggle(data)) {
3167
+ this.transcriptToolsExpanded = !this.transcriptToolsExpanded;
3168
+ } else if (matchesKey(data, Key.up) || data === "k") {
3169
+ if (this.detailScroll > 0) {
3170
+ if (this.detailView === "transcript") this.transcriptFollowing = false;
3171
+ this.detailScroll--;
3172
+ } else if (this.detailView === "transcript") {
3173
+ const detail = allEntities.find((entity) => entity.id === this.detailId);
3174
+ const target = detail ? this.transcriptTarget(detail) : void 0;
3175
+ if (target && this.loadOlderTranscript?.(target)) {
3176
+ this.transcriptPageAnchor = "end";
3177
+ this.transcriptFollowing = false;
3178
+ }
3179
+ }
3180
+ } else if (matchesKey(data, Key.down) || data === "j") {
3181
+ if (this.detailScroll < this.detailMaxScroll) {
3182
+ if (this.detailView === "transcript") this.transcriptFollowing = false;
3183
+ this.detailScroll++;
3184
+ } else if (this.detailView === "transcript") {
3185
+ const detail = allEntities.find((entity) => entity.id === this.detailId);
3186
+ const target = detail ? this.transcriptTarget(detail) : void 0;
3187
+ if (target && this.loadNewerTranscript?.(target)) {
3188
+ this.transcriptPageAnchor = "start";
3189
+ this.transcriptFollowing = false;
3190
+ }
3191
+ }
3192
+ } else if (data === "G" && this.detailView === "transcript") {
3193
+ const detail = allEntities.find((entity) => entity.id === this.detailId);
3194
+ const target = detail ? this.transcriptTarget(detail) : void 0;
3195
+ if (target) this.loadLatestTranscript?.(target);
3196
+ this.transcriptPageAnchor = void 0;
3197
+ this.transcriptFollowing = true;
3198
+ this.detailScroll = this.detailMaxScroll;
3199
+ } else if (matchesKey(data, Key.home) || data === "g") {
3200
+ if (this.detailView === "transcript") {
3201
+ this.transcriptPageAnchor = void 0;
3202
+ this.transcriptFollowing = false;
3203
+ }
3204
+ this.detailScroll = 0;
3205
+ } else if (data === "s" || data === "u") {
3206
+ const detail = allEntities.find((entity) => entity.id === this.detailId);
3207
+ const delivery = data === "s" ? "steer" : "followUp";
3208
+ if (detail && this.canMessage(detail, delivery)) {
3209
+ this.openAgentMessageEditor(detail, delivery);
3210
+ }
3211
+ } else if (data === "m" || data === "M") {
3212
+ const detail = allEntities.find((entity) => entity.id === this.detailId);
3213
+ if (detail && detail.kind === "actor" && detail.status !== "stopped" && (data === "m" || detail.value.local !== false)) {
3214
+ this.openModelPicker(detail, data === "M" ? "project" : "session");
3215
+ }
3216
+ } else if (data === "e" || data === "E") {
3217
+ const detail = allEntities.find((entity) => entity.id === this.detailId);
3218
+ if (detail && detail.kind === "actor" && detail.status !== "stopped" && (data === "e" || detail.value.local !== false)) {
3219
+ this.openThinkingPicker(detail, data === "E" ? "project" : "session");
3220
+ }
3221
+ } else if (data === "y") {
3222
+ const detail = allEntities.find((entity) => entity.id === this.detailId);
3223
+ if (detail && (detail.kind === "globalActor" || detail.kind === "actor" && detail.value.local !== false)) {
3224
+ this.openDeliveryPicker(detail);
3225
+ }
3226
+ } else if (data === "v") {
3227
+ const detail = allEntities.find((entity) => entity.id === this.detailId);
3228
+ if (detail && detail.kind === "actor" && detail.status !== "stopped" && detail.value.local !== false) {
3229
+ this.openEventsPicker(detail);
3230
+ }
3231
+ } else if (data === "o") {
3232
+ const detail = allEntities.find((entity) => entity.id === this.detailId);
3233
+ if (detail && detail.kind === "actor" && detail.status !== "stopped" && detail.value.local !== false) {
3234
+ this.openToolsPicker(detail);
3235
+ }
3236
+ } else if (data === "c") {
3237
+ const detail = allEntities.find((entity) => entity.id === this.detailId);
3238
+ if (detail && detail.kind === "actor" && detail.status !== "stopped" && detail.value.local !== false && this.onClearMessages) {
3239
+ this.onClearMessages(detail.value.id);
3240
+ }
3241
+ } else if (data === "i") {
3242
+ const detail = allEntities.find((entity) => entity.id === this.detailId);
3243
+ if (detail && (detail.kind === "globalActor" || detail.kind === "actor" && detail.value.local !== false)) {
3244
+ this.openInstructionsEditor(detail);
3245
+ }
3246
+ } else if (data === "x") {
3247
+ const detail = allEntities.find((entity) => entity.id === this.detailId);
3248
+ if (detail && this.canStop(detail)) {
3249
+ this.requestParticipantStop(detail);
3250
+ } else if (detail && detail.kind === "actor" && detail.status !== "stopped" && this.onExportActor) {
3251
+ this.onExportActor(detail.value.id);
3252
+ }
3253
+ } else if (data === "p") {
3254
+ const detail = allEntities.find((entity) => entity.id === this.detailId);
3255
+ if (detail && detail.kind === "globalActor" && this.onImportActor) {
3256
+ this.onImportActor(detail.value.id);
3257
+ }
3258
+ } else if (data === "d") {
3259
+ const detail = allEntities.find((entity) => entity.id === this.detailId);
3260
+ if (detail && detail.kind === "globalActor" && this.onRemoveGlobalActor) {
3261
+ this.onRemoveGlobalActor(detail.value.id);
3262
+ }
3263
+ }
3264
+ this.tui.requestRender();
3265
+ return;
3266
+ }
3267
+ if (data === "1" || data === "2") {
3268
+ const nextOverview = data === "1" ? "activity" : "topology";
3269
+ if (nextOverview !== this.overviewView) {
3270
+ if (nextOverview === "activity") {
3271
+ this.stopGraphAnimation();
3272
+ this.stopGraphEffectsAnimation();
3273
+ }
3274
+ this.overviewView = nextOverview;
3275
+ this.pane = nextOverview === "activity" ? "phases" : "entities";
3276
+ this.entityIndex = 0;
3277
+ this.selectedEntityId = void 0;
3278
+ this.pendingStop = void 0;
3279
+ }
3280
+ this.tui.requestRender();
3281
+ return;
3282
+ }
3283
+ if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl("c"))) {
3284
+ if (this.overviewView === "activity" && this.pane === "entities") {
3285
+ this.pane = "phases";
3286
+ } else {
3287
+ this.done();
3288
+ return;
3289
+ }
3290
+ } else if (this.overviewView === "topology" && data === "r") {
3291
+ this.toggleGraphReplay(snapshot, projectMesh);
3292
+ this.startGraphEffectsAnimation();
3293
+ this.tui.requestRender();
3294
+ return;
3295
+ } else if (this.overviewView === "topology" && this.graphReplayIndex !== void 0 && data === " ") {
3296
+ this.graphReplayPlaying = !this.graphReplayPlaying;
3297
+ this.graphReplayAdvancedAt = Date.now();
3298
+ this.startGraphEffectsAnimation();
3299
+ this.tui.requestRender();
3300
+ return;
3301
+ } else if (this.overviewView === "topology" && this.graphReplayIndex !== void 0 && (matchesKey(data, Key.left) || matchesKey(data, Key.right))) {
3302
+ this.stepGraphReplay(matchesKey(data, Key.left) ? -1 : 1);
3303
+ this.tui.requestRender();
3304
+ return;
3305
+ } else if (this.overviewView === "topology" && (data === "+" || data === "=" || data === "-")) {
3306
+ const speeds = [0.5, 1, 2, 4];
3307
+ const current = speeds.indexOf(this.graphReplaySpeed);
3308
+ const direction = data === "-" ? -1 : 1;
3309
+ this.graphReplaySpeed = speeds[Math.max(0, Math.min(speeds.length - 1, current + direction))] ?? 1;
3310
+ this.graphReplayAdvancedAt = Date.now();
3311
+ this.tui.requestRender();
3312
+ return;
3313
+ } else if (this.overviewView === "topology" && data === "H") {
3314
+ this.graphShowHistory = !this.graphShowHistory;
3315
+ this.tui.requestRender();
3316
+ return;
3317
+ } else if (this.overviewView === "topology" && data === "M") {
3318
+ const selected = this.pane === "entities" ? entities[this.entityIndex] : void 0;
3319
+ if (selected?.kind === "actor" && selected.status !== "stopped" && selected.value.local !== false && this.modelSourceForActor(selected.value) && this.onActorModel) {
3320
+ this.detailId = selected.id;
3321
+ this.openModelPicker(selected, "project");
3322
+ } else {
3323
+ this.graphReducedMotion = !this.graphReducedMotion;
3324
+ }
3325
+ this.tui.requestRender();
3326
+ return;
3327
+ } else if (this.overviewView === "topology" && (matchesKey(data, Key.left) || matchesKey(data, Key.right) || matchesKey(data, Key.up) || matchesKey(data, Key.down) || data === "h" || data === "l")) {
3328
+ const direction = matchesKey(data, Key.left) || data === "h" ? "left" : matchesKey(data, Key.right) || data === "l" ? "right" : matchesKey(data, Key.up) ? "up" : "down";
3329
+ const target = directionalGraphTarget(this.graphPositions, this.selectedEntityId, direction);
3330
+ const targetIndex = target ? entities.findIndex((entity) => entity.id === target) : -1;
3331
+ if (targetIndex >= 0) {
3332
+ this.entityIndex = targetIndex;
3333
+ this.selectedEntityId = target;
3334
+ this.pendingStop = void 0;
3335
+ }
3336
+ this.tui.requestRender();
3337
+ return;
3338
+ } else if (matchesKey(data, Key.tab) && this.overviewView === "topology") {
3339
+ this.entityIndex = entities.length > 0 ? (this.entityIndex + 1) % entities.length : 0;
3340
+ this.selectedEntityId = entities[this.entityIndex]?.id;
3341
+ this.pendingStop = void 0;
3342
+ this.tui.requestRender();
3343
+ return;
3344
+ } else if (matchesKey(data, Key.tab) && this.overviewView === "activity") {
3345
+ this.pane = this.pane === "phases" ? "entities" : "phases";
3346
+ } else if (this.overviewView === "activity" && (matchesKey(data, Key.left) || data === "h")) {
3347
+ this.pane = "phases";
3348
+ } else if (this.overviewView === "activity" && (matchesKey(data, Key.right) || data === "l")) {
3349
+ this.pane = "entities";
3350
+ } else if (matchesKey(data, Key.up) || data === "k") {
3351
+ if (this.overviewView === "activity" && this.pane === "phases") {
3352
+ this.phaseIndex = Math.max(0, this.phaseIndex - 1);
3353
+ this.phaseSelectionTouched = true;
3354
+ this.entityIndex = 0;
3355
+ this.selectedEntityId = void 0;
3356
+ } else {
3357
+ this.entityIndex = Math.max(0, this.entityIndex - 1);
3358
+ }
3359
+ } else if (matchesKey(data, Key.down) || data === "j") {
3360
+ if (this.overviewView === "activity" && this.pane === "phases") {
3361
+ this.phaseIndex = Math.min(Math.max(0, panels.length - 1), this.phaseIndex + 1);
3362
+ this.phaseSelectionTouched = true;
3363
+ this.entityIndex = 0;
3364
+ this.selectedEntityId = void 0;
3365
+ } else {
3366
+ this.entityIndex = Math.min(Math.max(0, entities.length - 1), this.entityIndex + 1);
3367
+ }
3368
+ } else if (["m", "M", "e", "E", "y", "v", "o", "i", "c", "s", "u", "x", "p", "d"].includes(data) && this.pane === "entities") {
3369
+ const selected = entities[this.entityIndex];
3370
+ if (selected) {
3371
+ if ((data === "s" || data === "u") && this.canMessage(selected, data === "s" ? "steer" : "followUp")) {
3372
+ this.detailId = selected.id;
3373
+ this.openAgentMessageEditor(selected, data === "s" ? "steer" : "followUp");
3374
+ } else if (data === "x" && this.canStop(selected)) {
3375
+ this.requestParticipantStop(selected);
3376
+ } else if (data === "x" && selected.kind === "actor" && selected.status !== "stopped" && this.onExportActor) {
3377
+ this.onExportActor(selected.value.id);
3378
+ } else if ((data === "m" || data === "M") && selected.kind === "actor" && selected.status !== "stopped" && (data === "m" || selected.value.local !== false)) {
3379
+ this.detailId = selected.id;
3380
+ this.openModelPicker(selected, data === "M" ? "project" : "session");
3381
+ } else if ((data === "e" || data === "E") && selected.kind === "actor" && selected.status !== "stopped" && (data === "e" || selected.value.local !== false)) {
3382
+ this.detailId = selected.id;
3383
+ this.openThinkingPicker(selected, data === "E" ? "project" : "session");
3384
+ } else if (data === "y" && (selected.kind === "globalActor" || selected.kind === "actor" && selected.status !== "stopped" && selected.value.local !== false)) {
3385
+ this.detailId = selected.id;
3386
+ this.openDeliveryPicker(selected);
3387
+ } else if (data === "v" && selected.kind === "actor" && selected.status !== "stopped" && selected.value.local !== false) {
3388
+ this.detailId = selected.id;
3389
+ this.openEventsPicker(selected);
3390
+ } else if (data === "o" && selected.kind === "actor" && selected.status !== "stopped" && selected.value.local !== false) {
3391
+ this.detailId = selected.id;
3392
+ this.openToolsPicker(selected);
3393
+ } else if (data === "c" && selected.kind === "actor" && selected.status !== "stopped" && selected.value.local !== false && this.onClearMessages) {
3394
+ this.onClearMessages(selected.value.id);
3395
+ } else if (data === "i" && (selected.kind === "globalActor" || selected.kind === "actor" && selected.value.local !== false)) {
3396
+ this.detailId = selected.id;
3397
+ this.openInstructionsEditor(selected);
3398
+ } else if (data === "p" && selected.kind === "globalActor" && this.onImportActor) {
3399
+ this.onImportActor(selected.value.id);
3400
+ } else if (data === "d" && selected.kind === "globalActor" && this.onRemoveGlobalActor) {
3401
+ this.onRemoveGlobalActor(selected.value.id);
3402
+ }
3403
+ }
3404
+ } else if (data === " " && this.pane === "entities") {
3405
+ const selected = entities[this.entityIndex];
3406
+ if (selected && this.hasTranscript(selected)) {
3407
+ this.detailId = selected.id;
3408
+ this.detailView = "transcript";
3409
+ this.detailScroll = 0;
3410
+ this.transcriptPageAnchor = void 0;
3411
+ this.transcriptFollowing = true;
3412
+ }
3413
+ } else if (matchesKey(data, Key.enter)) {
3414
+ if (this.overviewView === "activity" && this.pane === "phases") {
3415
+ this.pane = "entities";
3416
+ } else {
3417
+ const selected = entities[this.entityIndex];
3418
+ if (selected) {
3419
+ this.detailId = selected.id;
3420
+ this.detailView = "summary";
3421
+ this.detailScroll = 0;
3422
+ this.transcriptFollowing = true;
3423
+ }
3424
+ }
3425
+ } else if (data === "f") {
3426
+ const next = (filters.indexOf(this.filter) + 1) % filters.length;
3427
+ this.filter = filters[next] ?? "all";
3428
+ this.entityIndex = 0;
3429
+ this.selectedEntityId = void 0;
3430
+ this.tui.requestRender();
3431
+ return;
3432
+ } else if (data === "[") {
3433
+ this.runIndex = Math.min(Math.max(0, snapshot.runs.length - 1), this.runIndex + 1);
3434
+ this.selectedRunId = snapshot.runs[this.runIndex]?.id;
3435
+ this.runSelectionTouched = true;
3436
+ this.resetSelection();
3437
+ this.tui.requestRender();
3438
+ return;
3439
+ } else if (data === "]") {
3440
+ this.runIndex = Math.max(0, this.runIndex - 1);
3441
+ this.selectedRunId = snapshot.runs[this.runIndex]?.id;
3442
+ this.runSelectionTouched = true;
3443
+ this.resetSelection();
3444
+ this.tui.requestRender();
3445
+ return;
3446
+ } else if (data === "G") {
3447
+ if (this.overviewView === "activity" && this.pane === "phases") {
3448
+ this.phaseIndex = Math.max(0, panels.length - 1);
3449
+ this.phaseSelectionTouched = true;
3450
+ this.entityIndex = 0;
3451
+ this.selectedEntityId = void 0;
3452
+ } else {
3453
+ this.entityIndex = Math.max(0, entities.length - 1);
3454
+ }
3455
+ } else if (data === "g") {
3456
+ if (this.overviewView === "activity" && this.pane === "phases") {
3457
+ this.phaseIndex = 0;
3458
+ this.phaseSelectionTouched = true;
3459
+ this.entityIndex = 0;
3460
+ this.selectedEntityId = void 0;
3461
+ } else {
3462
+ this.entityIndex = 0;
3463
+ }
3464
+ }
3465
+ if (this.phaseSelectionTouched) this.selectedPhaseId = panels[this.phaseIndex]?.id;
3466
+ if (this.detailId) {
3467
+ this.pinDetailSelection(run, panel, this.overviewView === "activity");
3468
+ }
3469
+ if (this.pane === "entities") {
3470
+ this.selectedEntityId = entities[this.entityIndex]?.id;
3471
+ }
3472
+ this.tui.requestRender();
3473
+ }
3474
+ render(width) {
3475
+ if (width <= 0) return [];
3476
+ if (this.mode === "help") return this.renderHelp(width);
3477
+ if (this.mode === "agentMessageEditor") return this.renderAgentMessageEditor(width);
3478
+ if (this.mode === "instructionsEditor") {
3479
+ return this.renderInstructionsEditor(width);
3480
+ }
3481
+ if ((this.mode === "modelPicker" || this.mode === "thinkingPicker" || this.mode === "deliveryPicker" || this.mode === "eventsPicker" || this.mode === "toolsPicker") && this.picker) {
3482
+ return this.renderPicker(width);
3483
+ }
3484
+ const snapshot = this.snapshot();
3485
+ const run = this.selectRun(snapshot);
3486
+ const panels = phasePanels(snapshot, run);
3487
+ this.syncPhase(run, panels);
3488
+ const panel = panels[this.phaseIndex];
3489
+ const projectMesh = this.projectMesh(snapshot);
3490
+ const allEntities = entitiesForOverview(
3491
+ snapshot,
3492
+ run,
3493
+ panel,
3494
+ this.overviewView,
3495
+ projectMesh
3496
+ );
3497
+ const entities = allEntities.filter(
3498
+ (entity) => entity.kind === "main" || matchesFilter(entity.status, this.filter)
3499
+ );
3500
+ this.syncEntitySelection(entities, this.overviewView !== "activity");
3501
+ if (this.detailId) {
3502
+ const detail = allEntities.find((entity) => entity.id === this.detailId);
3503
+ if (detail) return this.renderDetail(width, snapshot, detail);
3504
+ this.closeDetail();
3505
+ }
3506
+ return this.renderOverview(
3507
+ width,
3508
+ snapshot,
3509
+ run,
3510
+ panels,
3511
+ entities,
3512
+ allEntities,
3513
+ projectMesh
3514
+ );
3515
+ }
3516
+ invalidate() {
3517
+ this.detailRenderer.invalidate();
3518
+ }
3519
+ dispose() {
3520
+ this.picker = void 0;
3521
+ this.editor = void 0;
3522
+ this.editorActorName = void 0;
3523
+ this.agentMessageTarget = void 0;
3524
+ this.pendingStop = void 0;
3525
+ this.stopGraphAnimation();
3526
+ this.stopGraphEffectsAnimation();
3527
+ this.detailRenderer.invalidate();
3528
+ this.mode = "overview";
3529
+ }
3530
+ transcriptTarget(entity) {
3531
+ if (entity.kind === "agent" || entity.kind === "actor") return entity.value;
3532
+ return void 0;
3533
+ }
3534
+ hasTranscript(entity) {
3535
+ return entity.kind === "agent" && this.agentTranscript !== void 0 || entity.kind === "actor" && this.actorTranscript !== void 0;
3536
+ }
3537
+ matchesTranscriptToolToggle(data) {
3538
+ if (this.keybindings) return this.keybindings.matches(data, "app.tools.expand");
3539
+ const keybindings = getKeybindings3();
3540
+ const keys = keybindings.getKeys("app.tools.expand");
3541
+ return keys.length > 0 ? keybindings.matches(data, "app.tools.expand") : matchesKey(data, Key.ctrl("o"));
3542
+ }
3543
+ transcriptToolToggleHint() {
3544
+ const keys = (this.keybindings ?? getKeybindings3()).getKeys("app.tools.expand");
3545
+ const key = keys.length > 0 ? keys.join("/") : this.keybindings ? "unbound" : "ctrl+o";
3546
+ return `${key} ${this.transcriptToolsExpanded ? "collapse" : "expand"} tools`;
3547
+ }
3548
+ messageTarget(entity) {
3549
+ if (entity.kind === "main") {
3550
+ return { id: entity.value.id, name: "Main", kind: "main" };
3551
+ }
3552
+ if (entity.kind === "peer") {
3553
+ return { id: entity.value.id, name: entity.value.name, kind: "peer" };
3554
+ }
3555
+ if (entity.kind === "agent") {
3556
+ return { id: entity.value.id, name: entity.value.name, kind: "agent" };
3557
+ }
3558
+ if (entity.kind === "actor") {
3559
+ return { id: entity.value.id, name: entity.value.name, kind: "actor" };
3560
+ }
3561
+ if (entity.kind === "meshParticipant") {
3562
+ return { id: entity.value.id, name: entity.value.name, kind: "meshParticipant" };
3563
+ }
3564
+ return void 0;
3565
+ }
3566
+ canMessage(entity, delivery) {
3567
+ const target = this.messageTarget(entity);
3568
+ if (!target) return false;
3569
+ if (target.kind === "agent") {
3570
+ if (!isActiveStatus(entity.status)) return false;
3571
+ if (entity.kind === "agent" && entity.value.capabilities && !entity.value.capabilities.includes(delivery)) {
3572
+ return false;
3573
+ }
3574
+ return Boolean(
3575
+ this.onTargetMessage || (delivery === "steer" ? this.onAgentSteer : this.onAgentFollowUp)
3576
+ );
3577
+ }
3578
+ if (!this.onTargetMessage) return false;
3579
+ if (target.kind === "actor") return entity.status !== "stopped" && delivery === "steer";
3580
+ if (target.kind === "meshParticipant" && entity.kind === "meshParticipant") {
3581
+ const participant = entity.value.participant;
3582
+ return participant ? !participant.stale && participant.capabilities.includes(delivery) : true;
3583
+ }
3584
+ return true;
3585
+ }
3586
+ openAgentMessageEditor(entity, delivery) {
3587
+ const target = this.messageTarget(entity);
3588
+ if (!target || !this.canMessage(entity, delivery)) return;
3589
+ const editor = new Editor(editorTheme(this.theme));
3590
+ editor.focused = true;
3591
+ editor.onSubmit = (text) => {
3592
+ const message = text.trim();
3593
+ if (!message) return;
3594
+ if (this.onTargetMessage) {
3595
+ this.onTargetMessage(target, message, delivery);
3596
+ } else if (target.kind === "agent") {
3597
+ if (delivery === "steer") this.onAgentSteer?.(target.id, message);
3598
+ else this.onAgentFollowUp?.(target.id, message);
3599
+ }
3600
+ this.closeAgentMessageEditor();
3601
+ };
3602
+ this.editor = editor;
3603
+ this.agentMessageTarget = { ...target, delivery };
3604
+ this.mode = "agentMessageEditor";
3605
+ }
3606
+ closeAgentMessageEditor() {
3607
+ this.editor = void 0;
3608
+ this.agentMessageTarget = void 0;
3609
+ this.mode = this.detailId ? "detail" : "overview";
3610
+ }
3611
+ canStop(entity) {
3612
+ if (!this.onAgentStop) return false;
3613
+ if (entity.kind === "agent") {
3614
+ return isActiveStatus(entity.status) && (!entity.value.capabilities || entity.value.capabilities.includes("stop"));
3615
+ }
3616
+ if (entity.kind === "meshParticipant") {
3617
+ const participant = entity.value.participant;
3618
+ return Boolean(
3619
+ participant && !participant.stale && participant.capabilities.includes("stop")
3620
+ );
3621
+ }
3622
+ return false;
3623
+ }
3624
+ requestParticipantStop(entity) {
3625
+ if (!this.onAgentStop || !this.canStop(entity)) return;
3626
+ const now = Date.now();
3627
+ if (this.pendingStop?.id === entity.value.id && this.pendingStop.expiresAt > now) {
3628
+ this.pendingStop = void 0;
3629
+ this.onAgentStop(entity.value.id);
3630
+ return;
3631
+ }
3632
+ this.pendingStop = { id: entity.value.id, expiresAt: now + 2e3 };
3633
+ }
3634
+ renderAgentMessageEditor(width) {
3635
+ if (!this.editor || !this.agentMessageTarget) return [];
3636
+ if (width < 24) return this.renderNarrowFallback(width, `${this.agentMessageTarget.delivery} \xB7 ${this.agentMessageTarget.name}`, "esc cancel");
3637
+ const target = this.agentMessageTarget;
3638
+ const label = target.kind === "actor" ? "queue actor message" : target.delivery === "steer" ? target.kind === "main" ? "message or steer Main" : "steer now" : "queue follow-up";
3639
+ const innerWidth = width - 2;
3640
+ const lines = [this.topBorder(width, `${label} \xB7 ${target.name}`)];
3641
+ for (const line of this.editor.render(innerWidth)) lines.push(this.row(width, line));
3642
+ lines.push(this.middleBorder(width));
3643
+ lines.push(
3644
+ this.row(
3645
+ width,
3646
+ this.theme.fg("dim", " enter send \xB7 shift+enter newline \xB7 esc cancel")
3647
+ )
3648
+ );
3649
+ lines.push(this.bottomBorder(width));
3650
+ return lines.map((line) => truncateToWidth4(line, width, ""));
3651
+ }
3652
+ renderHelp(width) {
3653
+ if (width < 24) return this.renderNarrowFallback(width, "dashboard help", "? or esc close");
3654
+ const lines = [this.topBorder(width, "Fabric dashboard help")];
3655
+ const mainActions = [
3656
+ this.onTargetMessage ? "s message/steer" : void 0,
3657
+ this.onTargetMessage ? "u queue follow-up" : void 0,
3658
+ "enter details"
3659
+ ].filter((value) => Boolean(value));
3660
+ const agentActions = [
3661
+ this.agentTranscript ? "space transcript peek" : void 0,
3662
+ this.onTargetMessage || this.onAgentSteer ? "s steer now" : void 0,
3663
+ this.onTargetMessage || this.onAgentFollowUp ? "u queue follow-up" : void 0,
3664
+ this.onAgentStop ? "x twice stop" : void 0,
3665
+ "enter details"
3666
+ ].filter((value) => Boolean(value));
3667
+ const actorActions = [
3668
+ this.actorTranscript ? "space transcript peek" : void 0,
3669
+ this.onTargetMessage ? "s queue message" : void 0,
3670
+ (this.modelSource || this.claudeModelSource) && this.onActorModel ? "m session model \xB7 M pin model" : void 0,
3671
+ this.onActorThinking ? "e session thinking \xB7 E pin thinking" : void 0,
3672
+ this.onActorDeliveryPolicy ? "y delivery policy" : void 0,
3673
+ this.onActorEvents ? "v events" : void 0,
3674
+ this.onActorTools ? "o tools" : void 0,
3675
+ this.onActorInstructions ? "i instructions" : void 0,
3676
+ this.onClearMessages ? "c clear mailbox" : void 0,
3677
+ this.onExportActor ? "x export" : void 0
3678
+ ].filter((value) => Boolean(value));
3679
+ const templateActions = [
3680
+ this.onGlobalDeliveryPolicy ? "y delivery policy" : void 0,
3681
+ this.onGlobalInstructions ? "i instructions" : void 0,
3682
+ this.onImportActor ? "p import" : void 0,
3683
+ this.onRemoveGlobalActor ? "d delete" : void 0
3684
+ ].filter((value) => Boolean(value));
3685
+ const help = [
3686
+ ["Navigate", "Topology: arrows/h/l move spatially \xB7 j/k ordered selection \xB7 tab next \xB7 enter inspect \xB7 esc back"],
3687
+ ["Views", "1 Activity \xB7 2 unified Topology"],
3688
+ ...this.onConversation ? [["Chat", "Shift+C opens the selected participant conversation \xB7 Esc returns to Main"]] : [],
3689
+ ["Topology", "Main branches into Participants (sessions, agents, actors) and Mesh (namespaced topics and hierarchical state); traffic travels on decaying edges"],
3690
+ ["Motion", "r replay/live \xB7 space pause/play \xB7 \u2190/\u2192 step \xB7 +/- speed \xB7 H history \xB7 M reduced motion"],
3691
+ ["Runs", "[ older \xB7 ] newer \xB7 f cycle status filter"],
3692
+ ...mainActions.length > 1 ? [["Main", mainActions.join(" \xB7 ")]] : [],
3693
+ ...agentActions.length > 1 ? [["Agents", agentActions.join(" \xB7 ")]] : [],
3694
+ ...actorActions.length > 0 ? [["Actors", actorActions.join(" \xB7 ")]] : [],
3695
+ ...templateActions.length > 0 ? [["Templates", templateActions.join(" \xB7 ")]] : [],
3696
+ [
3697
+ "Details",
3698
+ `\u2191\u2193/jk lazy scroll \xB7 g page top \xB7 G live tail \xB7 ${this.transcriptToolToggleHint()} \xB7 t transcript/summary \xB7 ? close help`
3699
+ ]
3700
+ ];
3701
+ for (const [label, value] of help) {
3702
+ const prefix = `${this.theme.fg("accent", `${label}:`)} `;
3703
+ const wrapped = wrapPlainText(value ?? "", Math.max(1, width - 2 - visibleWidth4(prefix)), 3);
3704
+ if (wrapped[0]) lines.push(this.row(width, prefix + wrapped[0]));
3705
+ for (const continuation of wrapped.slice(1)) {
3706
+ lines.push(this.row(width, " ".repeat(visibleWidth4(prefix)) + continuation));
3707
+ }
3708
+ }
3709
+ lines.push(this.middleBorder(width));
3710
+ lines.push(this.row(width, this.theme.fg("dim", " ? or esc close")));
3711
+ lines.push(this.bottomBorder(width));
3712
+ return lines.map((line) => truncateToWidth4(line, width, ""));
3713
+ }
3714
+ modelSourceForActor(actor) {
3715
+ return actor.runner === "claude" ? this.claudeModelSource : this.modelSource;
3716
+ }
3717
+ openModelPicker(entity, scope = "session") {
3718
+ if (entity.kind !== "actor" || !this.onActorModel) return;
3719
+ const actor = entity.value;
3720
+ if (scope === "project" && actor.local === false) return;
3721
+ const source = this.modelSourceForActor(actor);
3722
+ if (!source) return;
3723
+ const projectModel = actor.projectDefaults?.model ?? (actor.binding ? void 0 : actor.model);
3724
+ const currentValue = scope === "session" ? actor.binding?.model : projectModel;
3725
+ const runtimeDefault = actor.runner === "claude" ? "Fabric Claude model (or Claude Code runtime default)" : "Fabric OMP model (or host default)";
3726
+ this.pickerActorName = actor.name;
3727
+ this.picker = new FabricModelSelector({
3728
+ theme: this.theme,
3729
+ source,
3730
+ currentValue: currentValue ?? INHERIT_VALUE,
3731
+ headerText: scope === "session" ? actor.runner === "claude" ? `Model for Claude actor "${actor.name}" \xB7 session binding. Inherit uses the project default.` : `Model for actor "${actor.name}" \xB7 session binding. Inherit uses the project default.` : `Project model default for actor "${actor.name}". This pin is shared by every session.`,
3732
+ inheritName: scope === "session" ? `Use project default (${projectModel ?? runtimeDefault})` : `Clear project pin; use ${runtimeDefault}`,
3733
+ onSelect: (value) => {
3734
+ const model = value === INHERIT_VALUE ? void 0 : value;
3735
+ this.onActorModel(actor.id, model, scope);
3736
+ this.closeModelPicker();
3737
+ },
3738
+ onCancel: () => this.closeModelPicker()
3739
+ });
3740
+ this.picker.focused = true;
3741
+ this.mode = "modelPicker";
3742
+ }
3743
+ openThinkingPicker(entity, scope = "session") {
3744
+ if (entity.kind !== "actor" || !this.onActorThinking) return;
3745
+ const actor = entity.value;
3746
+ if (scope === "project" && actor.local === false) return;
3747
+ const projectThinking = actor.projectDefaults?.thinking ?? (actor.binding ? void 0 : actor.thinking);
3748
+ const currentValue = scope === "session" ? actor.binding?.thinking : projectThinking;
3749
+ this.pickerActorName = actor.name;
3750
+ this.picker = new FabricThinkingSelector({
3751
+ theme: this.theme,
3752
+ currentValue: currentValue ?? INHERIT_VALUE,
3753
+ headerText: scope === "session" ? `Thinking level for actor "${actor.name}" \xB7 session binding. Inherit uses the project default.` : `Project thinking default for actor "${actor.name}". This pin is shared by every session.`,
3754
+ inheritName: scope === "session" ? `Use project default (${projectThinking ?? "Fabric default"})` : "Clear project pin; use the Fabric default thinking level",
3755
+ onSelect: (value) => {
3756
+ const thinking = value === INHERIT_VALUE ? void 0 : value;
3757
+ this.onActorThinking(
3758
+ actor.id,
3759
+ isFabricThinking(thinking) ? thinking : void 0,
3760
+ scope
3761
+ );
3762
+ this.closeModelPicker();
3763
+ },
3764
+ onCancel: () => this.closeModelPicker()
3765
+ });
3766
+ this.picker.focused = true;
3767
+ this.mode = "thinkingPicker";
3768
+ }
3769
+ openDeliveryPicker(entity) {
3770
+ if (entity.kind !== "actor" && entity.kind !== "globalActor") return;
3771
+ const target = entity.value;
3772
+ const callback = entity.kind === "actor" ? this.onActorDeliveryPolicy : this.onGlobalDeliveryPolicy;
3773
+ if (!callback || entity.kind === "actor" && (entity.status === "stopped" || entity.value.local === false)) return;
3774
+ this.pickerActorName = target.name;
3775
+ this.picker = new FabricActorDeliverySelector({
3776
+ theme: this.theme,
3777
+ currentValue: { delivery: target.delivery, triggerTurn: target.triggerTurn },
3778
+ headerText: `Delivery policy for ${entity.kind === "actor" ? "actor" : "template"} "${target.name}". Active delivery requires an explicit resume choice.`,
3779
+ onSelect: (policy) => {
3780
+ callback(target.id, policy.delivery, policy.triggerTurn);
3781
+ this.closeModelPicker();
3782
+ },
3783
+ onCancel: () => this.closeModelPicker()
3784
+ });
3785
+ this.picker.focused = true;
3786
+ this.mode = "deliveryPicker";
3787
+ }
3788
+ openEventsPicker(entity) {
3789
+ if (entity.kind !== "actor" || entity.value.local === false || !this.onActorEvents) return;
3790
+ const actor = entity.value;
3791
+ this.pickerActorName = actor.name;
3792
+ this.picker = new FabricHostEventSelector({
3793
+ theme: this.theme,
3794
+ currentValue: actor.events,
3795
+ headerText: `Host events for actor "${actor.name}". Toggle with space, Enter to apply, Esc to cancel.`,
3796
+ onSelect: (events) => {
3797
+ this.onActorEvents(actor.id, events);
3798
+ this.closeModelPicker();
3799
+ },
3800
+ onCancel: () => this.closeModelPicker()
3801
+ });
3802
+ this.picker.focused = true;
3803
+ this.mode = "eventsPicker";
3804
+ }
3805
+ openToolsPicker(entity) {
3806
+ if (entity.kind !== "actor" || entity.value.local === false || !this.onActorTools) return;
3807
+ const actor = entity.value;
3808
+ this.pickerActorName = actor.name;
3809
+ this.picker = new FabricActorToolSelector({
3810
+ theme: this.theme,
3811
+ currentValue: actor.tools ?? this.actorDefaultTools,
3812
+ headerText: `Tools for actor "${actor.name}". Toggle with space, Enter to apply, Esc to cancel. OMP actors always retain fabric_exec.`,
3813
+ onSelect: (tools) => {
3814
+ this.onActorTools(actor.id, tools);
3815
+ this.closeModelPicker();
3816
+ },
3817
+ onCancel: () => this.closeModelPicker()
3818
+ });
3819
+ this.picker.focused = true;
3820
+ this.mode = "toolsPicker";
3821
+ }
3822
+ closeModelPicker() {
3823
+ this.picker = void 0;
3824
+ this.pickerActorName = void 0;
3825
+ this.mode = "detail";
3826
+ }
3827
+ /**
3828
+ * Open the embedded multi-line editor for an actor's default instruction.
3829
+ * Matches OMP's editor dialog convention (Enter submit, Shift+Enter newline,
3830
+ * Esc/Ctrl+C cancel) so a steering user edits the persona with the same
3831
+ * muscle memory as the chat input. Works for both live project actors and
3832
+ * global templates; the submit routes to the scope-appropriate callback.
3833
+ */
3834
+ openInstructionsEditor(entity) {
3835
+ let kind;
3836
+ let id;
3837
+ let name;
3838
+ let instructions;
3839
+ if (entity.kind === "actor") {
3840
+ if (entity.status === "stopped" || entity.value.local === false || !this.onActorInstructions) return;
3841
+ kind = "actor";
3842
+ id = entity.value.id;
3843
+ name = entity.value.name;
3844
+ instructions = entity.value.instructions;
3845
+ } else if (entity.kind === "globalActor") {
3846
+ if (!this.onGlobalInstructions) return;
3847
+ kind = "globalActor";
3848
+ id = entity.value.id;
3849
+ name = entity.value.name;
3850
+ instructions = entity.value.instructions;
3851
+ } else {
3852
+ return;
3853
+ }
3854
+ const editor = new Editor(editorTheme(this.theme));
3855
+ editor.focused = true;
3856
+ editor.setText(instructions);
3857
+ editor.onSubmit = (text) => {
3858
+ if (kind === "actor") this.onActorInstructions?.(id, text);
3859
+ else this.onGlobalInstructions?.(id, text);
3860
+ this.closeInstructionsEditor();
3861
+ };
3862
+ this.editor = editor;
3863
+ this.editorActorName = name;
3864
+ this.mode = "instructionsEditor";
3865
+ }
3866
+ closeInstructionsEditor() {
3867
+ this.editor = void 0;
3868
+ this.editorActorName = void 0;
3869
+ this.mode = "detail";
3870
+ }
3871
+ renderPicker(width) {
3872
+ if (!this.picker) return [];
3873
+ if (width < 24) return this.renderNarrowFallback(width, `actor \xB7 ${this.pickerActorName ?? ""}`, "esc cancel");
3874
+ const kind = this.mode === "thinkingPicker" ? "thinking" : this.mode === "deliveryPicker" ? "delivery" : this.mode === "eventsPicker" ? "events" : this.mode === "toolsPicker" ? "tools" : "model";
3875
+ const lines = [
3876
+ this.topBorder(width, `actor \xB7 ${this.pickerActorName ?? ""} \xB7 ${kind}`)
3877
+ ];
3878
+ const inner = this.picker.render(width - 2);
3879
+ for (const line of inner) lines.push(this.row(width, line));
3880
+ lines.push(this.middleBorder(width));
3881
+ const filterHint = this.mode === "thinkingPicker" || this.mode === "deliveryPicker" || this.mode === "eventsPicker" || this.mode === "toolsPicker" ? "" : " \xB7 type to filter";
3882
+ lines.push(
3883
+ this.row(
3884
+ width,
3885
+ this.theme.fg("dim", ` Enter to select \xB7 Esc to cancel${filterHint}`)
3886
+ )
3887
+ );
3888
+ lines.push(this.bottomBorder(width));
3889
+ return lines.map((line) => truncateToWidth4(line, width, ""));
3890
+ }
3891
+ renderInstructionsEditor(width) {
3892
+ if (!this.editor) return [];
3893
+ if (width < 24) return this.renderNarrowFallback(width, `instructions \xB7 ${this.editorActorName ?? ""}`, "esc cancel");
3894
+ const innerWidth = width - 2;
3895
+ const lines = [this.topBorder(width, `instructions \xB7 ${this.editorActorName ?? ""}`)];
3896
+ for (const line of this.editor.render(innerWidth)) {
3897
+ lines.push(this.row(width, line));
3898
+ }
3899
+ lines.push(this.middleBorder(width));
3900
+ lines.push(
3901
+ this.row(
3902
+ width,
3903
+ this.theme.fg("dim", " enter submit \xB7 shift+enter newline \xB7 esc cancel")
3904
+ )
3905
+ );
3906
+ lines.push(this.bottomBorder(width));
3907
+ return lines.map((line) => truncateToWidth4(line, width, ""));
3908
+ }
3909
+ projectMesh(snapshot) {
3910
+ if (this.overviewView !== "topology") return void 0;
3911
+ return buildProjectMeshTopology({
3912
+ main: snapshot.main,
3913
+ actors: snapshot.actors,
3914
+ agents: snapshot.agents,
3915
+ state: snapshot.state,
3916
+ events: snapshot.events,
3917
+ ...snapshot.participants ? { participants: snapshot.participants } : {},
3918
+ now: snapshot.now
3919
+ });
3920
+ }
3921
+ replayFrames(snapshot, topology) {
3922
+ return snapshot.events.flatMap((event) => {
3923
+ const route = topology.routes.find(
3924
+ (candidate) => candidate.topic === event.topic && candidate.kind === event.kind && (candidate.fromId === event.from.id || candidate.fromName === event.from.name)
3925
+ );
3926
+ return route ? [{ event, route }] : [];
3927
+ });
3928
+ }
3929
+ startGraphEffectsAnimation() {
3930
+ if (this.graphEffectsAnimation) return;
3931
+ this.graphReplayAdvancedAt = Date.now();
3932
+ this.graphEffectsAnimation = setInterval(() => {
3933
+ const now = Date.now();
3934
+ if (this.graphReplayPlaying && this.graphReplayIndex !== void 0 && this.graphReplayLength > 0 && now - this.graphReplayAdvancedAt >= 850 / this.graphReplaySpeed) {
3935
+ if (this.graphReplayIndex < this.graphReplayLength - 1) {
3936
+ this.graphReplayIndex++;
3937
+ this.graphReplayAdvancedAt = now;
3938
+ } else {
3939
+ this.graphReplayPlaying = false;
3940
+ }
3941
+ }
3942
+ this.tui.requestRender();
3943
+ }, 80);
3944
+ this.graphEffectsAnimation.unref?.();
3945
+ }
3946
+ stopGraphEffectsAnimation() {
3947
+ if (this.graphEffectsAnimation) clearInterval(this.graphEffectsAnimation);
3948
+ this.graphEffectsAnimation = void 0;
3949
+ this.graphReplayPlaying = false;
3950
+ }
3951
+ toggleGraphReplay(snapshot, topology) {
3952
+ const model = topology ?? this.projectMesh(snapshot);
3953
+ const frames = model ? this.replayFrames(snapshot, model) : [];
3954
+ this.graphReplayLength = frames.length;
3955
+ if (frames.length === 0) return;
3956
+ if (this.graphReplayIndex === void 0) {
3957
+ this.graphReplayIndex = 0;
3958
+ this.graphReplayPlaying = true;
3959
+ } else {
3960
+ this.graphReplayIndex = void 0;
3961
+ this.graphReplayPlaying = false;
3962
+ }
3963
+ this.graphReplayAdvancedAt = Date.now();
3964
+ }
3965
+ stepGraphReplay(delta) {
3966
+ if (this.graphReplayIndex === void 0 || this.graphReplayLength === 0) return;
3967
+ this.graphReplayIndex = Math.max(
3968
+ 0,
3969
+ Math.min(this.graphReplayLength - 1, this.graphReplayIndex + delta)
3970
+ );
3971
+ this.graphReplayPlaying = false;
3972
+ this.graphReplayAdvancedAt = Date.now();
3973
+ }
3974
+ setGraphCameraTarget(point) {
3975
+ if (!this.graphCameraInitialized) {
3976
+ this.graphCamera = { ...point };
3977
+ this.graphCameraTarget = { ...point };
3978
+ this.graphCameraInitialized = true;
3979
+ return;
3980
+ }
3981
+ if (this.graphCameraTarget.x === point.x && this.graphCameraTarget.y === point.y) return;
3982
+ this.graphCameraTarget = { ...point };
3983
+ this.graphAnimationAt = Date.now();
3984
+ if (this.graphAnimation) return;
3985
+ this.graphAnimation = setInterval(() => this.stepGraphCamera(), 16);
3986
+ this.graphAnimation.unref?.();
3987
+ }
3988
+ stopGraphAnimation() {
3989
+ if (this.graphAnimation) clearInterval(this.graphAnimation);
3990
+ this.graphAnimation = void 0;
3991
+ this.graphAnimationAt = 0;
3992
+ this.graphVelocity = { x: 0, y: 0 };
3993
+ this.graphCameraTarget = { ...this.graphCamera };
3994
+ }
3995
+ stepGraphCamera() {
3996
+ const now = Date.now();
3997
+ const elapsed = this.graphAnimationAt > 0 ? (now - this.graphAnimationAt) / 1e3 : 0.016;
3998
+ const dt = Math.max(8e-3, Math.min(0.032, elapsed));
3999
+ this.graphAnimationAt = now;
4000
+ const stiffness = 115;
4001
+ const damping = 19;
4002
+ const stepAxis = (position, target, velocity) => {
4003
+ const acceleration = stiffness * (target - position) - damping * velocity;
4004
+ const nextVelocity = velocity + acceleration * dt;
4005
+ return [position + nextVelocity * dt, nextVelocity];
4006
+ };
4007
+ [this.graphCamera.x, this.graphVelocity.x] = stepAxis(
4008
+ this.graphCamera.x,
4009
+ this.graphCameraTarget.x,
4010
+ this.graphVelocity.x
4011
+ );
4012
+ [this.graphCamera.y, this.graphVelocity.y] = stepAxis(
4013
+ this.graphCamera.y,
4014
+ this.graphCameraTarget.y,
4015
+ this.graphVelocity.y
4016
+ );
4017
+ const distance = Math.hypot(
4018
+ this.graphCameraTarget.x - this.graphCamera.x,
4019
+ this.graphCameraTarget.y - this.graphCamera.y
4020
+ );
4021
+ const speed = Math.hypot(this.graphVelocity.x, this.graphVelocity.y);
4022
+ if (distance < 0.025 && speed < 0.025) {
4023
+ this.graphCamera = { ...this.graphCameraTarget };
4024
+ this.graphVelocity = { x: 0, y: 0 };
4025
+ if (this.graphAnimation) clearInterval(this.graphAnimation);
4026
+ this.graphAnimation = void 0;
4027
+ }
4028
+ this.tui.requestRender();
4029
+ }
4030
+ renderOverview(width, snapshot, run, panels, entities, allEntities, meshModel) {
4031
+ if (width < 24) {
4032
+ return [truncateToWidth4("too narrow \xB7 need 24 cols", width)];
4033
+ }
4034
+ const innerWidth = width - 2;
4035
+ const terminalRows = Math.max(
4036
+ 1,
4037
+ this.tui.terminal?.rows ?? process.stdout.rows ?? 28
4038
+ );
4039
+ const overlayRows = dashboardOverlayRows(terminalRows);
4040
+ const lines = [];
4041
+ const title = this.overviewView === "activity" ? `Fabric \xB7 ${run?.name ?? "session"} \xB7 Activity` : "Fabric \xB7 Topology";
4042
+ lines.push(this.topBorder(width, title));
4043
+ const runAgents = run ? snapshot.agents.filter((agent) => agent.runId === run.id) : snapshot.agents;
4044
+ const activeAgents = runAgents.filter((agent) => isActiveStatus(agent.status)).length;
4045
+ const hasDetachedWork = activeAgents > 0;
4046
+ const runTokens = tokensFor(snapshot, run);
4047
+ const largeRun = runAgents.length > 25 || runTokens > 15e5;
4048
+ const elapsed = run ? formatDuration(((hasDetachedWork ? snapshot.now : run.finishedAt) ?? snapshot.now) - run.startedAt) : void 0;
4049
+ const activeActors = snapshot.actors.filter((actor) => isActiveStatus(actor.status)).length;
4050
+ const summary = (meshModel ? [
4051
+ run?.name ? `focus ${run.name}` : void 0,
4052
+ run?.currentPhaseId ? `current ${run.phases.find((phase) => phase.id === run.currentPhaseId)?.name ?? run.currentPhaseId}` : void 0,
4053
+ `Participants ${snapshot.agents.filter((agent) => isActiveStatus(agent.status)).length}/${snapshot.agents.length} agents \xB7 ${activeActors}/${snapshot.actors.length} actors \xB7 ${meshModel.participants.length} remote`,
4054
+ `Mesh ${meshModel.topics.length} topics \xB7 ${snapshot.state.length} state`,
4055
+ this.graphReplayIndex !== void 0 ? `${this.graphReplayPlaying ? "\u25B6" : "\u2161"} replay ${this.graphReplayIndex + 1}/${Math.max(1, this.graphReplayLength)} \xB7 ${this.graphReplaySpeed}\xD7` : void 0,
4056
+ snapshot.runs.length > 1 ? `run ${this.runIndex + 1}/${snapshot.runs.length}` : void 0
4057
+ ] : [
4058
+ this.overviewView === "topology" ? run?.name : void 0,
4059
+ run?.status,
4060
+ largeRun ? "\u26A0 large run" : void 0,
4061
+ `${activeAgents}/${runAgents.length} run agents active`,
4062
+ `${snapshot.actors.length} actors`,
4063
+ runTokens > 0 ? `${formatTokens(runTokens)} tok` : void 0,
4064
+ elapsed,
4065
+ snapshot.runs.length > 1 ? `run ${this.runIndex + 1}/${snapshot.runs.length}` : void 0
4066
+ ]).filter((value) => Boolean(value)).join(" \xB7 ");
4067
+ const summaryText = safeText(summary);
4068
+ let headerLine = summaryText;
4069
+ if (run?.description && this.overviewView === "activity") {
4070
+ const gap = " ";
4071
+ const availableDescription = innerWidth - visibleWidth4(summaryText) - gap.length;
4072
+ headerLine = availableDescription >= 12 ? `${padToWidth(
4073
+ this.theme.fg("muted", safeText(run.description)),
4074
+ availableDescription
4075
+ )}${gap}${this.theme.fg("dim", summaryText)}` : this.theme.fg("dim", summaryText);
4076
+ } else if (summaryText) {
4077
+ headerLine = this.theme.fg("dim", summaryText);
4078
+ }
4079
+ const minimumRows = 8;
4080
+ if (overlayRows < minimumRows) {
4081
+ return [
4082
+ title,
4083
+ this.theme.fg("dim", summaryText || "No Fabric activity yet"),
4084
+ this.theme.fg("dim", "1 activity \xB7 2 topology \xB7 arrows move \xB7 esc close")
4085
+ ].slice(0, overlayRows).map((line) => truncateToWidth4(line, width, ""));
4086
+ }
4087
+ lines.push(this.row(width, headerLine || this.theme.fg("muted", "No Fabric activity yet")));
4088
+ lines.push(this.middleBorder(width));
4089
+ const desiredRunEvents = run?.events.slice(-2) ?? [];
4090
+ const desiredMeshEventCount = Math.max(0, 2 - desiredRunEvents.length);
4091
+ const desiredMeshEvents = desiredMeshEventCount > 0 ? snapshot.events.slice(-desiredMeshEventCount) : [];
4092
+ const optionalEventRoom = Math.max(0, overlayRows - minimumRows);
4093
+ const eventRows = optionalEventRoom >= 2 ? Math.min(2, optionalEventRoom - 1) : 0;
4094
+ const runEventRows = Math.min(desiredRunEvents.length, eventRows);
4095
+ const meshEventRows = Math.max(0, eventRows - runEventRows);
4096
+ const runEvents = runEventRows > 0 ? desiredRunEvents.slice(-runEventRows) : [];
4097
+ const meshEvents = meshEventRows > 0 ? desiredMeshEvents.slice(-meshEventRows) : [];
4098
+ const eventChromeRows = eventRows > 0 ? eventRows + 1 : 0;
4099
+ const maxBody = Math.max(
4100
+ 1,
4101
+ Math.min(this.overviewView === "topology" ? 30 : 22, overlayRows - 7 - eventChromeRows)
4102
+ );
4103
+ if (this.overviewView === "topology") {
4104
+ const topology = meshModel ?? buildProjectMeshTopology({
4105
+ main: snapshot.main,
4106
+ actors: snapshot.actors,
4107
+ agents: snapshot.agents,
4108
+ state: snapshot.state,
4109
+ events: snapshot.events,
4110
+ ...snapshot.participants ? { participants: snapshot.participants } : {},
4111
+ now: snapshot.now
4112
+ });
4113
+ this.startGraphEffectsAnimation();
4114
+ const replayFrames = this.replayFrames(snapshot, topology);
4115
+ this.graphReplayLength = replayFrames.length;
4116
+ if (this.graphReplayIndex !== void 0 && replayFrames.length === 0) {
4117
+ this.graphReplayIndex = void 0;
4118
+ this.graphReplayPlaying = false;
4119
+ } else if (this.graphReplayIndex !== void 0) {
4120
+ this.graphReplayIndex = Math.min(this.graphReplayIndex, replayFrames.length - 1);
4121
+ }
4122
+ const replayFrame = this.graphReplayIndex === void 0 ? void 0 : replayFrames[this.graphReplayIndex];
4123
+ this.graphReplayLabel = replayFrame?.event.kind;
4124
+ const renderGraph = () => renderFabricTopologyPanel({
4125
+ theme: this.theme,
4126
+ filter: this.filter,
4127
+ selectedEntityId: this.selectedEntityId,
4128
+ snapshot,
4129
+ run,
4130
+ mesh: topology,
4131
+ allEntities,
4132
+ entities,
4133
+ width: innerWidth,
4134
+ height: maxBody,
4135
+ camera: this.graphCamera,
4136
+ invalidate: this.highlightInvalidate,
4137
+ animation: {
4138
+ now: Date.now(),
4139
+ reducedMotion: this.graphReducedMotion,
4140
+ showHistory: this.graphShowHistory,
4141
+ ...replayFrame ? { replayRouteId: replayFrame.route.id, replayLabel: replayFrame.event.kind } : {}
4142
+ }
4143
+ });
4144
+ const cameraWasInitialized = this.graphCameraInitialized;
4145
+ let rendered = renderGraph();
4146
+ this.graphPositions = rendered.positions;
4147
+ if (rendered.selectedPosition) this.setGraphCameraTarget(rendered.selectedPosition);
4148
+ if (!cameraWasInitialized && this.graphCameraInitialized) rendered = renderGraph();
4149
+ for (const line of rendered.lines) lines.push(this.row(width, line));
4150
+ } else if (innerWidth >= 88) {
4151
+ const leftWidth = Math.min(38, Math.max(28, Math.floor((innerWidth - 1) * 0.34)));
4152
+ const rightWidth = innerWidth - leftWidth - 1;
4153
+ const leftLines = this.renderPhasePanel(panels, leftWidth, maxBody);
4154
+ const rightLines = this.renderEntityPanel(entities, rightWidth, maxBody, snapshot.now);
4155
+ for (let index = 0; index < maxBody; index++) {
4156
+ const left = leftLines[index] ?? "";
4157
+ const right = rightLines[index] ?? "";
4158
+ lines.push(
4159
+ this.row(
4160
+ width,
4161
+ `${padToWidth(left, leftWidth)}${this.theme.fg("borderMuted", "\u2502")}${padToWidth(
4162
+ right,
4163
+ rightWidth
4164
+ )}`
4165
+ )
4166
+ );
4167
+ }
4168
+ } else {
4169
+ const panelRows = Math.max(2, maxBody - 1);
4170
+ const phaseHeight = Math.max(1, Math.min(panels.length + 1, Math.floor(panelRows * 0.45)));
4171
+ const entityHeight = Math.max(1, panelRows - phaseHeight);
4172
+ for (const line of this.renderPhasePanel(panels, innerWidth, phaseHeight)) {
4173
+ lines.push(this.row(width, line));
4174
+ }
4175
+ lines.push(this.row(width, this.theme.fg("borderMuted", "\u2500".repeat(innerWidth))));
4176
+ for (const line of this.renderEntityPanel(entities, innerWidth, entityHeight, snapshot.now)) {
4177
+ lines.push(this.row(width, line));
4178
+ }
4179
+ }
4180
+ if (eventRows > 0) {
4181
+ lines.push(this.middleBorder(width));
4182
+ let renderedEventRows = 0;
4183
+ for (const event of runEvents) {
4184
+ lines.push(
4185
+ this.row(
4186
+ width,
4187
+ colorStatus(
4188
+ this.theme,
4189
+ event.level === "success" ? "completed" : event.level,
4190
+ `[${formatClock(event.createdAt)}] ${safeText(event.message)}`
4191
+ )
4192
+ )
4193
+ );
4194
+ renderedEventRows++;
4195
+ }
4196
+ for (const event of meshEvents) {
4197
+ const target = event.to ? ` \u2192 ${event.to}` : "";
4198
+ const text = event.text ? ` \xB7 ${safeText(event.text)}` : "";
4199
+ lines.push(
4200
+ this.row(
4201
+ width,
4202
+ this.theme.fg(
4203
+ "dim",
4204
+ `[${formatClock(event.createdAt)}] ${event.topic} \xB7 ${event.from.name}${target}${text}`
4205
+ )
4206
+ )
4207
+ );
4208
+ renderedEventRows++;
4209
+ }
4210
+ while (renderedEventRows < eventRows) {
4211
+ lines.push(this.row(width, ""));
4212
+ renderedEventRows++;
4213
+ }
4214
+ }
4215
+ lines.push(this.middleBorder(width));
4216
+ const navigationHint = this.overviewView === "topology" ? this.graphReplayIndex !== void 0 ? `replay ${this.graphReplayIndex + 1}/${Math.max(1, this.graphReplayLength)}${this.graphReplayLabel ? ` \xB7 ${safeText(this.graphReplayLabel)}` : ""} \xB7 r live \xB7 space ${this.graphReplayPlaying ? "pause" : "play"} \xB7 \u2190/\u2192 step \xB7 +/- speed:${this.graphReplaySpeed}\xD7 \xB7 H history \xB7 M motion:${this.graphReducedMotion ? "reduced" : "full"} \xB7 ? help` : `arrows/h/l move \xB7 j/k order \xB7 r replay \xB7 H history \xB7 M motion:${this.graphReducedMotion ? "reduced" : "full"} \xB7 f filter:${this.filter} \xB7 1 activity \xB7 ? help` : `\u2191\u2193/jk select \xB7 \u2190\u2192/tab pane \xB7 enter inspect \xB7 f filter:${this.filter} \xB7 2 topology \xB7 [ older \xB7 ] newer \xB7 ? help`;
4217
+ lines.push(this.row(width, this.theme.fg("dim", navigationHint)));
4218
+ const selectedEntity = entities[this.entityIndex];
4219
+ const actionHint = this.pane === "entities" && selectedEntity ? this.theme.fg("muted", ` ${this.overviewActionHint(selectedEntity)}`) : "";
4220
+ lines.push(this.row(width, actionHint));
4221
+ lines.push(this.bottomBorder(width));
4222
+ return lines.map((line) => truncateToWidth4(line, width, ""));
4223
+ }
4224
+ overviewActionHint(entity) {
4225
+ if (entity.kind === "main") {
4226
+ const actions = [
4227
+ this.canMessage(entity, "steer") ? "s message/steer" : void 0,
4228
+ this.canMessage(entity, "followUp") ? "u queue follow-up" : void 0,
4229
+ "enter details"
4230
+ ].filter((value) => Boolean(value));
4231
+ return `Main actions: ${actions.join(" \xB7 ")}`;
4232
+ }
4233
+ if (entity.kind === "peer") {
4234
+ const actions = [
4235
+ this.canMessage(entity, "steer") ? "s steer" : void 0,
4236
+ this.canMessage(entity, "followUp") ? "u follow-up" : void 0,
4237
+ "enter details"
4238
+ ].filter((value) => Boolean(value));
4239
+ return `peer actions: ${actions.join(" \xB7 ")}`;
4240
+ }
4241
+ if (entity.kind === "actor" && entity.status !== "stopped") {
4242
+ const owned = entity.value.local !== false;
4243
+ const actions = [
4244
+ this.actorTranscript ? `space ${isActiveStatus(entity.status) ? "live " : ""}transcript peek` : void 0,
4245
+ this.canMessage(entity, "steer") ? "s queue message" : void 0,
4246
+ this.modelSourceForActor(entity.value) && this.onActorModel ? `m session model${owned ? " \xB7 M pin model" : ""}` : void 0,
4247
+ this.onActorThinking ? `e session thinking${owned ? " \xB7 E pin thinking" : ""}` : void 0,
4248
+ owned && this.onActorDeliveryPolicy ? "y delivery policy" : void 0,
4249
+ owned && this.onActorEvents ? "v events" : void 0,
4250
+ owned && this.onActorTools ? "o tools" : void 0,
4251
+ owned && this.onActorInstructions ? "i instructions" : void 0,
4252
+ owned && this.onClearMessages ? "c clear mailbox" : void 0,
4253
+ this.onExportActor ? "x export" : void 0,
4254
+ "enter details"
4255
+ ].filter((value) => Boolean(value));
4256
+ return `actor actions: ${actions.join(" \xB7 ")}`;
4257
+ }
4258
+ if (entity.kind === "globalActor") {
4259
+ const actions = [
4260
+ this.onGlobalDeliveryPolicy ? "y delivery policy" : void 0,
4261
+ this.onGlobalInstructions ? "i instructions" : void 0,
4262
+ this.onImportActor ? "p import" : void 0,
4263
+ this.onRemoveGlobalActor ? "d delete" : void 0,
4264
+ "enter details"
4265
+ ].filter((value) => Boolean(value));
4266
+ return `template actions: ${actions.join(" \xB7 ")}`;
4267
+ }
4268
+ if (entity.kind === "agent") {
4269
+ const armed = this.pendingStop?.id === entity.value.id && this.pendingStop.expiresAt > Date.now();
4270
+ const actions = [
4271
+ this.agentTranscript ? `space ${isActiveStatus(entity.status) ? "live " : ""}transcript peek` : void 0,
4272
+ this.canMessage(entity, "steer") ? "s steer" : void 0,
4273
+ this.canMessage(entity, "followUp") ? "u follow-up" : void 0,
4274
+ this.canStop(entity) ? armed ? "x again to stop" : "x stop" : void 0,
4275
+ "enter details"
4276
+ ].filter((value) => Boolean(value));
4277
+ return `agent actions: ${actions.join(" \xB7 ")}`;
4278
+ }
4279
+ if (entity.kind === "meshParticipant") {
4280
+ const actions = [
4281
+ this.canMessage(entity, "steer") ? "s steer" : void 0,
4282
+ this.canMessage(entity, "followUp") ? "u follow-up" : void 0,
4283
+ this.canStop(entity) ? "x twice to stop" : void 0,
4284
+ "enter details"
4285
+ ].filter((value) => Boolean(value));
4286
+ return `participant actions: ${actions.join(" \xB7 ")}`;
4287
+ }
4288
+ return "enter details";
4289
+ }
4290
+ renderPhasePanel(panels, width, height) {
4291
+ const lines = [
4292
+ truncateToWidth4(
4293
+ `${this.pane === "phases" ? this.theme.fg("accent", "\u25B8 ") : " "}${this.theme.fg(
4294
+ "accent",
4295
+ "Activity"
4296
+ )}`,
4297
+ width
4298
+ )
4299
+ ];
4300
+ const available = Math.max(0, height - 1);
4301
+ const start = Math.max(
4302
+ 0,
4303
+ Math.min(this.phaseIndex - Math.floor(available / 2), Math.max(0, panels.length - available))
4304
+ );
4305
+ for (let index = start; index < Math.min(panels.length, start + available); index++) {
4306
+ const panel = panels[index];
4307
+ if (!panel) continue;
4308
+ const selected = index === this.phaseIndex;
4309
+ const prefix = selected ? "\u203A " : " ";
4310
+ const count = panel.total > 0 ? `${panel.completed}/${panel.total}` : "";
4311
+ const raw = `${prefix}${colorStatus(this.theme, panel.status, statusGlyph(panel.status))} ${this.theme.fg("muted", safeText(
4312
+ panel.name
4313
+ ))}`;
4314
+ const countWidth = visibleWidth4(count);
4315
+ const contentWidth = Math.max(0, width - countWidth - (count ? 1 : 0));
4316
+ let line = `${padToWidth(raw, contentWidth)}${count ? ` ${this.theme.fg("dim", count)}` : ""}`;
4317
+ if (selected && this.pane === "phases") {
4318
+ line = this.theme.bg("selectedBg", padToWidth(line, width));
4319
+ }
4320
+ lines.push(truncateToWidth4(line, width, ""));
4321
+ }
4322
+ while (lines.length < height) lines.push("");
4323
+ return lines.slice(0, height);
4324
+ }
4325
+ renderEntityPanel(entities, width, height, now) {
4326
+ const lines = [];
4327
+ const available = Math.max(0, height);
4328
+ const groupedRows = [];
4329
+ const groups = groupEntities(entities);
4330
+ for (let groupIndex = 0; groupIndex < groups.length; groupIndex++) {
4331
+ const group = groups[groupIndex];
4332
+ if (groupIndex > 0) groupedRows.push({ type: "spacer" });
4333
+ groupedRows.push({ type: "group", group });
4334
+ for (const entry of group.entries) {
4335
+ groupedRows.push({ type: "entity", entity: entry.entity, entityIndex: entry.index });
4336
+ }
4337
+ }
4338
+ const selectedRow = Math.max(
4339
+ 0,
4340
+ groupedRows.findIndex(
4341
+ (row) => row.type === "entity" && row.entityIndex === this.entityIndex
4342
+ )
4343
+ );
4344
+ const start = Math.max(
4345
+ 0,
4346
+ Math.min(
4347
+ selectedRow - Math.floor(available / 2),
4348
+ Math.max(0, groupedRows.length - available)
4349
+ )
4350
+ );
4351
+ for (let index = start; index < Math.min(groupedRows.length, start + available); index++) {
4352
+ const row = groupedRows[index];
4353
+ if (!row) continue;
4354
+ if (row.type === "spacer") {
4355
+ lines.push("");
4356
+ continue;
4357
+ }
4358
+ if (row.type === "group") {
4359
+ lines.push(
4360
+ truncateToWidth4(
4361
+ this.theme.fg(
4362
+ "muted",
4363
+ ` ${this.theme.bold(row.group.label)} (${row.group.entries.length})`
4364
+ ),
4365
+ width,
4366
+ ""
4367
+ )
4368
+ );
4369
+ continue;
4370
+ }
4371
+ const entity = row.entity;
4372
+ const selected = row.entityIndex === this.entityIndex;
4373
+ const prefix = selected ? "\u203A " : " ";
4374
+ const lead = `${prefix}${colorStatus(this.theme, entity.status, statusGlyph(entity.status))} ${this.theme.fg("muted", safeText(
4375
+ entity.label
4376
+ ))}`;
4377
+ const tail = safeText(entityTail(entity, now));
4378
+ let line = tail ? `${lead} ${this.theme.fg("dim", tail)}` : lead;
4379
+ if (selected && this.pane === "entities") {
4380
+ line = this.theme.bg("selectedBg", padToWidth(line, width));
4381
+ }
4382
+ lines.push(truncateToWidth4(line, width, ""));
4383
+ }
4384
+ if (entities.length === 0 && available > 0) {
4385
+ const label = this.filter === "all" ? "activity" : `${this.filter} activity`;
4386
+ lines.push(this.theme.fg("dim", ` (no ${label}; press f to change filter)`));
4387
+ }
4388
+ while (lines.length < height) lines.push("");
4389
+ return lines.slice(0, height);
4390
+ }
4391
+ renderDetail(width, snapshot, entity) {
4392
+ const result = this.detailRenderer.render(
4393
+ width,
4394
+ snapshot,
4395
+ entity,
4396
+ {
4397
+ view: this.detailView,
4398
+ scroll: this.detailScroll,
4399
+ pageAnchor: this.transcriptPageAnchor,
4400
+ transcriptFollowing: this.transcriptFollowing,
4401
+ transcriptToolsExpanded: this.transcriptToolsExpanded
4402
+ },
4403
+ this.detailActionHint(entity),
4404
+ (entity.kind === "agent" || entity.kind === "actor") && this.detailView === "transcript" ? this.transcriptToolToggleHint() : ""
4405
+ );
4406
+ this.detailScroll = result.scroll;
4407
+ this.detailMaxScroll = result.maxScroll;
4408
+ this.transcriptPageAnchor = result.pageAnchor;
4409
+ return result.lines;
4410
+ }
4411
+ detailActionHint(entity) {
4412
+ if (entity.kind === "main") {
4413
+ const actions = [
4414
+ this.canMessage(entity, "steer") ? "s message/steer now" : void 0,
4415
+ this.canMessage(entity, "followUp") ? "u queue follow-up" : void 0
4416
+ ].filter((value) => Boolean(value));
4417
+ return actions.length > 0 ? `Main OMP agent actions: ${actions.join(" \xB7 ")}` : "Main OMP agent controls are unavailable in this session.";
4418
+ }
4419
+ if (entity.kind === "peer") {
4420
+ const actions = [
4421
+ this.canMessage(entity, "steer") ? "s steer over mesh" : void 0,
4422
+ this.canMessage(entity, "followUp") ? "u queue follow-up over mesh" : void 0
4423
+ ].filter((value) => Boolean(value));
4424
+ return actions.length > 0 ? `Peer session actions: ${actions.join(" \xB7 ")}` : "Peer session is read-only.";
4425
+ }
4426
+ if (entity.kind === "agent") {
4427
+ const armed = this.pendingStop?.id === entity.value.id && this.pendingStop.expiresAt > Date.now();
4428
+ const actions = [
4429
+ this.canMessage(entity, "steer") ? "s steer now" : void 0,
4430
+ this.canMessage(entity, "followUp") ? "u queue follow-up" : void 0,
4431
+ this.canStop(entity) ? armed ? "x again to confirm stop" : "x stop" : void 0
4432
+ ].filter((value) => Boolean(value));
4433
+ const controls = actions.length > 0 ? `One-shot agent actions: ${actions.join(" \xB7 ")}. ` : "One-shot agent. ";
4434
+ return `${controls}Model and thinking are fixed at spawn; use a persistent actor for editable runtime settings.`;
4435
+ }
4436
+ if (entity.kind === "actor" && entity.status !== "stopped") {
4437
+ const owned = entity.value.local !== false;
4438
+ const actions = [
4439
+ this.canMessage(entity, "steer") ? "s queue message" : void 0,
4440
+ this.modelSourceForActor(entity.value) && this.onActorModel ? `m session model${owned ? " \xB7 M pin model" : ""}` : void 0,
4441
+ this.onActorThinking ? `e session thinking${owned ? " \xB7 E pin thinking" : ""}` : void 0,
4442
+ owned && this.onActorDeliveryPolicy ? "y delivery policy" : void 0,
4443
+ owned && this.onActorEvents ? "v events" : void 0,
4444
+ owned && this.onActorTools ? "o tools" : void 0,
4445
+ owned && this.onClearMessages ? "c clear mailbox" : void 0,
4446
+ owned && this.onActorInstructions ? "i instructions" : void 0,
4447
+ this.onExportActor ? "x export\u2192global" : void 0
4448
+ ].filter((value) => Boolean(value));
4449
+ return actions.length > 0 ? `Actor actions: ${actions.join(" \xB7 ")}` : "Actor settings are read-only in this session.";
4450
+ }
4451
+ if (entity.kind === "meshParticipant") {
4452
+ const actions = [
4453
+ this.canMessage(entity, "steer") ? "s steer over mesh" : void 0,
4454
+ this.canMessage(entity, "followUp") ? "u queue follow-up over mesh" : void 0,
4455
+ this.canStop(entity) ? "x twice to stop" : void 0
4456
+ ].filter((value) => Boolean(value));
4457
+ return actions.length > 0 ? `Remote participant actions: ${actions.join(" \xB7 ")}` : "Remote participant is read-only.";
4458
+ }
4459
+ if (entity.kind === "globalActor") {
4460
+ const actions = [
4461
+ this.onGlobalDeliveryPolicy ? "y delivery policy" : void 0,
4462
+ this.onGlobalInstructions ? "i instructions" : void 0,
4463
+ this.onImportActor ? "p import" : void 0,
4464
+ this.onRemoveGlobalActor ? "d delete" : void 0
4465
+ ].filter((value) => Boolean(value));
4466
+ return actions.length > 0 ? `Template actions: ${actions.join(" \xB7 ")}` : "Global template is read-only in this session.";
4467
+ }
4468
+ return "Read-only detail.";
4469
+ }
4470
+ syncEntitySelection(entities, preferAttention = false) {
4471
+ if (entities.length === 0) {
4472
+ this.entityIndex = 0;
4473
+ this.selectedEntityId = void 0;
4474
+ return;
4475
+ }
4476
+ const retainedIndex = this.selectedEntityId ? entities.findIndex((entity) => entity.id === this.selectedEntityId) : -1;
4477
+ const failedIndex = preferAttention ? entities.findIndex(
4478
+ (entity) => entity.kind !== "main" && ["failed", "timed_out", "error"].includes(entity.status)
4479
+ ) : -1;
4480
+ const blockedIndex = preferAttention ? entities.findIndex(
4481
+ (entity) => entity.kind !== "main" && entity.status === "blocked"
4482
+ ) : -1;
4483
+ const activeIndex = preferAttention ? entities.findIndex(
4484
+ (entity) => entity.kind !== "main" && isActiveStatus(entity.status)
4485
+ ) : -1;
4486
+ const attentionIndex = failedIndex >= 0 ? failedIndex : blockedIndex >= 0 ? blockedIndex : activeIndex;
4487
+ const firstWorkIndex = entities.findIndex((entity) => entity.kind !== "main");
4488
+ this.entityIndex = retainedIndex >= 0 ? retainedIndex : attentionIndex >= 0 ? attentionIndex : firstWorkIndex >= 0 ? firstWorkIndex : Math.max(0, Math.min(this.entityIndex, entities.length - 1));
4489
+ this.selectedEntityId = entities[this.entityIndex]?.id;
4490
+ }
4491
+ selectRun(snapshot) {
4492
+ if (snapshot.runs.length === 0) {
4493
+ this.runIndex = 0;
4494
+ this.selectedRunId = void 0;
4495
+ return void 0;
4496
+ }
4497
+ if (!this.runSelectionTouched) {
4498
+ this.runIndex = 0;
4499
+ this.selectedRunId = snapshot.runs[0]?.id;
4500
+ return snapshot.runs[0];
4501
+ }
4502
+ const retainedIndex = this.selectedRunId ? snapshot.runs.findIndex((run) => run.id === this.selectedRunId) : -1;
4503
+ this.runIndex = retainedIndex >= 0 ? retainedIndex : Math.max(0, Math.min(this.runIndex, snapshot.runs.length - 1));
4504
+ this.selectedRunId = snapshot.runs[this.runIndex]?.id;
4505
+ return snapshot.runs[this.runIndex];
4506
+ }
4507
+ syncPhase(run, panels) {
4508
+ if (panels.length === 0) {
4509
+ this.phaseIndex = 0;
4510
+ this.selectedPhaseId = void 0;
4511
+ return;
4512
+ }
4513
+ if (!this.phaseSelectionTouched) {
4514
+ const current = run?.currentPhaseId ? panels.findIndex((panel) => panel.id === run.currentPhaseId) : -1;
4515
+ const activeRunActivity = panels.findIndex(
4516
+ (panel) => panel.kind === "unphased" && isActiveStatus(panel.status)
4517
+ );
4518
+ if (current >= 0 && isActiveStatus(panels[current].status)) {
4519
+ this.phaseIndex = current;
4520
+ } else if (activeRunActivity >= 0) {
4521
+ this.phaseIndex = activeRunActivity;
4522
+ } else if (current >= 0) {
4523
+ this.phaseIndex = current;
4524
+ } else {
4525
+ this.phaseIndex = 0;
4526
+ }
4527
+ } else {
4528
+ const retainedIndex = this.selectedPhaseId ? panels.findIndex((panel) => panel.id === this.selectedPhaseId) : -1;
4529
+ this.phaseIndex = retainedIndex >= 0 ? retainedIndex : Math.max(0, Math.min(this.phaseIndex, panels.length - 1));
4530
+ }
4531
+ this.phaseIndex = Math.max(0, Math.min(this.phaseIndex, panels.length - 1));
4532
+ this.selectedPhaseId = panels[this.phaseIndex]?.id;
4533
+ }
4534
+ resetSelection() {
4535
+ this.phaseIndex = 0;
4536
+ this.entityIndex = 0;
4537
+ this.selectedEntityId = void 0;
4538
+ this.phaseSelectionTouched = false;
4539
+ this.selectedPhaseId = void 0;
4540
+ this.detailId = void 0;
4541
+ this.detailScroll = 0;
4542
+ this.detailMaxScroll = 0;
4543
+ this.transcriptPageAnchor = void 0;
4544
+ this.detailSelectionRestore = void 0;
4545
+ this.detailView = "summary";
4546
+ this.transcriptFollowing = true;
4547
+ this.pane = this.overviewView === "activity" ? "phases" : "entities";
4548
+ }
4549
+ pinDetailSelection(run, panel, pinPhase) {
4550
+ this.detailSelectionRestore ??= {
4551
+ runSelectionTouched: this.runSelectionTouched,
4552
+ phaseSelectionTouched: this.phaseSelectionTouched
4553
+ };
4554
+ this.runSelectionTouched = true;
4555
+ this.selectedRunId = run?.id;
4556
+ if (pinPhase) {
4557
+ this.phaseSelectionTouched = true;
4558
+ this.selectedPhaseId = panel?.id;
4559
+ }
4560
+ }
4561
+ closeDetail() {
4562
+ const restore = this.detailSelectionRestore;
4563
+ if (restore) {
4564
+ this.runSelectionTouched = restore.runSelectionTouched;
4565
+ this.phaseSelectionTouched = restore.phaseSelectionTouched;
4566
+ }
4567
+ this.detailSelectionRestore = void 0;
4568
+ this.detailId = void 0;
4569
+ this.detailScroll = 0;
4570
+ this.detailMaxScroll = 0;
4571
+ this.transcriptPageAnchor = void 0;
4572
+ this.detailView = "summary";
4573
+ this.transcriptFollowing = true;
4574
+ }
4575
+ renderNarrowFallback(width, label, hint) {
4576
+ return [safeText(label), hint].map((line) => truncateToWidth4(line, width, "")).filter((line) => visibleWidth4(line) > 0);
4577
+ }
4578
+ topBorder(width, title) {
4579
+ const border = (value) => this.theme.fg("borderMuted", value);
4580
+ const safeTitle = truncateToWidth4(safeText(title), Math.max(0, width - 6));
4581
+ const styledTitle = ` ${this.theme.fg("accent", safeTitle)} `;
4582
+ const remaining = Math.max(0, width - 2 - visibleWidth4(styledTitle));
4583
+ const left = Math.floor(remaining / 2);
4584
+ const right = remaining - left;
4585
+ return `${border(`\u256D${"\u2500".repeat(left)}`)}${styledTitle}${border(`${"\u2500".repeat(right)}\u256E`)}`;
4586
+ }
4587
+ middleBorder(width) {
4588
+ return this.theme.fg("borderMuted", `\u251C${"\u2500".repeat(Math.max(0, width - 2))}\u2524`);
4589
+ }
4590
+ bottomBorder(width) {
4591
+ return this.theme.fg("borderMuted", `\u2570${"\u2500".repeat(Math.max(0, width - 2))}\u256F`);
4592
+ }
4593
+ row(width, content) {
4594
+ const innerWidth = Math.max(0, width - 2);
4595
+ return `${this.theme.fg("borderMuted", "\u2502")}${padToWidth(content, innerWidth)}${this.theme.fg(
4596
+ "borderMuted",
4597
+ "\u2502"
4598
+ )}`;
4599
+ }
4600
+ };
4601
+ export {
4602
+ FabricDashboard
4603
+ };
4604
+ //# sourceMappingURL=dashboard.js.map