@yancyyu/openhermit 1.5.8

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 (980) hide show
  1. package/LICENSE +611 -0
  2. package/README.md +220 -0
  3. package/bin/hermit.mjs +364 -0
  4. package/bin/kill-dev.js +20 -0
  5. package/dist-renderer/assets/01-BApSFlV4.png +0 -0
  6. package/dist-renderer/assets/02-CRQGs29u.png +0 -0
  7. package/dist-renderer/assets/03-BFCM2jnD.png +0 -0
  8. package/dist-renderer/assets/04-B2FThbKO.png +0 -0
  9. package/dist-renderer/assets/05-D9p0Znkd.png +0 -0
  10. package/dist-renderer/assets/06-DZAfbDlP.png +0 -0
  11. package/dist-renderer/assets/07-B_PXWGCc.png +0 -0
  12. package/dist-renderer/assets/08-DGRMZ6sl.png +0 -0
  13. package/dist-renderer/assets/09-SGCQvc7U.png +0 -0
  14. package/dist-renderer/assets/10-Cve81Q3W.png +0 -0
  15. package/dist-renderer/assets/11-DGglolDW.png +0 -0
  16. package/dist-renderer/assets/12-C3lnu79c.png +0 -0
  17. package/dist-renderer/assets/13-M59meqdw.png +0 -0
  18. package/dist-renderer/assets/ProjectEditorOverlay-BNoDw9T1.js +57 -0
  19. package/dist-renderer/assets/TeamGraphOverlay-CfGRKQIu.js +1 -0
  20. package/dist-renderer/assets/_basePickBy-Ct8Hm5_h.js +1 -0
  21. package/dist-renderer/assets/_baseUniq-BofrAFBx.js +1 -0
  22. package/dist-renderer/assets/apl-B4CMkyY2.js +1 -0
  23. package/dist-renderer/assets/arc-AbJgatzR.js +1 -0
  24. package/dist-renderer/assets/architectureDiagram-VXUJARFQ-gpniCJVk.js +36 -0
  25. package/dist-renderer/assets/asciiarmor-Df11BRmG.js +1 -0
  26. package/dist-renderer/assets/asn1-EdZsLKOL.js +1 -0
  27. package/dist-renderer/assets/asterisk-B-8jnY81.js +1 -0
  28. package/dist-renderer/assets/blockDiagram-VD42YOAC-aBbbmONC.js +122 -0
  29. package/dist-renderer/assets/brainfuck-C4LP7Hcl.js +1 -0
  30. package/dist-renderer/assets/c4Diagram-YG6GDRKO-DJio1IsU.js +10 -0
  31. package/dist-renderer/assets/channel-CZ8sd5Xf.js +1 -0
  32. package/dist-renderer/assets/chunk-4BX2VUAB-D1_HKao2.js +1 -0
  33. package/dist-renderer/assets/chunk-55IACEB6-NAmVxF4k.js +1 -0
  34. package/dist-renderer/assets/chunk-B4BG7PRW-Ce829laz.js +165 -0
  35. package/dist-renderer/assets/chunk-DI55MBZ5-Ct2Le12y.js +220 -0
  36. package/dist-renderer/assets/chunk-FMBD7UC4-Cie3DzKk.js +15 -0
  37. package/dist-renderer/assets/chunk-QN33PNHL-4f5Yb50e.js +1 -0
  38. package/dist-renderer/assets/chunk-QZHKN3VN-D9ranl9c.js +1 -0
  39. package/dist-renderer/assets/chunk-TZMSLE5B-bdGZWlEy.js +1 -0
  40. package/dist-renderer/assets/classDiagram-2ON5EDUG-CMcfSKj5.js +1 -0
  41. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-CMcfSKj5.js +1 -0
  42. package/dist-renderer/assets/clike-B9uivgTg.js +1 -0
  43. package/dist-renderer/assets/clojure-BMjYHr_A.js +1 -0
  44. package/dist-renderer/assets/clone-CMuwA8RV.js +1 -0
  45. package/dist-renderer/assets/cmake-BQqOBYOt.js +1 -0
  46. package/dist-renderer/assets/cobol-CWcv1MsR.js +1 -0
  47. package/dist-renderer/assets/coffeescript-S37ZYGWr.js +1 -0
  48. package/dist-renderer/assets/commonlisp-DBKNyK5s.js +1 -0
  49. package/dist-renderer/assets/cose-bilkent-S5V4N54A-C6tvfcVi.js +1 -0
  50. package/dist-renderer/assets/crystal-SjHAIU92.js +1 -0
  51. package/dist-renderer/assets/css-BnMrqG3P.js +1 -0
  52. package/dist-renderer/assets/cypher-C_CwsFkJ.js +1 -0
  53. package/dist-renderer/assets/cytoscape.esm-DsxaTqgk.js +331 -0
  54. package/dist-renderer/assets/d-pRatUO7H.js +1 -0
  55. package/dist-renderer/assets/dagre-6UL2VRFP-B-4qcZam.js +4 -0
  56. package/dist-renderer/assets/defaultLocale-DX6XiGOO.js +1 -0
  57. package/dist-renderer/assets/diagram-PSM6KHXK-CwT3TLjx.js +24 -0
  58. package/dist-renderer/assets/diagram-QEK2KX5R-BWH6-ZFd.js +43 -0
  59. package/dist-renderer/assets/diagram-S2PKOQOG-DfpPnfi1.js +24 -0
  60. package/dist-renderer/assets/diff-DbItnlRl.js +1 -0
  61. package/dist-renderer/assets/dockerfile-BKs6k2Af.js +1 -0
  62. package/dist-renderer/assets/dtd-DF_7sFjM.js +1 -0
  63. package/dist-renderer/assets/dylan-DwRh75JA.js +1 -0
  64. package/dist-renderer/assets/ebnf-CDyGwa7X.js +1 -0
  65. package/dist-renderer/assets/ecl-Cabwm37j.js +1 -0
  66. package/dist-renderer/assets/eiffel-CnydiIhH.js +1 -0
  67. package/dist-renderer/assets/elm-vLlmbW-K.js +1 -0
  68. package/dist-renderer/assets/erDiagram-Q2GNP2WA-BFbEFR4x.js +60 -0
  69. package/dist-renderer/assets/erlang-BNw1qcRV.js +1 -0
  70. package/dist-renderer/assets/factor-kuTfRLto.js +1 -0
  71. package/dist-renderer/assets/favicon-B8xY-GVk.png +0 -0
  72. package/dist-renderer/assets/fcl-Kvtd6kyn.js +1 -0
  73. package/dist-renderer/assets/flowDiagram-NV44I4VS-Dg3cf5hW.js +162 -0
  74. package/dist-renderer/assets/forth-Ffai-XNe.js +1 -0
  75. package/dist-renderer/assets/fortran-DYz_wnZ1.js +1 -0
  76. package/dist-renderer/assets/ganttDiagram-JELNMOA3-B21y55W5.js +267 -0
  77. package/dist-renderer/assets/gas-Bneqetm1.js +1 -0
  78. package/dist-renderer/assets/gherkin-heZmZLOM.js +1 -0
  79. package/dist-renderer/assets/gitGraphDiagram-V2S2FVAM-BDV3BJzn.js +65 -0
  80. package/dist-renderer/assets/graph-BfaZ4hZt.js +1 -0
  81. package/dist-renderer/assets/groovy-D9Dt4D0W.js +1 -0
  82. package/dist-renderer/assets/haskell-BWDZoCOh.js +1 -0
  83. package/dist-renderer/assets/haxe-H-WmDvRZ.js +1 -0
  84. package/dist-renderer/assets/http-DBlCnlav.js +1 -0
  85. package/dist-renderer/assets/idl-BEugSyMb.js +1 -0
  86. package/dist-renderer/assets/index-BMXHMpkG.js +1 -0
  87. package/dist-renderer/assets/index-CCqtDawH.js +1 -0
  88. package/dist-renderer/assets/index-CVMSpK8C.js +1 -0
  89. package/dist-renderer/assets/index-CZltVMDP.js +1844 -0
  90. package/dist-renderer/assets/index-CaG9mf8s.css +1 -0
  91. package/dist-renderer/assets/index-Ct0-y9TF.js +1 -0
  92. package/dist-renderer/assets/index-pMg_LlsS.js +1 -0
  93. package/dist-renderer/assets/infoDiagram-HS3SLOUP-DvMlS0CL.js +2 -0
  94. package/dist-renderer/assets/init-Gi6I4Gst.js +1 -0
  95. package/dist-renderer/assets/javascript-qCveANmP.js +1 -0
  96. package/dist-renderer/assets/journeyDiagram-XKPGCS4Q-DIyMluRv.js +139 -0
  97. package/dist-renderer/assets/julia-DuME0IfC.js +1 -0
  98. package/dist-renderer/assets/kanban-definition-3W4ZIXB7-CVOx8f-7.js +89 -0
  99. package/dist-renderer/assets/katex-DGN8GczM.js +261 -0
  100. package/dist-renderer/assets/layout-BPKIXUf4.js +1 -0
  101. package/dist-renderer/assets/linear-CScZGLr2.js +1 -0
  102. package/dist-renderer/assets/livescript-BwQOo05w.js +1 -0
  103. package/dist-renderer/assets/lua-BgMRiT3U.js +1 -0
  104. package/dist-renderer/assets/mathematica-DTrFuWx2.js +1 -0
  105. package/dist-renderer/assets/mbox-CNhZ1qSd.js +1 -0
  106. package/dist-renderer/assets/mindmap-definition-VGOIOE7T-CmDQ7Wo6.js +68 -0
  107. package/dist-renderer/assets/mirc-CjQqDB4T.js +1 -0
  108. package/dist-renderer/assets/mllike-CXdrOF99.js +1 -0
  109. package/dist-renderer/assets/modelica-Dc1JOy9r.js +1 -0
  110. package/dist-renderer/assets/mscgen-BA5vi2Kp.js +1 -0
  111. package/dist-renderer/assets/mumps-BT43cFF4.js +1 -0
  112. package/dist-renderer/assets/nginx-DdIZxoE0.js +1 -0
  113. package/dist-renderer/assets/nsis-LdVXkNf5.js +1 -0
  114. package/dist-renderer/assets/ntriples-BfvgReVJ.js +1 -0
  115. package/dist-renderer/assets/octave-Ck1zUtKM.js +1 -0
  116. package/dist-renderer/assets/ordinal-Cboi1Yqb.js +1 -0
  117. package/dist-renderer/assets/oz-BzwKVEFT.js +1 -0
  118. package/dist-renderer/assets/pascal--L3eBynH.js +1 -0
  119. package/dist-renderer/assets/perl-CdXCOZ3F.js +1 -0
  120. package/dist-renderer/assets/pieDiagram-ADFJNKIX-DbVClin-.js +30 -0
  121. package/dist-renderer/assets/pig-CevX1Tat.js +1 -0
  122. package/dist-renderer/assets/powershell-CFHJl5sT.js +1 -0
  123. package/dist-renderer/assets/properties-C78fOPTZ.js +1 -0
  124. package/dist-renderer/assets/protobuf-ChK-085T.js +1 -0
  125. package/dist-renderer/assets/pug-DukmZTjD.js +1 -0
  126. package/dist-renderer/assets/puppet-DMA9R1ak.js +1 -0
  127. package/dist-renderer/assets/python-BuPzkPfP.js +1 -0
  128. package/dist-renderer/assets/q-pXgVlZs6.js +1 -0
  129. package/dist-renderer/assets/quadrantDiagram-AYHSOK5B-CAB0MYcW.js +7 -0
  130. package/dist-renderer/assets/r-DUYO_cvP.js +1 -0
  131. package/dist-renderer/assets/requirementDiagram-UZGBJVZJ-w2Lfpg3T.js +64 -0
  132. package/dist-renderer/assets/rpm-CTu-6PCP.js +1 -0
  133. package/dist-renderer/assets/ruby-B2Rjki9n.js +1 -0
  134. package/dist-renderer/assets/sankeyDiagram-TZEHDZUN-kvG1QoKY.js +10 -0
  135. package/dist-renderer/assets/sas-B4kiWyti.js +1 -0
  136. package/dist-renderer/assets/scheme-C41bIUwD.js +1 -0
  137. package/dist-renderer/assets/sequenceDiagram-WL72ISMW-DCVBQ23J.js +145 -0
  138. package/dist-renderer/assets/shell-CjFT_Tl9.js +1 -0
  139. package/dist-renderer/assets/sieve-C3Gn_uJK.js +1 -0
  140. package/dist-renderer/assets/simple-mode-GW_nhZxv.js +1 -0
  141. package/dist-renderer/assets/smalltalk-CnHTOXQT.js +1 -0
  142. package/dist-renderer/assets/solr-DehyRSwq.js +1 -0
  143. package/dist-renderer/assets/sparql-DkYu6x3z.js +1 -0
  144. package/dist-renderer/assets/splashScene-C8lWNnm4.js +1 -0
  145. package/dist-renderer/assets/spreadsheet-BCZA_wO0.js +1 -0
  146. package/dist-renderer/assets/sql-D0XecflT.js +1 -0
  147. package/dist-renderer/assets/stateDiagram-FKZM4ZOC-ItZ0JBvq.js +1 -0
  148. package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-Hpmw4dMm.js +1 -0
  149. package/dist-renderer/assets/stex-C3f8Ysf7.js +1 -0
  150. package/dist-renderer/assets/stylus-B533Al4x.js +1 -0
  151. package/dist-renderer/assets/swift-BzpIVaGY.js +1 -0
  152. package/dist-renderer/assets/tcl-DVfN8rqt.js +1 -0
  153. package/dist-renderer/assets/textile-CnDTJFAw.js +1 -0
  154. package/dist-renderer/assets/tiddlywiki-DO-Gjzrf.js +1 -0
  155. package/dist-renderer/assets/tiki-DGYXhP31.js +1 -0
  156. package/dist-renderer/assets/timeline-definition-IT6M3QCI-BzSFaAjV.js +61 -0
  157. package/dist-renderer/assets/toml-Bm5Em-hy.js +1 -0
  158. package/dist-renderer/assets/treemap-GDKQZRPO-fSz4hQn0.js +162 -0
  159. package/dist-renderer/assets/troff-wAsdV37c.js +1 -0
  160. package/dist-renderer/assets/ttcn-CfJYG6tj.js +1 -0
  161. package/dist-renderer/assets/ttcn-cfg-B9xdYoR4.js +1 -0
  162. package/dist-renderer/assets/turtle-B1tBg_DP.js +1 -0
  163. package/dist-renderer/assets/vb-CmGdzxic.js +1 -0
  164. package/dist-renderer/assets/vbscript-BuJXcnF6.js +1 -0
  165. package/dist-renderer/assets/velocity-D8B20fx6.js +1 -0
  166. package/dist-renderer/assets/verilog-C6RDOZhf.js +1 -0
  167. package/dist-renderer/assets/vhdl-lSbBsy5d.js +1 -0
  168. package/dist-renderer/assets/webidl-ZXfAyPTL.js +1 -0
  169. package/dist-renderer/assets/xquery-CQfU5ijd.js +1 -0
  170. package/dist-renderer/assets/xychartDiagram-PRI3JC2R-CT1kaGlv.js +7 -0
  171. package/dist-renderer/assets/yacas-BJ4BC0dw.js +1 -0
  172. package/dist-renderer/assets/z80-Hz9HOZM7.js +1 -0
  173. package/dist-renderer/index.html +1274 -0
  174. package/package.json +181 -0
  175. package/src/features/README.md +24 -0
  176. package/src/features/agent-graph/README.md +21 -0
  177. package/src/features/agent-graph/STABLE_SLOT_LAYOUT_PLAN.md +2846 -0
  178. package/src/features/agent-graph/core/domain/buildInlineActivityEntries.ts +416 -0
  179. package/src/features/agent-graph/core/domain/collapseOverflowStacks.ts +126 -0
  180. package/src/features/agent-graph/core/domain/graphOwnerIdentity.ts +55 -0
  181. package/src/features/agent-graph/core/domain/taskGraphSemantics.ts +48 -0
  182. package/src/features/agent-graph/renderer/adapters/TeamGraphAdapter.ts +1400 -0
  183. package/src/features/agent-graph/renderer/hooks/useGraphActivityContext.ts +34 -0
  184. package/src/features/agent-graph/renderer/hooks/useGraphCreateTaskDialog.tsx +126 -0
  185. package/src/features/agent-graph/renderer/hooks/useGraphMemberPopoverContext.ts +34 -0
  186. package/src/features/agent-graph/renderer/hooks/useGraphSidebarVisibility.ts +52 -0
  187. package/src/features/agent-graph/renderer/hooks/useTeamGraphAdapter.ts +173 -0
  188. package/src/features/agent-graph/renderer/hooks/useTeamGraphSurfaceActions.ts +98 -0
  189. package/src/features/agent-graph/renderer/index.ts +14 -0
  190. package/src/features/agent-graph/renderer/ui/GraphActivityCard.tsx +96 -0
  191. package/src/features/agent-graph/renderer/ui/GraphActivityHud.tsx +498 -0
  192. package/src/features/agent-graph/renderer/ui/GraphBlockingEdgePopover.tsx +207 -0
  193. package/src/features/agent-graph/renderer/ui/GraphNodePopover.tsx +573 -0
  194. package/src/features/agent-graph/renderer/ui/GraphProvisioningHud.tsx +113 -0
  195. package/src/features/agent-graph/renderer/ui/GraphTaskCard.tsx +149 -0
  196. package/src/features/agent-graph/renderer/ui/GraphTransientHandoffHud.tsx +176 -0
  197. package/src/features/agent-graph/renderer/ui/TeamGraphOverlay.tsx +224 -0
  198. package/src/features/agent-graph/renderer/ui/TeamGraphTab.tsx +257 -0
  199. package/src/features/agent-graph/renderer/ui/buildTransientHandoffMessage.ts +70 -0
  200. package/src/features/recent-projects/contracts/api.ts +5 -0
  201. package/src/features/recent-projects/contracts/channels.ts +2 -0
  202. package/src/features/recent-projects/contracts/dto.ts +24 -0
  203. package/src/features/recent-projects/contracts/index.ts +4 -0
  204. package/src/features/recent-projects/contracts/normalize.ts +32 -0
  205. package/src/features/recent-projects/core/application/models/ListDashboardRecentProjectsResponse.ts +6 -0
  206. package/src/features/recent-projects/core/application/ports/ClockPort.ts +3 -0
  207. package/src/features/recent-projects/core/application/ports/ListDashboardRecentProjectsOutputPort.ts +5 -0
  208. package/src/features/recent-projects/core/application/ports/LoggerPort.ts +5 -0
  209. package/src/features/recent-projects/core/application/ports/RecentProjectsCachePort.ts +5 -0
  210. package/src/features/recent-projects/core/application/ports/RecentProjectsSourcePort.ts +14 -0
  211. package/src/features/recent-projects/core/application/use-cases/ListDashboardRecentProjectsUseCase.ts +191 -0
  212. package/src/features/recent-projects/core/domain/models/ProviderId.ts +1 -0
  213. package/src/features/recent-projects/core/domain/models/RecentProjectAggregate.ts +14 -0
  214. package/src/features/recent-projects/core/domain/models/RecentProjectCandidate.ts +14 -0
  215. package/src/features/recent-projects/core/domain/models/RecentProjectOpenTarget.ts +3 -0
  216. package/src/features/recent-projects/core/domain/policies/mergeRecentProjectCandidates.ts +88 -0
  217. package/src/features/recent-projects/main/adapters/input/http/registerRecentProjectsHttp.ts +30 -0
  218. package/src/features/recent-projects/main/adapters/output/presenters/DashboardRecentProjectsPresenter.ts +27 -0
  219. package/src/features/recent-projects/main/adapters/output/sources/ClaudeRecentProjectsSourceAdapter.ts +91 -0
  220. package/src/features/recent-projects/main/adapters/output/sources/CodexRecentProjectsSourceAdapter.ts +326 -0
  221. package/src/features/recent-projects/main/composition/createRecentProjectsFeature.ts +43 -0
  222. package/src/features/recent-projects/main/index.ts +3 -0
  223. package/src/features/recent-projects/main/infrastructure/cache/InMemoryRecentProjectsCache.ts +34 -0
  224. package/src/features/recent-projects/main/infrastructure/codex/CodexAppServerClient.ts +116 -0
  225. package/src/features/recent-projects/main/infrastructure/identity/RecentProjectIdentityResolver.ts +20 -0
  226. package/src/features/recent-projects/main/infrastructure/identity/normalizeIdentityPath.ts +10 -0
  227. package/src/features/recent-projects/renderer/adapters/RecentProjectsSectionAdapter.ts +132 -0
  228. package/src/features/recent-projects/renderer/hooks/useOpenRecentProject.ts +143 -0
  229. package/src/features/recent-projects/renderer/hooks/useRecentProjectsSection.ts +289 -0
  230. package/src/features/recent-projects/renderer/index.ts +2 -0
  231. package/src/features/recent-projects/renderer/ui/RecentProjectCard.tsx +221 -0
  232. package/src/features/recent-projects/renderer/ui/RecentProjectsSection.tsx +167 -0
  233. package/src/features/recent-projects/renderer/utils/activeProjectTeams.ts +48 -0
  234. package/src/features/recent-projects/renderer/utils/navigation.ts +65 -0
  235. package/src/features/recent-projects/renderer/utils/projectDecorations.ts +11 -0
  236. package/src/features/recent-projects/renderer/utils/recentProjectOpenHistory.ts +268 -0
  237. package/src/features/recent-projects/renderer/utils/recentProjectsClientCache.ts +78 -0
  238. package/src/main/constants/messageTags.ts +46 -0
  239. package/src/main/constants/worktreePatterns.ts +47 -0
  240. package/src/main/server.ts +3705 -0
  241. package/src/main/services/UpdateService.ts +166 -0
  242. package/src/main/services/ccConnect/CcConnectBridge.ts +313 -0
  243. package/src/main/services/ccConnect/CcConnectClient.ts +397 -0
  244. package/src/main/services/ccConnect/MessageBridge.ts +162 -0
  245. package/src/main/services/ccConnect/ProjectMappingStore.ts +148 -0
  246. package/src/main/services/ccConnect/index.ts +8 -0
  247. package/src/main/services/teams-mvp/TeamProvisioningService.ts +275 -0
  248. package/src/main/services/teams-mvp/TeamWorkspaceService.ts +404 -0
  249. package/src/main/services/teams-mvp/index.ts +26 -0
  250. package/src/main/types/chunks.ts +506 -0
  251. package/src/main/types/domain.ts +342 -0
  252. package/src/main/types/index.ts +24 -0
  253. package/src/main/types/jsonl.ts +355 -0
  254. package/src/main/types/messages.ts +395 -0
  255. package/src/renderer/App.tsx +287 -0
  256. package/src/renderer/api/httpClient.ts +2207 -0
  257. package/src/renderer/api/index.ts +19 -0
  258. package/src/renderer/api/providers.ts +77 -0
  259. package/src/renderer/assets/participant-avatars/01.png +0 -0
  260. package/src/renderer/assets/participant-avatars/02.png +0 -0
  261. package/src/renderer/assets/participant-avatars/03.png +0 -0
  262. package/src/renderer/assets/participant-avatars/04.png +0 -0
  263. package/src/renderer/assets/participant-avatars/05.png +0 -0
  264. package/src/renderer/assets/participant-avatars/06.png +0 -0
  265. package/src/renderer/assets/participant-avatars/07.png +0 -0
  266. package/src/renderer/assets/participant-avatars/08.png +0 -0
  267. package/src/renderer/assets/participant-avatars/09.png +0 -0
  268. package/src/renderer/assets/participant-avatars/10.png +0 -0
  269. package/src/renderer/assets/participant-avatars/11.png +0 -0
  270. package/src/renderer/assets/participant-avatars/12.png +0 -0
  271. package/src/renderer/assets/participant-avatars/13.png +0 -0
  272. package/src/renderer/components/chat/AIChatGroup.tsx +519 -0
  273. package/src/renderer/components/chat/ChatHistory.tsx +1115 -0
  274. package/src/renderer/components/chat/ChatHistoryEmptyState.tsx +15 -0
  275. package/src/renderer/components/chat/ChatHistoryItem.tsx +144 -0
  276. package/src/renderer/components/chat/ChatHistoryLoadingState.tsx +45 -0
  277. package/src/renderer/components/chat/CompactBoundary.tsx +169 -0
  278. package/src/renderer/components/chat/ContextBadge.tsx +582 -0
  279. package/src/renderer/components/chat/DisplayItemList.tsx +431 -0
  280. package/src/renderer/components/chat/LastOutputDisplay.tsx +259 -0
  281. package/src/renderer/components/chat/SessionContextPanel/DirectoryTree/DirectoryTreeNode.tsx +125 -0
  282. package/src/renderer/components/chat/SessionContextPanel/DirectoryTree/buildDirectoryTree.ts +47 -0
  283. package/src/renderer/components/chat/SessionContextPanel/DirectoryTree/types.ts +12 -0
  284. package/src/renderer/components/chat/SessionContextPanel/components/ClaudeMdFilesSection.tsx +90 -0
  285. package/src/renderer/components/chat/SessionContextPanel/components/ClaudeMdSection.tsx +86 -0
  286. package/src/renderer/components/chat/SessionContextPanel/components/CollapsibleSection.tsx +77 -0
  287. package/src/renderer/components/chat/SessionContextPanel/components/FlatInjectionList.tsx +248 -0
  288. package/src/renderer/components/chat/SessionContextPanel/components/MentionedFilesSection.tsx +50 -0
  289. package/src/renderer/components/chat/SessionContextPanel/components/RankedInjectionList.tsx +284 -0
  290. package/src/renderer/components/chat/SessionContextPanel/components/SessionContextHeader.tsx +290 -0
  291. package/src/renderer/components/chat/SessionContextPanel/components/SessionContextHelpTooltip.tsx +165 -0
  292. package/src/renderer/components/chat/SessionContextPanel/components/TaskCoordinationSection.tsx +47 -0
  293. package/src/renderer/components/chat/SessionContextPanel/components/ThinkingTextSection.tsx +47 -0
  294. package/src/renderer/components/chat/SessionContextPanel/components/ToolOutputsSection.tsx +47 -0
  295. package/src/renderer/components/chat/SessionContextPanel/components/UserMessagesSection.tsx +47 -0
  296. package/src/renderer/components/chat/SessionContextPanel/index.tsx +314 -0
  297. package/src/renderer/components/chat/SessionContextPanel/items/ClaudeMdItem.tsx +76 -0
  298. package/src/renderer/components/chat/SessionContextPanel/items/MentionedFileItem.tsx +91 -0
  299. package/src/renderer/components/chat/SessionContextPanel/items/TaskCoordinationItem.tsx +116 -0
  300. package/src/renderer/components/chat/SessionContextPanel/items/ThinkingTextItem.tsx +96 -0
  301. package/src/renderer/components/chat/SessionContextPanel/items/ToolBreakdownItem.tsx +38 -0
  302. package/src/renderer/components/chat/SessionContextPanel/items/ToolOutputItem.tsx +113 -0
  303. package/src/renderer/components/chat/SessionContextPanel/items/UserMessageItem.tsx +69 -0
  304. package/src/renderer/components/chat/SessionContextPanel/types.ts +96 -0
  305. package/src/renderer/components/chat/SessionContextPanel/utils/formatting.ts +6 -0
  306. package/src/renderer/components/chat/SessionContextPanel/utils/pathParsing.ts +23 -0
  307. package/src/renderer/components/chat/SystemChatGroup.tsx +60 -0
  308. package/src/renderer/components/chat/UserChatGroup.tsx +668 -0
  309. package/src/renderer/components/chat/items/BaseItem.tsx +213 -0
  310. package/src/renderer/components/chat/items/ExecutionTrace.tsx +279 -0
  311. package/src/renderer/components/chat/items/LinkedToolItem.tsx +235 -0
  312. package/src/renderer/components/chat/items/MetricsPill.tsx +215 -0
  313. package/src/renderer/components/chat/items/SlashItem.tsx +81 -0
  314. package/src/renderer/components/chat/items/SubagentItem.tsx +592 -0
  315. package/src/renderer/components/chat/items/TeammateMessageItem.tsx +261 -0
  316. package/src/renderer/components/chat/items/TextItem.tsx +82 -0
  317. package/src/renderer/components/chat/items/ThinkingItem.tsx +82 -0
  318. package/src/renderer/components/chat/items/baseItemHelpers.ts +42 -0
  319. package/src/renderer/components/chat/items/linkedTool/CollapsibleOutputSection.tsx +57 -0
  320. package/src/renderer/components/chat/items/linkedTool/DefaultToolViewer.tsx +56 -0
  321. package/src/renderer/components/chat/items/linkedTool/EditToolViewer.tsx +74 -0
  322. package/src/renderer/components/chat/items/linkedTool/ReadToolViewer.tsx +102 -0
  323. package/src/renderer/components/chat/items/linkedTool/SkillToolViewer.tsx +67 -0
  324. package/src/renderer/components/chat/items/linkedTool/ToolErrorDisplay.tsx +43 -0
  325. package/src/renderer/components/chat/items/linkedTool/WriteToolViewer.tsx +66 -0
  326. package/src/renderer/components/chat/items/linkedTool/index.ts +13 -0
  327. package/src/renderer/components/chat/items/linkedTool/renderHelpers.tsx +259 -0
  328. package/src/renderer/components/chat/markdownComponents.tsx +257 -0
  329. package/src/renderer/components/chat/markdownCopyUtils.ts +18 -0
  330. package/src/renderer/components/chat/searchHighlightUtils.ts +166 -0
  331. package/src/renderer/components/chat/viewers/CodeBlockViewer.tsx +244 -0
  332. package/src/renderer/components/chat/viewers/DiffViewer.tsx +459 -0
  333. package/src/renderer/components/chat/viewers/FileLink.tsx +182 -0
  334. package/src/renderer/components/chat/viewers/MarkdownViewer.tsx +1093 -0
  335. package/src/renderer/components/chat/viewers/MermaidDiagram.tsx +116 -0
  336. package/src/renderer/components/chat/viewers/index.ts +3 -0
  337. package/src/renderer/components/chat/viewers/syntaxHighlighter.ts +583 -0
  338. package/src/renderer/components/common/AppLogo.tsx +61 -0
  339. package/src/renderer/components/common/CliInstallWarningBanner.tsx +57 -0
  340. package/src/renderer/components/common/ConfirmDialog.tsx +176 -0
  341. package/src/renderer/components/common/ConnectionStatusBadge.tsx +56 -0
  342. package/src/renderer/components/common/ContextSwitchOverlay.tsx +38 -0
  343. package/src/renderer/components/common/CopyButton.tsx +85 -0
  344. package/src/renderer/components/common/CopyablePath.tsx +68 -0
  345. package/src/renderer/components/common/ErrorBoundary.tsx +211 -0
  346. package/src/renderer/components/common/ExportDropdown.tsx +142 -0
  347. package/src/renderer/components/common/FileTree.tsx +182 -0
  348. package/src/renderer/components/common/GlobalProviderStatusHeader.tsx +316 -0
  349. package/src/renderer/components/common/OngoingIndicator.tsx +67 -0
  350. package/src/renderer/components/common/ProviderBrandLogo.tsx +206 -0
  351. package/src/renderer/components/common/RepositoryDropdown.tsx +230 -0
  352. package/src/renderer/components/common/TokenUsageDisplay.tsx +581 -0
  353. package/src/renderer/components/common/WarningBanner.tsx +25 -0
  354. package/src/renderer/components/common/WorkspaceIndicator.tsx +183 -0
  355. package/src/renderer/components/common/WorktreeBadge.tsx +123 -0
  356. package/src/renderer/components/dashboard/CliStatusBanner.tsx +1845 -0
  357. package/src/renderer/components/dashboard/DashboardView.tsx +274 -0
  358. package/src/renderer/components/extensions/ExtensionStoreView.tsx +591 -0
  359. package/src/renderer/components/extensions/ExtensionsSubTabTrigger.tsx +52 -0
  360. package/src/renderer/components/extensions/apikeys/ApiKeyCard.tsx +143 -0
  361. package/src/renderer/components/extensions/apikeys/ApiKeyFormDialog.tsx +282 -0
  362. package/src/renderer/components/extensions/apikeys/ApiKeysPanel.tsx +280 -0
  363. package/src/renderer/components/extensions/common/InstallButton.tsx +186 -0
  364. package/src/renderer/components/extensions/common/InstallCountBadge.tsx +21 -0
  365. package/src/renderer/components/extensions/common/SearchInput.tsx +70 -0
  366. package/src/renderer/components/extensions/common/SourceBadge.tsx +31 -0
  367. package/src/renderer/components/extensions/mcp/CustomMcpServerDialog.tsx +560 -0
  368. package/src/renderer/components/extensions/mcp/McpServerCard.tsx +314 -0
  369. package/src/renderer/components/extensions/mcp/McpServerDetailDialog.tsx +669 -0
  370. package/src/renderer/components/extensions/mcp/McpServersPanel.tsx +543 -0
  371. package/src/renderer/components/extensions/plugins/CapabilityChips.tsx +70 -0
  372. package/src/renderer/components/extensions/plugins/CategoryChips.tsx +67 -0
  373. package/src/renderer/components/extensions/plugins/PluginCard.tsx +146 -0
  374. package/src/renderer/components/extensions/plugins/PluginDetailDialog.tsx +270 -0
  375. package/src/renderer/components/extensions/plugins/PluginsPanel.tsx +436 -0
  376. package/src/renderer/components/extensions/skills/SkillCodeEditor.tsx +117 -0
  377. package/src/renderer/components/extensions/skills/SkillDetailDialog.tsx +372 -0
  378. package/src/renderer/components/extensions/skills/SkillEditorDialog.tsx +856 -0
  379. package/src/renderer/components/extensions/skills/SkillImportDialog.tsx +343 -0
  380. package/src/renderer/components/extensions/skills/SkillReviewDialog.tsx +166 -0
  381. package/src/renderer/components/extensions/skills/SkillsPanel.tsx +784 -0
  382. package/src/renderer/components/extensions/skills/skillDraftUtils.ts +234 -0
  383. package/src/renderer/components/extensions/skills/skillFolderNameUtils.ts +19 -0
  384. package/src/renderer/components/extensions/skills/skillProjectUtils.ts +13 -0
  385. package/src/renderer/components/extensions/skills/skillValidationUtils.ts +31 -0
  386. package/src/renderer/components/layout/MiddlePanel.tsx +18 -0
  387. package/src/renderer/components/layout/MoreMenu.tsx +243 -0
  388. package/src/renderer/components/layout/PaneContainer.tsx +27 -0
  389. package/src/renderer/components/layout/PaneContent.tsx +84 -0
  390. package/src/renderer/components/layout/PaneResizeHandle.tsx +85 -0
  391. package/src/renderer/components/layout/PaneSplitDropZone.tsx +54 -0
  392. package/src/renderer/components/layout/PaneView.tsx +75 -0
  393. package/src/renderer/components/layout/SessionTabContent.tsx +102 -0
  394. package/src/renderer/components/layout/Sidebar.tsx +205 -0
  395. package/src/renderer/components/layout/SortableTab.tsx +261 -0
  396. package/src/renderer/components/layout/TabBar.tsx +354 -0
  397. package/src/renderer/components/layout/TabBarActions.tsx +176 -0
  398. package/src/renderer/components/layout/TabBarRow.tsx +99 -0
  399. package/src/renderer/components/layout/TabContextMenu.tsx +171 -0
  400. package/src/renderer/components/layout/TabbedLayout.tsx +186 -0
  401. package/src/renderer/components/layout/TeamTabSectionNav.tsx +146 -0
  402. package/src/renderer/components/notifications/NotificationRow.tsx +228 -0
  403. package/src/renderer/components/notifications/NotificationsView.tsx +371 -0
  404. package/src/renderer/components/report/AssessmentBadge.tsx +78 -0
  405. package/src/renderer/components/report/ReportSection.tsx +58 -0
  406. package/src/renderer/components/report/SessionReportTab.tsx +102 -0
  407. package/src/renderer/components/report/sections/CostSection.tsx +259 -0
  408. package/src/renderer/components/report/sections/ErrorSection.tsx +100 -0
  409. package/src/renderer/components/report/sections/FrictionSection.tsx +91 -0
  410. package/src/renderer/components/report/sections/GitSection.tsx +72 -0
  411. package/src/renderer/components/report/sections/InsightsSection.tsx +207 -0
  412. package/src/renderer/components/report/sections/KeyTakeawaysSection.tsx +55 -0
  413. package/src/renderer/components/report/sections/OverviewSection.tsx +64 -0
  414. package/src/renderer/components/report/sections/QualitySection.tsx +151 -0
  415. package/src/renderer/components/report/sections/SubagentSection.tsx +88 -0
  416. package/src/renderer/components/report/sections/TimelineSection.tsx +111 -0
  417. package/src/renderer/components/report/sections/TokenSection.tsx +116 -0
  418. package/src/renderer/components/report/sections/ToolSection.tsx +77 -0
  419. package/src/renderer/components/runtime/ProviderModelBadges.tsx +142 -0
  420. package/src/renderer/components/runtime/ProviderRuntimeBackendSelector.tsx +327 -0
  421. package/src/renderer/components/runtime/ProviderRuntimeSettingsDialog.tsx +288 -0
  422. package/src/renderer/components/runtime/providerConnectionUi.ts +408 -0
  423. package/src/renderer/components/schedules/SchedulesView.tsx +529 -0
  424. package/src/renderer/components/search/CommandPalette.tsx +610 -0
  425. package/src/renderer/components/search/SearchBar.tsx +171 -0
  426. package/src/renderer/components/settings/NotificationTriggerSettings/components/AddTriggerForm.tsx +233 -0
  427. package/src/renderer/components/settings/NotificationTriggerSettings/components/ColorPaletteSelector.tsx +144 -0
  428. package/src/renderer/components/settings/NotificationTriggerSettings/components/DynamicConfigSection.tsx +189 -0
  429. package/src/renderer/components/settings/NotificationTriggerSettings/components/GeneralInfoSection.tsx +68 -0
  430. package/src/renderer/components/settings/NotificationTriggerSettings/components/IgnorePatternsSection.tsx +73 -0
  431. package/src/renderer/components/settings/NotificationTriggerSettings/components/ModeSelector.tsx +45 -0
  432. package/src/renderer/components/settings/NotificationTriggerSettings/components/RepositoryScopeSection.tsx +63 -0
  433. package/src/renderer/components/settings/NotificationTriggerSettings/components/SectionHeader.tsx +15 -0
  434. package/src/renderer/components/settings/NotificationTriggerSettings/components/TriggerCard.tsx +150 -0
  435. package/src/renderer/components/settings/NotificationTriggerSettings/components/TriggerCardHeader.tsx +125 -0
  436. package/src/renderer/components/settings/NotificationTriggerSettings/components/TriggerConfiguration.tsx +342 -0
  437. package/src/renderer/components/settings/NotificationTriggerSettings/components/TriggerPreview.tsx +108 -0
  438. package/src/renderer/components/settings/NotificationTriggerSettings/hooks/useAddTriggerFormHandlers.ts +218 -0
  439. package/src/renderer/components/settings/NotificationTriggerSettings/hooks/useAddTriggerFormState.ts +135 -0
  440. package/src/renderer/components/settings/NotificationTriggerSettings/hooks/useRepositoryLookup.ts +47 -0
  441. package/src/renderer/components/settings/NotificationTriggerSettings/hooks/useTriggerCardState.ts +281 -0
  442. package/src/renderer/components/settings/NotificationTriggerSettings/hooks/useTriggerForm.ts +185 -0
  443. package/src/renderer/components/settings/NotificationTriggerSettings/index.tsx +87 -0
  444. package/src/renderer/components/settings/NotificationTriggerSettings/types.ts +39 -0
  445. package/src/renderer/components/settings/NotificationTriggerSettings/utils/constants.ts +50 -0
  446. package/src/renderer/components/settings/NotificationTriggerSettings/utils/trigger.ts +113 -0
  447. package/src/renderer/components/settings/SettingsTabs.tsx +110 -0
  448. package/src/renderer/components/settings/SettingsView.tsx +153 -0
  449. package/src/renderer/components/settings/components/SettingRow.tsx +44 -0
  450. package/src/renderer/components/settings/components/SettingsSectionHeader.tsx +24 -0
  451. package/src/renderer/components/settings/components/SettingsSelect.tsx +100 -0
  452. package/src/renderer/components/settings/components/SettingsToggle.tsx +45 -0
  453. package/src/renderer/components/settings/components/index.ts +8 -0
  454. package/src/renderer/components/settings/hooks/index.ts +6 -0
  455. package/src/renderer/components/settings/hooks/useSettingsConfig.ts +270 -0
  456. package/src/renderer/components/settings/hooks/useSettingsHandlers.ts +468 -0
  457. package/src/renderer/components/settings/sections/AdvancedSection.tsx +234 -0
  458. package/src/renderer/components/settings/sections/CliStatusSection.tsx +930 -0
  459. package/src/renderer/components/settings/sections/ConfigEditorDialog.tsx +391 -0
  460. package/src/renderer/components/settings/sections/GeneralSection.tsx +665 -0
  461. package/src/renderer/components/settings/sections/HarnessSection.tsx +133 -0
  462. package/src/renderer/components/settings/sections/PlatformsSection.tsx +517 -0
  463. package/src/renderer/components/settings/sections/index.ts +8 -0
  464. package/src/renderer/components/sidebar/DateGroupedSessions.tsx +1115 -0
  465. package/src/renderer/components/sidebar/GlobalTaskList.tsx +853 -0
  466. package/src/renderer/components/sidebar/SessionContextMenu.tsx +182 -0
  467. package/src/renderer/components/sidebar/SessionFiltersPopover.tsx +115 -0
  468. package/src/renderer/components/sidebar/SessionItem.tsx +393 -0
  469. package/src/renderer/components/sidebar/SidebarSessions.tsx +542 -0
  470. package/src/renderer/components/sidebar/SidebarTaskItem.tsx +286 -0
  471. package/src/renderer/components/sidebar/TaskContextMenu.tsx +86 -0
  472. package/src/renderer/components/sidebar/TaskFiltersPopover.tsx +203 -0
  473. package/src/renderer/components/sidebar/WorkspaceBrowser.tsx +370 -0
  474. package/src/renderer/components/sidebar/dateGroupedSessionsSelection.ts +33 -0
  475. package/src/renderer/components/sidebar/projectGroupPagination.ts +89 -0
  476. package/src/renderer/components/sidebar/taskFiltersState.ts +82 -0
  477. package/src/renderer/components/splash/splashScene.ts +979 -0
  478. package/src/renderer/components/team/CcSessionsSection.tsx +202 -0
  479. package/src/renderer/components/team/ClaudeLogsDialog.tsx +71 -0
  480. package/src/renderer/components/team/ClaudeLogsFilterPopover.tsx +213 -0
  481. package/src/renderer/components/team/ClaudeLogsPanel.tsx +170 -0
  482. package/src/renderer/components/team/ClaudeLogsSection.tsx +154 -0
  483. package/src/renderer/components/team/CliLogsRichView.tsx +640 -0
  484. package/src/renderer/components/team/CollapsibleTeamSection.tsx +177 -0
  485. package/src/renderer/components/team/HarnessCards.ts +38 -0
  486. package/src/renderer/components/team/MemberBadge.tsx +117 -0
  487. package/src/renderer/components/team/ProcessesSection.tsx +193 -0
  488. package/src/renderer/components/team/ProvisioningProgressBlock.tsx +389 -0
  489. package/src/renderer/components/team/RoleSelect.tsx +171 -0
  490. package/src/renderer/components/team/StepProgressBar.tsx +165 -0
  491. package/src/renderer/components/team/TaskTooltip.tsx +197 -0
  492. package/src/renderer/components/team/TeamDetailView.tsx +3002 -0
  493. package/src/renderer/components/team/TeamEmptyState.tsx +102 -0
  494. package/src/renderer/components/team/TeamListFilterPopover.tsx +183 -0
  495. package/src/renderer/components/team/TeamListView.tsx +1336 -0
  496. package/src/renderer/components/team/TeamProvisioningBanner.tsx +16 -0
  497. package/src/renderer/components/team/TeamProvisioningPanel.tsx +115 -0
  498. package/src/renderer/components/team/TeamSessionsSection.tsx +267 -0
  499. package/src/renderer/components/team/ToolApprovalDiffPreview.tsx +206 -0
  500. package/src/renderer/components/team/ToolApprovalSheet.tsx +675 -0
  501. package/src/renderer/components/team/UnreadCommentsBadge.tsx +37 -0
  502. package/src/renderer/components/team/activity/ActiveTasksBlock.tsx +191 -0
  503. package/src/renderer/components/team/activity/ActivityItem.tsx +1649 -0
  504. package/src/renderer/components/team/activity/ActivityTimeline.tsx +959 -0
  505. package/src/renderer/components/team/activity/AnimatedHeightReveal.tsx +117 -0
  506. package/src/renderer/components/team/activity/LeadThoughtsGroup.tsx +1152 -0
  507. package/src/renderer/components/team/activity/MessageExpandDialog.tsx +213 -0
  508. package/src/renderer/components/team/activity/PendingRepliesBlock.tsx +275 -0
  509. package/src/renderer/components/team/activity/ReplyQuoteBlock.tsx +79 -0
  510. package/src/renderer/components/team/activity/ThoughtBodyContent.tsx +150 -0
  511. package/src/renderer/components/team/activity/activityMarkdown.ts +36 -0
  512. package/src/renderer/components/team/activity/activityMessageContext.ts +68 -0
  513. package/src/renderer/components/team/activity/collapseState.ts +66 -0
  514. package/src/renderer/components/team/activity/useNewItemKeys.ts +70 -0
  515. package/src/renderer/components/team/attachments/AttachmentDisplay.tsx +132 -0
  516. package/src/renderer/components/team/attachments/AttachmentPreviewItem.tsx +62 -0
  517. package/src/renderer/components/team/attachments/AttachmentPreviewList.tsx +193 -0
  518. package/src/renderer/components/team/attachments/AttachmentThumbnail.tsx +42 -0
  519. package/src/renderer/components/team/attachments/DropZoneOverlay.tsx +54 -0
  520. package/src/renderer/components/team/attachments/ImageLightbox.tsx +132 -0
  521. package/src/renderer/components/team/attachments/SourceMessageAttachments.tsx +70 -0
  522. package/src/renderer/components/team/dialogs/AddMemberDialog.tsx +222 -0
  523. package/src/renderer/components/team/dialogs/AdvancedCliSection.tsx +347 -0
  524. package/src/renderer/components/team/dialogs/AnthropicFastModeSelector.tsx +120 -0
  525. package/src/renderer/components/team/dialogs/CreateTaskDialog.tsx +489 -0
  526. package/src/renderer/components/team/dialogs/CreateTeamDialog.tsx +484 -0
  527. package/src/renderer/components/team/dialogs/EditTeamDialog.tsx +448 -0
  528. package/src/renderer/components/team/dialogs/EffortLevelSelector.tsx +69 -0
  529. package/src/renderer/components/team/dialogs/GlobalTaskDetailDialog.tsx +165 -0
  530. package/src/renderer/components/team/dialogs/LaunchTeamDialog.tsx +2859 -0
  531. package/src/renderer/components/team/dialogs/LimitContextCheckbox.tsx +57 -0
  532. package/src/renderer/components/team/dialogs/MembersJsonEditor.tsx +123 -0
  533. package/src/renderer/components/team/dialogs/OptionalSettingsSection.tsx +124 -0
  534. package/src/renderer/components/team/dialogs/PlatformManualForm.tsx +145 -0
  535. package/src/renderer/components/team/dialogs/PlatformSetupQR.tsx +289 -0
  536. package/src/renderer/components/team/dialogs/ProjectPathSelector.tsx +330 -0
  537. package/src/renderer/components/team/dialogs/ProvisioningProviderStatusList.tsx +744 -0
  538. package/src/renderer/components/team/dialogs/ReviewDialog.tsx +130 -0
  539. package/src/renderer/components/team/dialogs/SendMessageDialog.tsx +530 -0
  540. package/src/renderer/components/team/dialogs/SkipPermissionsCheckbox.tsx +62 -0
  541. package/src/renderer/components/team/dialogs/StatusHistoryTimeline.tsx +229 -0
  542. package/src/renderer/components/team/dialogs/TaskAttachments.tsx +394 -0
  543. package/src/renderer/components/team/dialogs/TaskCommentAwaitingReply.tsx +57 -0
  544. package/src/renderer/components/team/dialogs/TaskCommentInput.tsx +420 -0
  545. package/src/renderer/components/team/dialogs/TaskCommentsSection.tsx +620 -0
  546. package/src/renderer/components/team/dialogs/TaskDetailDialog.tsx +1480 -0
  547. package/src/renderer/components/team/dialogs/TeamModelSelector.tsx +560 -0
  548. package/src/renderer/components/team/dialogs/TeammateRuntimeCompatibilityNotice.tsx +60 -0
  549. package/src/renderer/components/team/dialogs/ToolApprovalSettingsPanel.tsx +173 -0
  550. package/src/renderer/components/team/dialogs/editTeamRuntimeChanges.ts +179 -0
  551. package/src/renderer/components/team/dialogs/globalTaskDetailDialogLoading.ts +34 -0
  552. package/src/renderer/components/team/dialogs/launchDialogPrefill.ts +125 -0
  553. package/src/renderer/components/team/dialogs/memberModelScope.ts +77 -0
  554. package/src/renderer/components/team/dialogs/platformMeta.ts +118 -0
  555. package/src/renderer/components/team/dialogs/projectPathOptions.ts +50 -0
  556. package/src/renderer/components/team/dialogs/providerPrepareDiagnostics.ts +222 -0
  557. package/src/renderer/components/team/dialogs/providerPrepareRequestSignature.ts +122 -0
  558. package/src/renderer/components/team/dialogs/provisioningMemberScope.ts +10 -0
  559. package/src/renderer/components/team/dialogs/provisioningModelIssues.ts +124 -0
  560. package/src/renderer/components/team/dialogs/teamNameSets.ts +67 -0
  561. package/src/renderer/components/team/dialogs/teamRelaunchFlow.ts +30 -0
  562. package/src/renderer/components/team/dialogs/teammateLaunchMode.ts +49 -0
  563. package/src/renderer/components/team/dialogs/teammateRuntimeCompatibility.tsx +101 -0
  564. package/src/renderer/components/team/editor/CodeMirrorEditor.tsx +506 -0
  565. package/src/renderer/components/team/editor/EditorBinaryPlaceholder.tsx +43 -0
  566. package/src/renderer/components/team/editor/EditorBinaryState.tsx +29 -0
  567. package/src/renderer/components/team/editor/EditorBreadcrumb.tsx +84 -0
  568. package/src/renderer/components/team/editor/EditorContextMenu.tsx +213 -0
  569. package/src/renderer/components/team/editor/EditorEmptyState.tsx +35 -0
  570. package/src/renderer/components/team/editor/EditorErrorBoundary.tsx +63 -0
  571. package/src/renderer/components/team/editor/EditorErrorState.tsx +41 -0
  572. package/src/renderer/components/team/editor/EditorFileTree.tsx +903 -0
  573. package/src/renderer/components/team/editor/EditorImagePreview.tsx +138 -0
  574. package/src/renderer/components/team/editor/EditorSearchPanel.tsx +508 -0
  575. package/src/renderer/components/team/editor/EditorSelectionMenu.tsx +112 -0
  576. package/src/renderer/components/team/editor/EditorShortcutsHelp.tsx +125 -0
  577. package/src/renderer/components/team/editor/EditorStatusBar.tsx +72 -0
  578. package/src/renderer/components/team/editor/EditorTabBar.tsx +265 -0
  579. package/src/renderer/components/team/editor/EditorTabContextMenu.tsx +88 -0
  580. package/src/renderer/components/team/editor/EditorToolbar.tsx +163 -0
  581. package/src/renderer/components/team/editor/FileIcon.tsx +66 -0
  582. package/src/renderer/components/team/editor/GitStatusBadge.tsx +47 -0
  583. package/src/renderer/components/team/editor/GoToLineDialog.tsx +186 -0
  584. package/src/renderer/components/team/editor/MarkdownPreviewPane.tsx +57 -0
  585. package/src/renderer/components/team/editor/MarkdownSplitView.tsx +127 -0
  586. package/src/renderer/components/team/editor/NewFileDialog.tsx +131 -0
  587. package/src/renderer/components/team/editor/ProjectEditorOverlay.tsx +924 -0
  588. package/src/renderer/components/team/editor/QuickOpenDialog.tsx +163 -0
  589. package/src/renderer/components/team/editor/SearchInFilesPanel.tsx +358 -0
  590. package/src/renderer/components/team/editor/fileIcons.ts +222 -0
  591. package/src/renderer/components/team/kanban/KanbanBoard.tsx +664 -0
  592. package/src/renderer/components/team/kanban/KanbanColumn.tsx +61 -0
  593. package/src/renderer/components/team/kanban/KanbanFilterPopover.tsx +210 -0
  594. package/src/renderer/components/team/kanban/KanbanGridLayout.tsx +460 -0
  595. package/src/renderer/components/team/kanban/KanbanSearchInput.tsx +284 -0
  596. package/src/renderer/components/team/kanban/KanbanSortPopover.tsx +140 -0
  597. package/src/renderer/components/team/kanban/KanbanTaskCard.test.tsx +199 -0
  598. package/src/renderer/components/team/kanban/KanbanTaskCard.tsx +446 -0
  599. package/src/renderer/components/team/kanban/TrashDialog.tsx +112 -0
  600. package/src/renderer/components/team/members/CurrentTaskIndicator.tsx +56 -0
  601. package/src/renderer/components/team/members/LeadModelRow.test.tsx +133 -0
  602. package/src/renderer/components/team/members/LeadModelRow.tsx +183 -0
  603. package/src/renderer/components/team/members/MemberCard.tsx +665 -0
  604. package/src/renderer/components/team/members/MemberDetailDialog.tsx +309 -0
  605. package/src/renderer/components/team/members/MemberDetailHeader.tsx +183 -0
  606. package/src/renderer/components/team/members/MemberDetailStats.tsx +80 -0
  607. package/src/renderer/components/team/members/MemberDraftRow.test.tsx +184 -0
  608. package/src/renderer/components/team/members/MemberDraftRow.tsx +515 -0
  609. package/src/renderer/components/team/members/MemberExecutionLog.tsx +224 -0
  610. package/src/renderer/components/team/members/MemberHoverCard.tsx +292 -0
  611. package/src/renderer/components/team/members/MemberLaunchDiagnosticsButton.tsx +60 -0
  612. package/src/renderer/components/team/members/MemberList.tsx +405 -0
  613. package/src/renderer/components/team/members/MemberLogsTab.tsx +958 -0
  614. package/src/renderer/components/team/members/MemberMessagesTab.tsx +251 -0
  615. package/src/renderer/components/team/members/MemberPresenceDot.tsx +28 -0
  616. package/src/renderer/components/team/members/MemberRoleEditor.tsx +84 -0
  617. package/src/renderer/components/team/members/MemberStatsTab.tsx +299 -0
  618. package/src/renderer/components/team/members/MemberTasksTab.tsx +87 -0
  619. package/src/renderer/components/team/members/MemberWorkspaceTab.tsx +141 -0
  620. package/src/renderer/components/team/members/MembersEditorSection.tsx +495 -0
  621. package/src/renderer/components/team/members/SubagentRecentMessagesPreview.tsx +125 -0
  622. package/src/renderer/components/team/members/TeamRosterEditorSection.tsx +153 -0
  623. package/src/renderer/components/team/members/memberActivityEntries.ts +42 -0
  624. package/src/renderer/components/team/members/memberDetailTypes.ts +3 -0
  625. package/src/renderer/components/team/members/memberNameSets.ts +65 -0
  626. package/src/renderer/components/team/members/membersEditorTypes.ts +21 -0
  627. package/src/renderer/components/team/members/membersEditorUtils.ts +267 -0
  628. package/src/renderer/components/team/messages/MessageComposer.tsx +939 -0
  629. package/src/renderer/components/team/messages/MessagesFilterPopover.tsx +228 -0
  630. package/src/renderer/components/team/messages/MessagesPanel.tsx +1508 -0
  631. package/src/renderer/components/team/messages/OpenCodeDeliveryWarning.tsx +151 -0
  632. package/src/renderer/components/team/messages/StatusBlock.tsx +126 -0
  633. package/src/renderer/components/team/provisioningSteps.ts +363 -0
  634. package/src/renderer/components/team/review/ChangeReviewDialog.tsx +133 -0
  635. package/src/renderer/components/team/schedule/CcCronScheduleDialog.tsx +218 -0
  636. package/src/renderer/components/team/schedule/CronScheduleInput.tsx +254 -0
  637. package/src/renderer/components/team/schedule/ScheduleEmptyState.tsx +15 -0
  638. package/src/renderer/components/team/schedule/ScheduleRunLogDialog.tsx +277 -0
  639. package/src/renderer/components/team/schedule/ScheduleRunRow.tsx +106 -0
  640. package/src/renderer/components/team/schedule/ScheduleSection.tsx +281 -0
  641. package/src/renderer/components/team/schedule/ScheduleStatusBadge.tsx +55 -0
  642. package/src/renderer/components/team/sidebar/TeamSidebarHost.tsx +76 -0
  643. package/src/renderer/components/team/sidebar/TeamSidebarPortalManager.ts +173 -0
  644. package/src/renderer/components/team/sidebar/TeamSidebarPortalSource.tsx +66 -0
  645. package/src/renderer/components/team/sidebar/TeamSidebarRail.tsx +68 -0
  646. package/src/renderer/components/team/sidebar/teamSidebarUiState.ts +136 -0
  647. package/src/renderer/components/team/taskLogs/ExactTaskLogCard.tsx +132 -0
  648. package/src/renderer/components/team/taskLogs/ExactTaskLogsSection.tsx +258 -0
  649. package/src/renderer/components/team/taskLogs/ExecutionSessionsSection.tsx +48 -0
  650. package/src/renderer/components/team/taskLogs/TaskActivityLinkedToolCard.tsx +31 -0
  651. package/src/renderer/components/team/taskLogs/TaskActivitySection.tsx +462 -0
  652. package/src/renderer/components/team/taskLogs/TaskLogStreamSection.tsx +375 -0
  653. package/src/renderer/components/team/taskLogs/TaskLogsPanel.tsx +294 -0
  654. package/src/renderer/components/team/taskLogs/featureGates.ts +22 -0
  655. package/src/renderer/components/team/tasks/TaskList.tsx +111 -0
  656. package/src/renderer/components/team/tasks/TaskRow.tsx +65 -0
  657. package/src/renderer/components/team/teamProjectSelection.ts +156 -0
  658. package/src/renderer/components/team/teamSessionFetchGuards.ts +26 -0
  659. package/src/renderer/components/team/useClaudeLogsController.ts +668 -0
  660. package/src/renderer/components/team/useTeamProvisioningPresentation.ts +54 -0
  661. package/src/renderer/components/terminal/TerminalLogPanel.tsx +37 -0
  662. package/src/renderer/components/ui/ChipInteractionLayer.tsx +255 -0
  663. package/src/renderer/components/ui/CodeChipBadge.tsx +37 -0
  664. package/src/renderer/components/ui/ExpandableContent.tsx +110 -0
  665. package/src/renderer/components/ui/MemberSelect.tsx +209 -0
  666. package/src/renderer/components/ui/MentionInteractionLayer.tsx +121 -0
  667. package/src/renderer/components/ui/MentionSuggestionList.tsx +274 -0
  668. package/src/renderer/components/ui/MentionableTextarea.tsx +1426 -0
  669. package/src/renderer/components/ui/SlashCommandInteractionLayer.tsx +88 -0
  670. package/src/renderer/components/ui/TaskReferenceInteractionLayer.tsx +101 -0
  671. package/src/renderer/components/ui/UrlInteractionLayer.tsx +102 -0
  672. package/src/renderer/components/ui/alert-dialog.tsx +127 -0
  673. package/src/renderer/components/ui/auto-resize-textarea.tsx +93 -0
  674. package/src/renderer/components/ui/badge.tsx +37 -0
  675. package/src/renderer/components/ui/button.tsx +54 -0
  676. package/src/renderer/components/ui/checkbox.tsx +29 -0
  677. package/src/renderer/components/ui/combobox.tsx +168 -0
  678. package/src/renderer/components/ui/context-menu.tsx +124 -0
  679. package/src/renderer/components/ui/dialog.tsx +114 -0
  680. package/src/renderer/components/ui/hover-card.tsx +30 -0
  681. package/src/renderer/components/ui/input.tsx +22 -0
  682. package/src/renderer/components/ui/label.tsx +21 -0
  683. package/src/renderer/components/ui/popover.tsx +31 -0
  684. package/src/renderer/components/ui/select.tsx +150 -0
  685. package/src/renderer/components/ui/tabs.tsx +52 -0
  686. package/src/renderer/components/ui/textarea.tsx +21 -0
  687. package/src/renderer/components/ui/tiptap/TiptapBubbleMenu.tsx +75 -0
  688. package/src/renderer/components/ui/tiptap/TiptapEditor.tsx +73 -0
  689. package/src/renderer/components/ui/tiptap/TiptapToolbar.tsx +269 -0
  690. package/src/renderer/components/ui/tiptap/index.ts +3 -0
  691. package/src/renderer/components/ui/tiptap/presets.ts +46 -0
  692. package/src/renderer/components/ui/tiptap/tiptapStyles.css +235 -0
  693. package/src/renderer/components/ui/tiptap/types.ts +32 -0
  694. package/src/renderer/components/ui/tiptap/useTiptapEditor.ts +94 -0
  695. package/src/renderer/components/ui/tooltip.tsx +32 -0
  696. package/src/renderer/constants/cssVariables.ts +226 -0
  697. package/src/renderer/constants/layout.ts +6 -0
  698. package/src/renderer/constants/teamColors.ts +397 -0
  699. package/src/renderer/constants/teamRoles.ts +41 -0
  700. package/src/renderer/contexts/TabUIContext.tsx +51 -0
  701. package/src/renderer/contexts/useTabUIContext.ts +18 -0
  702. package/src/renderer/favicon.png +0 -0
  703. package/src/renderer/features/CLAUDE.md +19 -0
  704. package/src/renderer/hooks/navigation/utils.ts +263 -0
  705. package/src/renderer/hooks/useAttachments.ts +312 -0
  706. package/src/renderer/hooks/useAutoScrollBottom.ts +285 -0
  707. package/src/renderer/hooks/useBranchSync.ts +105 -0
  708. package/src/renderer/hooks/useChipDraftPersistence.ts +172 -0
  709. package/src/renderer/hooks/useCliInstaller.ts +106 -0
  710. package/src/renderer/hooks/useCollapsedGroups.ts +71 -0
  711. package/src/renderer/hooks/useComposerDraft.ts +504 -0
  712. package/src/renderer/hooks/useContinuousScrollNav.ts +50 -0
  713. package/src/renderer/hooks/useCreateTeamDraft.ts +280 -0
  714. package/src/renderer/hooks/useDraftPersistence.ts +140 -0
  715. package/src/renderer/hooks/useEditorKeyboardShortcuts.ts +257 -0
  716. package/src/renderer/hooks/useEffectiveCliProviderStatus.ts +66 -0
  717. package/src/renderer/hooks/useExtensionsTabState.ts +206 -0
  718. package/src/renderer/hooks/useFileListCacheWarmer.ts +38 -0
  719. package/src/renderer/hooks/useFileSuggestions.ts +255 -0
  720. package/src/renderer/hooks/useKeyboardShortcuts.ts +363 -0
  721. package/src/renderer/hooks/useLazyFileContent.ts +150 -0
  722. package/src/renderer/hooks/useMarkCommentsRead.ts +27 -0
  723. package/src/renderer/hooks/useMarkdownScrollSync.ts +158 -0
  724. package/src/renderer/hooks/useMemberStats.ts +45 -0
  725. package/src/renderer/hooks/useMentionDetection.ts +375 -0
  726. package/src/renderer/hooks/usePersistedGridLayout.ts +109 -0
  727. package/src/renderer/hooks/useResizableColumns.ts +140 -0
  728. package/src/renderer/hooks/useResizablePanel.ts +144 -0
  729. package/src/renderer/hooks/useStableTeamMentionMeta.ts +68 -0
  730. package/src/renderer/hooks/useSyncedAnimationStyle.ts +29 -0
  731. package/src/renderer/hooks/useTabNavigationController.ts +524 -0
  732. package/src/renderer/hooks/useTabUI.ts +252 -0
  733. package/src/renderer/hooks/useTaskLocalState.ts +163 -0
  734. package/src/renderer/hooks/useTaskSuggestions.ts +131 -0
  735. package/src/renderer/hooks/useTeamMessagesExpanded.ts +34 -0
  736. package/src/renderer/hooks/useTeamMessagesRead.ts +52 -0
  737. package/src/renderer/hooks/useTeamSuggestions.ts +78 -0
  738. package/src/renderer/hooks/useTheme.ts +138 -0
  739. package/src/renderer/hooks/useToolApprovalDiff.ts +212 -0
  740. package/src/renderer/hooks/useUnreadCommentCount.ts +14 -0
  741. package/src/renderer/hooks/useViewedFiles.ts +74 -0
  742. package/src/renderer/hooks/useViewportCommentRead.ts +147 -0
  743. package/src/renderer/hooks/useViewportObserver.ts +138 -0
  744. package/src/renderer/hooks/useVisibleAIGroup.ts +122 -0
  745. package/src/renderer/hooks/useVisibleFileSection.ts +114 -0
  746. package/src/renderer/hooks/useZoomFactor.ts +36 -0
  747. package/src/renderer/index.css +1560 -0
  748. package/src/renderer/index.html +1293 -0
  749. package/src/renderer/lib/utils.ts +6 -0
  750. package/src/renderer/main.tsx +30 -0
  751. package/src/renderer/sentry.ts +104 -0
  752. package/src/renderer/services/__tests__/createTeamPreferences.test.ts +67 -0
  753. package/src/renderer/services/commentReadStorage.ts +349 -0
  754. package/src/renderer/services/composerDraftStorage.ts +271 -0
  755. package/src/renderer/services/contextStorage.ts +201 -0
  756. package/src/renderer/services/createTeamDraftStorage.ts +151 -0
  757. package/src/renderer/services/createTeamPreferences.ts +361 -0
  758. package/src/renderer/services/dashboardCliStatusBannerPreference.ts +20 -0
  759. package/src/renderer/services/draftStorage.ts +128 -0
  760. package/src/renderer/services/layout-system/BrowserGridLayoutRepository.ts +111 -0
  761. package/src/renderer/services/layout-system/GridLayoutRepository.ts +8 -0
  762. package/src/renderer/services/layout-system/gridLayoutSchema.ts +137 -0
  763. package/src/renderer/services/layout-system/gridLayoutTypes.ts +17 -0
  764. package/src/renderer/store/index.ts +1556 -0
  765. package/src/renderer/store/slices/changeReviewSlice.ts +1694 -0
  766. package/src/renderer/store/slices/cliInstallerSlice.ts +689 -0
  767. package/src/renderer/store/slices/configSlice.ts +111 -0
  768. package/src/renderer/store/slices/connectionSlice.ts +221 -0
  769. package/src/renderer/store/slices/contextSlice.ts +394 -0
  770. package/src/renderer/store/slices/conversationSlice.ts +510 -0
  771. package/src/renderer/store/slices/editorSlice.ts +1455 -0
  772. package/src/renderer/store/slices/extensionsSlice.ts +1415 -0
  773. package/src/renderer/store/slices/notificationSlice.ts +277 -0
  774. package/src/renderer/store/slices/paneSlice.ts +357 -0
  775. package/src/renderer/store/slices/projectSlice.ts +70 -0
  776. package/src/renderer/store/slices/repositorySlice.ts +165 -0
  777. package/src/renderer/store/slices/scheduleSlice.ts +246 -0
  778. package/src/renderer/store/slices/sessionDetailSlice.ts +755 -0
  779. package/src/renderer/store/slices/sessionSlice.ts +539 -0
  780. package/src/renderer/store/slices/subagentSlice.ts +145 -0
  781. package/src/renderer/store/slices/tabSlice.ts +842 -0
  782. package/src/renderer/store/slices/tabUISlice.ts +319 -0
  783. package/src/renderer/store/slices/teamSlice.ts +5080 -0
  784. package/src/renderer/store/slices/uiSlice.ts +45 -0
  785. package/src/renderer/store/types.ts +103 -0
  786. package/src/renderer/store/utils/paneHelpers.ts +134 -0
  787. package/src/renderer/store/utils/pathResolution.ts +121 -0
  788. package/src/renderer/store/utils/stateResetHelpers.ts +72 -0
  789. package/src/renderer/types/api.ts +8 -0
  790. package/src/renderer/types/claudeMd.ts +74 -0
  791. package/src/renderer/types/contextInjection.ts +309 -0
  792. package/src/renderer/types/data.ts +144 -0
  793. package/src/renderer/types/groups.ts +406 -0
  794. package/src/renderer/types/inlineChip.ts +110 -0
  795. package/src/renderer/types/mention.ts +38 -0
  796. package/src/renderer/types/notifications.ts +18 -0
  797. package/src/renderer/types/panes.ts +35 -0
  798. package/src/renderer/types/sessionReport.ts +386 -0
  799. package/src/renderer/types/tabs.ts +249 -0
  800. package/src/renderer/types/teamMessagesPanelMode.ts +1 -0
  801. package/src/renderer/utils/__tests__/teamEffortOptions.test.ts +217 -0
  802. package/src/renderer/utils/__tests__/teamModelAvailability.codexCatalog.test.ts +383 -0
  803. package/src/renderer/utils/agentMessageFormatting.ts +139 -0
  804. package/src/renderer/utils/aiGroupEnhancer.ts +78 -0
  805. package/src/renderer/utils/aiGroupHelpers.ts +208 -0
  806. package/src/renderer/utils/attachmentUtils.ts +60 -0
  807. package/src/renderer/utils/bootstrapPromptSanitizer.ts +225 -0
  808. package/src/renderer/utils/bugReportUtils.ts +157 -0
  809. package/src/renderer/utils/buildSelectionAction.ts +116 -0
  810. package/src/renderer/utils/chipUtils.ts +372 -0
  811. package/src/renderer/utils/claudeCodeOnlyProviders.ts +126 -0
  812. package/src/renderer/utils/claudeMdTracker.ts +644 -0
  813. package/src/renderer/utils/codemirrorLanguages.ts +141 -0
  814. package/src/renderer/utils/codemirrorSelectionInfo.ts +41 -0
  815. package/src/renderer/utils/codemirrorTheme.ts +138 -0
  816. package/src/renderer/utils/contextMath.ts +55 -0
  817. package/src/renderer/utils/contextTracker.ts +1100 -0
  818. package/src/renderer/utils/crossTeamPendingReplies.ts +92 -0
  819. package/src/renderer/utils/dateGrouping.ts +91 -0
  820. package/src/renderer/utils/diffViewedStorage.ts +120 -0
  821. package/src/renderer/utils/displayItemBuilder.ts +587 -0
  822. package/src/renderer/utils/displaySummary.ts +74 -0
  823. package/src/renderer/utils/editorBridge.ts +90 -0
  824. package/src/renderer/utils/fileTreeBuilder.ts +110 -0
  825. package/src/renderer/utils/formatAgentRole.ts +24 -0
  826. package/src/renderer/utils/formatters.ts +61 -0
  827. package/src/renderer/utils/groupTransformer.ts +744 -0
  828. package/src/renderer/utils/idleNotificationSemantics.ts +76 -0
  829. package/src/renderer/utils/keyboardUtils.ts +92 -0
  830. package/src/renderer/utils/lastOutputDetector.ts +150 -0
  831. package/src/renderer/utils/markdownPlugins.ts +60 -0
  832. package/src/renderer/utils/memberAvatarCatalog.ts +38 -0
  833. package/src/renderer/utils/memberHelpers.ts +858 -0
  834. package/src/renderer/utils/memberLaunchDiagnostics.ts +216 -0
  835. package/src/renderer/utils/memberRuntimeSummary.ts +122 -0
  836. package/src/renderer/utils/memberSpawnStatusPolling.ts +29 -0
  837. package/src/renderer/utils/mentionLinkify.ts +90 -0
  838. package/src/renderer/utils/mentionSuggestions.ts +34 -0
  839. package/src/renderer/utils/mergeTeamMessages.ts +27 -0
  840. package/src/renderer/utils/messageRenderEquality.ts +158 -0
  841. package/src/renderer/utils/modelExtractor.ts +90 -0
  842. package/src/renderer/utils/multimodelProviderVisibility.ts +32 -0
  843. package/src/renderer/utils/openCodeModelRecommendations.ts +1326 -0
  844. package/src/renderer/utils/openCodeRuntimeDeliveryDiagnostics.ts +79 -0
  845. package/src/renderer/utils/pathDisplay.ts +149 -0
  846. package/src/renderer/utils/pathNormalize.ts +61 -0
  847. package/src/renderer/utils/pathUtils.ts +47 -0
  848. package/src/renderer/utils/platformKeys.ts +24 -0
  849. package/src/renderer/utils/previewRegistry.ts +45 -0
  850. package/src/renderer/utils/projectColor.ts +54 -0
  851. package/src/renderer/utils/projectLookup.ts +64 -0
  852. package/src/renderer/utils/providerBackendIdentity.ts +43 -0
  853. package/src/renderer/utils/providerSlashCommands.ts +122 -0
  854. package/src/renderer/utils/quickOpenCache.ts +40 -0
  855. package/src/renderer/utils/refreshCliStatus.ts +17 -0
  856. package/src/renderer/utils/reportAssessments.ts +555 -0
  857. package/src/renderer/utils/reviewDecisionScope.ts +81 -0
  858. package/src/renderer/utils/reviewKey.ts +132 -0
  859. package/src/renderer/utils/runtimeDisplayName.ts +26 -0
  860. package/src/renderer/utils/scheduleFormatters.ts +45 -0
  861. package/src/renderer/utils/sessionAnalyzer.ts +1346 -0
  862. package/src/renderer/utils/sessionExporter.ts +427 -0
  863. package/src/renderer/utils/sessionTitleParser.ts +69 -0
  864. package/src/renderer/utils/skillCommandSuggestions.ts +77 -0
  865. package/src/renderer/utils/slashCommandExtractor.ts +154 -0
  866. package/src/renderer/utils/streamJsonParser.ts +393 -0
  867. package/src/renderer/utils/stringUtils.ts +50 -0
  868. package/src/renderer/utils/syntaxHighlighter.ts +158 -0
  869. package/src/renderer/utils/tabLabelDisambiguation.ts +99 -0
  870. package/src/renderer/utils/taskChangePresence.ts +19 -0
  871. package/src/renderer/utils/taskChangeRequest.ts +122 -0
  872. package/src/renderer/utils/taskCommentPendingReply.ts +74 -0
  873. package/src/renderer/utils/taskGrouping.ts +151 -0
  874. package/src/renderer/utils/taskReferenceUtils.ts +331 -0
  875. package/src/renderer/utils/teamEffortOptions.ts +150 -0
  876. package/src/renderer/utils/teamLaunchSummaryCopy.ts +17 -0
  877. package/src/renderer/utils/teamMessageExpandStorage.ts +39 -0
  878. package/src/renderer/utils/teamMessageFiltering.ts +95 -0
  879. package/src/renderer/utils/teamMessageKey.ts +14 -0
  880. package/src/renderer/utils/teamMessageReadStorage.ts +49 -0
  881. package/src/renderer/utils/teamModelAvailability.ts +465 -0
  882. package/src/renderer/utils/teamModelCatalog.ts +502 -0
  883. package/src/renderer/utils/teamModelContext.ts +34 -0
  884. package/src/renderer/utils/teamProvisioningPresentation.ts +772 -0
  885. package/src/renderer/utils/teamRuntimeSummary.ts +53 -0
  886. package/src/renderer/utils/toolLinkingEngine.ts +117 -0
  887. package/src/renderer/utils/toolRendering/index.ts +14 -0
  888. package/src/renderer/utils/toolRendering/toolContentChecks.ts +58 -0
  889. package/src/renderer/utils/toolRendering/toolSummaryHelpers.ts +276 -0
  890. package/src/renderer/utils/toolRendering/toolTokens.ts +57 -0
  891. package/src/renderer/utils/unwrapIpc.ts +31 -0
  892. package/src/renderer/utils/urlMatchUtils.ts +45 -0
  893. package/src/renderer/vite-env.d.ts +21 -0
  894. package/src/shared/constants/agentBlocks.ts +129 -0
  895. package/src/shared/constants/attachments.ts +175 -0
  896. package/src/shared/constants/cache.ts +12 -0
  897. package/src/shared/constants/cli.ts +15 -0
  898. package/src/shared/constants/crossTeam.ts +126 -0
  899. package/src/shared/constants/index.ts +15 -0
  900. package/src/shared/constants/kanban.ts +9 -0
  901. package/src/shared/constants/memberColors.ts +140 -0
  902. package/src/shared/constants/opencodeTaskLogAttribution.ts +1 -0
  903. package/src/shared/constants/teamLimits.ts +2 -0
  904. package/src/shared/constants/trafficLights.ts +60 -0
  905. package/src/shared/constants/triggerColors.ts +126 -0
  906. package/src/shared/constants/window.ts +12 -0
  907. package/src/shared/types/api.ts +1062 -0
  908. package/src/shared/types/ccConnect.ts +399 -0
  909. package/src/shared/types/cliInstaller.ts +335 -0
  910. package/src/shared/types/editor.ts +279 -0
  911. package/src/shared/types/extensions/api.ts +90 -0
  912. package/src/shared/types/extensions/apikey.ts +40 -0
  913. package/src/shared/types/extensions/common.ts +16 -0
  914. package/src/shared/types/extensions/index.ts +67 -0
  915. package/src/shared/types/extensions/mcp.ts +132 -0
  916. package/src/shared/types/extensions/plugin.ts +85 -0
  917. package/src/shared/types/extensions/skill.ts +173 -0
  918. package/src/shared/types/index.ts +48 -0
  919. package/src/shared/types/ipc.ts +5 -0
  920. package/src/shared/types/notifications.ts +407 -0
  921. package/src/shared/types/providers.ts +116 -0
  922. package/src/shared/types/review.ts +319 -0
  923. package/src/shared/types/schedule.ts +124 -0
  924. package/src/shared/types/team.ts +1726 -0
  925. package/src/shared/types/terminal.ts +49 -0
  926. package/src/shared/types/visualization.ts +60 -0
  927. package/src/shared/utils/__tests__/contextMetrics.test.ts +260 -0
  928. package/src/shared/utils/__tests__/ephemeralProjectPath.test.ts +42 -0
  929. package/src/shared/utils/__tests__/teamProvider.test.ts +29 -0
  930. package/src/shared/utils/agentLanguage.ts +122 -0
  931. package/src/shared/utils/anthropicLaunchModel.ts +96 -0
  932. package/src/shared/utils/anthropicModelDefaults.ts +3 -0
  933. package/src/shared/utils/apiErrorDetector.ts +13 -0
  934. package/src/shared/utils/boardTaskActivityLabels.ts +128 -0
  935. package/src/shared/utils/boardTaskActivityPresentation.ts +75 -0
  936. package/src/shared/utils/cliArgsParser.ts +129 -0
  937. package/src/shared/utils/contentSanitizer.ts +207 -0
  938. package/src/shared/utils/contextMetrics.ts +236 -0
  939. package/src/shared/utils/costFormatting.ts +45 -0
  940. package/src/shared/utils/diffContextHash.ts +22 -0
  941. package/src/shared/utils/effortLevels.ts +73 -0
  942. package/src/shared/utils/ephemeralProjectPath.ts +41 -0
  943. package/src/shared/utils/errorHandling.ts +26 -0
  944. package/src/shared/utils/extensionNormalizers.ts +336 -0
  945. package/src/shared/utils/idleNotificationSemantics.ts +86 -0
  946. package/src/shared/utils/inboxNoise.ts +158 -0
  947. package/src/shared/utils/leadDetection.ts +63 -0
  948. package/src/shared/utils/logger.ts +69 -0
  949. package/src/shared/utils/markdownTextSearch.ts +210 -0
  950. package/src/shared/utils/mcpScopes.ts +36 -0
  951. package/src/shared/utils/modelParser.ts +158 -0
  952. package/src/shared/utils/opencodeModelRef.ts +78 -0
  953. package/src/shared/utils/platformPath.ts +103 -0
  954. package/src/shared/utils/pricing.ts +129 -0
  955. package/src/shared/utils/providerBackend.ts +90 -0
  956. package/src/shared/utils/providerExtensionCapabilities.ts +92 -0
  957. package/src/shared/utils/providerModelSelection.ts +5 -0
  958. package/src/shared/utils/providerModelVisibility.ts +47 -0
  959. package/src/shared/utils/rateLimitDetector.ts +334 -0
  960. package/src/shared/utils/reviewState.ts +74 -0
  961. package/src/shared/utils/sentryConfig.ts +26 -0
  962. package/src/shared/utils/skillRoots.ts +93 -0
  963. package/src/shared/utils/slashCommands.ts +128 -0
  964. package/src/shared/utils/taskChangePresence.ts +35 -0
  965. package/src/shared/utils/taskChangeSince.ts +51 -0
  966. package/src/shared/utils/taskChangeState.ts +49 -0
  967. package/src/shared/utils/taskHistory.ts +82 -0
  968. package/src/shared/utils/taskIdentity.ts +32 -0
  969. package/src/shared/utils/teamGraphDefaultLayout.ts +97 -0
  970. package/src/shared/utils/teamMemberColors.ts +107 -0
  971. package/src/shared/utils/teamMemberName.ts +77 -0
  972. package/src/shared/utils/teamProvider.ts +73 -0
  973. package/src/shared/utils/teamStableOwnerId.ts +12 -0
  974. package/src/shared/utils/teammateMessageParser.ts +52 -0
  975. package/src/shared/utils/tokenFormatting.ts +91 -0
  976. package/src/shared/utils/toolSummary.ts +279 -0
  977. package/src/shared/utils/version.ts +29 -0
  978. package/src/types/agent-teams-controller.d.ts +163 -0
  979. package/src/types/node-pty.d.ts +22 -0
  980. package/src/types/pidusage.d.ts +23 -0
@@ -0,0 +1,1556 @@
1
+ /**
2
+ * Store index - combines all slices and exports the unified store.
3
+ */
4
+
5
+ import { api } from '@renderer/api';
6
+ import { syncRendererTelemetry } from '@renderer/sentry';
7
+ import { cleanupStale as cleanupCommentReadState } from '@renderer/services/commentReadStorage';
8
+ import { normalizePath } from '@renderer/utils/pathNormalize';
9
+ import { refreshCliStatusForCurrentMode } from '@renderer/utils/refreshCliStatus';
10
+ import {
11
+ buildTaskChangePresenceKey,
12
+ buildTaskChangeRequestOptions,
13
+ canDisplayTaskChangesForOptions,
14
+ } from '@renderer/utils/taskChangeRequest';
15
+ import { createLogger } from '@shared/utils/logger';
16
+ import { create } from 'zustand';
17
+
18
+ import { createChangeReviewSlice } from './slices/changeReviewSlice';
19
+ import {
20
+ createCliInstallerSlice,
21
+ getIncompleteMultimodelProviderIds,
22
+ getModelOnlyFallbackProviderIds,
23
+ mergeCliStatusPreservingHydratedProviders,
24
+ } from './slices/cliInstallerSlice';
25
+ import { createConfigSlice } from './slices/configSlice';
26
+ import { createConnectionSlice } from './slices/connectionSlice';
27
+ import { createContextSlice } from './slices/contextSlice';
28
+ import { createConversationSlice } from './slices/conversationSlice';
29
+ import { createEditorSlice } from './slices/editorSlice';
30
+ import { createExtensionsSlice } from './slices/extensionsSlice';
31
+ import { createNotificationSlice } from './slices/notificationSlice';
32
+ import { createPaneSlice } from './slices/paneSlice';
33
+ import { createProjectSlice } from './slices/projectSlice';
34
+ import { createRepositorySlice } from './slices/repositorySlice';
35
+ import { createScheduleSlice } from './slices/scheduleSlice';
36
+ import { createSessionDetailSlice } from './slices/sessionDetailSlice';
37
+ import { createSessionSlice } from './slices/sessionSlice';
38
+ import { createSubagentSlice } from './slices/subagentSlice';
39
+ import { createTabSlice } from './slices/tabSlice';
40
+ import { createTabUISlice } from './slices/tabUISlice';
41
+ import {
42
+ createTeamSlice,
43
+ getActiveTeamPendingReplyWaits,
44
+ getLastResolvedTeamDataRefreshAt,
45
+ hasActiveTeamPendingReplyWait,
46
+ isTeamDataRefreshPending,
47
+ selectTeamDataForName,
48
+ } from './slices/teamSlice';
49
+ import { createUISlice } from './slices/uiSlice';
50
+
51
+ import type { DetectedError } from '../types/data';
52
+ import type { AppState } from './types';
53
+ import type {
54
+ ActiveToolCall,
55
+ CliInstallerProgress,
56
+ CliProviderId,
57
+ LeadContextUsage,
58
+ ScheduleChangeEvent,
59
+ TeamChangeEvent,
60
+ ToolActivityEventPayload,
61
+ ToolApprovalEvent,
62
+ ToolApprovalRequest,
63
+ } from '@shared/types';
64
+
65
+ const ENABLE_AUTO_TEAM_CHANGE_PRESENCE_TRACKING = false;
66
+ const IN_PROGRESS_CHANGE_PRESENCE_POLL_MS = 10_000;
67
+ const FINISHED_TOOL_DISPLAY_MS = 1_500;
68
+ const MAX_TOOL_HISTORY_PER_MEMBER = 6;
69
+ const TEAM_CHANGE_EVENT_BURST_WINDOW_MS = 4_000;
70
+ const TEAM_CHANGE_EVENT_BURST_WARN_COUNT = 8;
71
+ const TEAM_CHANGE_EVENT_WARN_THROTTLE_MS = 2_000;
72
+ const TEAM_VISIBLE_IDLE_WATCHDOG_POLL_MS = 10_000;
73
+ const TEAM_VISIBLE_IDLE_WATCHDOG_STALE_MS = 30_000;
74
+ const TEAM_MESSAGE_FALLBACK_POLL_MS = 10_000;
75
+ const logger = createLogger('Store:index');
76
+ const RELEVANT_TEAM_CHANGE_EVENT_TYPES = new Set<TeamChangeEvent['type']>([
77
+ 'task',
78
+ 'config',
79
+ 'inbox',
80
+ 'lead-message',
81
+ 'lead-context',
82
+ 'lead-activity',
83
+ 'process',
84
+ 'member-spawn',
85
+ ]);
86
+ const teamChangeEventDiagnostics = new Map<
87
+ string,
88
+ {
89
+ windowStartedAt: number;
90
+ count: number;
91
+ lastWarnAt: number;
92
+ countsByType: Record<string, number>;
93
+ }
94
+ >();
95
+
96
+ function noteTeamChangeEventBurst(teamName: string, eventType: string, visible: boolean): void {
97
+ if (!visible) return;
98
+
99
+ const now = Date.now();
100
+ const diagnostic = teamChangeEventDiagnostics.get(teamName) ?? {
101
+ windowStartedAt: now,
102
+ count: 0,
103
+ lastWarnAt: 0,
104
+ countsByType: {},
105
+ };
106
+
107
+ if (now - diagnostic.windowStartedAt > TEAM_CHANGE_EVENT_BURST_WINDOW_MS) {
108
+ diagnostic.windowStartedAt = now;
109
+ diagnostic.count = 0;
110
+ diagnostic.countsByType = {};
111
+ }
112
+
113
+ diagnostic.count += 1;
114
+ diagnostic.countsByType[eventType] = (diagnostic.countsByType[eventType] ?? 0) + 1;
115
+
116
+ if (
117
+ diagnostic.count >= TEAM_CHANGE_EVENT_BURST_WARN_COUNT &&
118
+ now - diagnostic.lastWarnAt >= TEAM_CHANGE_EVENT_WARN_THROTTLE_MS
119
+ ) {
120
+ diagnostic.lastWarnAt = now;
121
+ // Disabled - this warning is too noisy during normal inbox bursts on active teams.
122
+ }
123
+
124
+ teamChangeEventDiagnostics.set(teamName, diagnostic);
125
+ }
126
+
127
+ // =============================================================================
128
+ // Store Creation
129
+ // =============================================================================
130
+
131
+ export const useStore = create<AppState>()((...args) => ({
132
+ ...createProjectSlice(...args),
133
+ ...createRepositorySlice(...args),
134
+ ...createSessionSlice(...args),
135
+ ...createSessionDetailSlice(...args),
136
+ ...createSubagentSlice(...args),
137
+ ...createTeamSlice(...args),
138
+ ...createConversationSlice(...args),
139
+ ...createTabSlice(...args),
140
+ ...createTabUISlice(...args),
141
+ ...createPaneSlice(...args),
142
+ ...createUISlice(...args),
143
+ ...createNotificationSlice(...args),
144
+ ...createConfigSlice(...args),
145
+ ...createConnectionSlice(...args),
146
+ ...createContextSlice(...args),
147
+ ...createChangeReviewSlice(...args),
148
+ ...createCliInstallerSlice(...args),
149
+ ...createEditorSlice(...args),
150
+ ...createScheduleSlice(...args),
151
+ ...createExtensionsSlice(...args),
152
+ }));
153
+
154
+ // =============================================================================
155
+ // Re-exports
156
+ // =============================================================================
157
+
158
+ // =============================================================================
159
+ // Store Initialization - Subscribe to IPC Events
160
+ // =============================================================================
161
+
162
+ /**
163
+ * Initialize notification event listeners and fetch initial notification count.
164
+ * Call this once when the app starts (e.g., in App.tsx useEffect).
165
+ */
166
+ export function initializeNotificationListeners(): () => void {
167
+ void cleanupCommentReadState();
168
+ const cleanupFns: (() => void)[] = [];
169
+ let cliStatusTimer: ReturnType<typeof setTimeout> | null = null;
170
+ useStore.getState().subscribeProvisioningProgress();
171
+ cleanupFns.push(() => {
172
+ useStore.getState().unsubscribeProvisioningProgress();
173
+ });
174
+ // Initial data fetches. Config loads first (needed for theme), then the rest
175
+ // run in parallel (no data dependencies between them). UV_THREADPOOL_SIZE=16
176
+ // prevents thread pool saturation even with concurrent I/O on Windows.
177
+ // Components also fire these from useEffect — loading guards in each action
178
+ // prevent duplicate IPC calls (whichever caller starts first wins).
179
+ void (async () => {
180
+ // Config: fast (in-memory read) — needed for theme before first paint.
181
+ await useStore.getState().fetchConfig();
182
+
183
+ // Sync Sentry renderer telemetry gate from loaded config
184
+ const loadedConfig = useStore.getState().appConfig;
185
+ syncRendererTelemetry(loadedConfig?.general?.telemetryEnabled ?? true);
186
+
187
+ if (api.cliInstaller) {
188
+ // Resolve the configured CLI flavor after config has loaded to avoid
189
+ // bootstrapping multimodel placeholder state in Claude-only mode.
190
+ const delayMs = 3000;
191
+ cliStatusTimer = setTimeout(() => {
192
+ const multimodelEnabled =
193
+ useStore.getState().appConfig?.general?.multimodelEnabled ?? false;
194
+ if (multimodelEnabled) {
195
+ void useStore.getState().bootstrapCliStatus({ multimodelEnabled: true });
196
+ } else {
197
+ void useStore.getState().fetchCliStatus();
198
+ }
199
+ cliStatusTimer = null;
200
+ }, delayMs);
201
+ }
202
+
203
+ // Remaining fetches have no data dependency on each other — run in parallel
204
+ // to avoid blocking teams/notifications behind a slow repository scan.
205
+ await Promise.all([
206
+ useStore.getState().fetchRepositoryGroups(),
207
+ useStore.getState().fetchAllTasks(),
208
+ useStore.getState().fetchTeams(),
209
+ useStore.getState().fetchNotifications(),
210
+ useStore.getState().fetchSchedules(),
211
+ ]);
212
+ })();
213
+ cleanupFns.push(() => {
214
+ if (cliStatusTimer) clearTimeout(cliStatusTimer);
215
+ });
216
+ // This lightweight renderer-side poll keeps visible in-progress task badges fresh.
217
+ // It is intentionally independent from the backend log-source tracking feature flag below.
218
+ const inProgressChangePresencePollTimer = setInterval(() => {
219
+ void pollVisibleTeamInProgressChangePresence();
220
+ }, IN_PROGRESS_CHANGE_PRESENCE_POLL_MS);
221
+ cleanupFns.push(() => {
222
+ clearInterval(inProgressChangePresencePollTimer);
223
+ });
224
+ const pendingSessionRefreshTimers = new Map<string, ReturnType<typeof setTimeout>>();
225
+ const pendingProjectRefreshTimers = new Map<string, ReturnType<typeof setTimeout>>();
226
+ const teamLastRelevantActivityAt = new Map<string, number>();
227
+ const teamLastIdleWatchdogRefreshAt = new Map<string, number>();
228
+ let teamRefreshTimers = new Map<string, ReturnType<typeof setTimeout>>();
229
+ let teamMessageRefreshTimers = new Map<string, ReturnType<typeof setTimeout>>();
230
+ let teamPresenceRefreshTimers = new Map<string, ReturnType<typeof setTimeout>>();
231
+ let memberSpawnRefreshTimers = new Map<string, ReturnType<typeof setTimeout>>();
232
+ let teamAgentRuntimeRefreshTimers = new Map<string, ReturnType<typeof setTimeout>>();
233
+ let toolActivityTimers = new Map<string, ReturnType<typeof setTimeout>>();
234
+ let inProgressChangePresencePollInFlight = false;
235
+ let teamMessageFallbackPollInFlight = false;
236
+ const inProgressChangePresenceCursorByTeam = new Map<string, number>();
237
+
238
+ let teamListRefreshTimer: ReturnType<typeof setTimeout> | null = null;
239
+ let globalTasksRefreshTimer: ReturnType<typeof setTimeout> | null = null;
240
+ const SESSION_REFRESH_DEBOUNCE_MS = 150;
241
+ const PROJECT_REFRESH_DEBOUNCE_MS = 300;
242
+ const TEAM_REFRESH_THROTTLE_MS = 800;
243
+ const TEAM_PRESENCE_REFRESH_THROTTLE_MS = 400;
244
+ const TEAM_MEMBER_SPAWN_REFRESH_THROTTLE_MS = 500;
245
+ const TEAM_LIST_REFRESH_THROTTLE_MS = 2000;
246
+ const GLOBAL_TASKS_REFRESH_THROTTLE_MS = 500;
247
+ const refreshTrackedTeamMessages = async (teamName: string): Promise<void> => {
248
+ if (!teamName || !shouldRefreshTeamMessages(teamName)) {
249
+ return;
250
+ }
251
+
252
+ const current = useStore.getState();
253
+ try {
254
+ const headResult = await current.refreshTeamMessagesHead(teamName);
255
+ const latest = useStore.getState();
256
+ const meta = latest.memberActivityMetaByTeam[teamName];
257
+ if (headResult.feedChanged || meta?.feedRevision !== headResult.feedRevision) {
258
+ await latest.refreshMemberActivityMeta(teamName);
259
+ }
260
+ } catch {
261
+ // Best-effort refresh for message-driven events and fallback polling only.
262
+ }
263
+ };
264
+ const scheduleMemberSpawnStatusesRefresh = (teamName: string | null | undefined): void => {
265
+ if (!teamName || !isTeamVisibleInAnyPane(teamName)) {
266
+ return;
267
+ }
268
+ if (memberSpawnRefreshTimers.has(teamName)) {
269
+ return;
270
+ }
271
+ const timer = setTimeout(() => {
272
+ memberSpawnRefreshTimers.delete(teamName);
273
+ void useStore.getState().fetchMemberSpawnStatuses(teamName);
274
+ }, TEAM_MEMBER_SPAWN_REFRESH_THROTTLE_MS);
275
+ memberSpawnRefreshTimers.set(teamName, timer);
276
+ };
277
+ const scheduleTeamAgentRuntimeRefresh = (teamName: string | null | undefined): void => {
278
+ if (!teamName || !isTeamVisibleInAnyPane(teamName)) {
279
+ return;
280
+ }
281
+ if (teamAgentRuntimeRefreshTimers.has(teamName)) {
282
+ return;
283
+ }
284
+ const timer = setTimeout(() => {
285
+ teamAgentRuntimeRefreshTimers.delete(teamName);
286
+ void useStore.getState().fetchTeamAgentRuntime(teamName);
287
+ }, TEAM_MEMBER_SPAWN_REFRESH_THROTTLE_MS);
288
+ teamAgentRuntimeRefreshTimers.set(teamName, timer);
289
+ };
290
+ const scheduleTrackedTeamMessageRefresh = (teamName: string | null | undefined): void => {
291
+ if (!teamName || !shouldRefreshTeamMessages(teamName)) {
292
+ return;
293
+ }
294
+ if (teamMessageRefreshTimers.has(teamName)) {
295
+ return;
296
+ }
297
+ const timer = setTimeout(() => {
298
+ teamMessageRefreshTimers.delete(teamName);
299
+ void refreshTrackedTeamMessages(teamName);
300
+ }, TEAM_REFRESH_THROTTLE_MS);
301
+ teamMessageRefreshTimers.set(teamName, timer);
302
+ };
303
+ const buildToolActivityTimerKey = (
304
+ teamName: string,
305
+ memberName: string,
306
+ toolUseId: string,
307
+ kind: 'fade'
308
+ ): string => `${teamName}:${memberName}:${toolUseId}:${kind}`;
309
+ const clearToolActivityTimer = (
310
+ teamName: string,
311
+ memberName: string,
312
+ toolUseId: string,
313
+ kind: 'fade'
314
+ ): void => {
315
+ const key = buildToolActivityTimerKey(teamName, memberName, toolUseId, kind);
316
+ const existing = toolActivityTimers.get(key);
317
+ if (existing) {
318
+ clearTimeout(existing);
319
+ toolActivityTimers.delete(key);
320
+ }
321
+ };
322
+ const scheduleToolActivityTimer = (
323
+ teamName: string,
324
+ memberName: string,
325
+ toolUseId: string,
326
+ kind: 'fade',
327
+ delayMs: number,
328
+ cb: () => void
329
+ ): void => {
330
+ clearToolActivityTimer(teamName, memberName, toolUseId, kind);
331
+ const key = buildToolActivityTimerKey(teamName, memberName, toolUseId, kind);
332
+ const timer = setTimeout(() => {
333
+ toolActivityTimers.delete(key);
334
+ cb();
335
+ }, delayMs);
336
+ toolActivityTimers.set(key, timer);
337
+ };
338
+ const clearToolActivityTimersForTeam = (teamName: string): void => {
339
+ for (const [key, timer] of toolActivityTimers.entries()) {
340
+ if (!key.startsWith(`${teamName}:`)) continue;
341
+ clearTimeout(timer);
342
+ toolActivityTimers.delete(key);
343
+ }
344
+ };
345
+ const clearRuntimeToolStateForTeam = (
346
+ prev: AppState,
347
+ teamName: string
348
+ ): Pick<AppState, 'activeToolsByTeam' | 'finishedVisibleByTeam' | 'toolHistoryByTeam'> => {
349
+ const nextActive = { ...prev.activeToolsByTeam };
350
+ const nextFinished = { ...prev.finishedVisibleByTeam };
351
+ const nextHistory = { ...prev.toolHistoryByTeam };
352
+ delete nextActive[teamName];
353
+ delete nextFinished[teamName];
354
+ delete nextHistory[teamName];
355
+ return {
356
+ activeToolsByTeam: nextActive,
357
+ finishedVisibleByTeam: nextFinished,
358
+ toolHistoryByTeam: nextHistory,
359
+ };
360
+ };
361
+ const pushToolHistoryEntry = (
362
+ history: Record<string, Record<string, ActiveToolCall[]>>,
363
+ teamName: string,
364
+ entry: ActiveToolCall
365
+ ): Record<string, Record<string, ActiveToolCall[]>> => {
366
+ const teamHistory = { ...(history[teamName] ?? {}) };
367
+ const existing = teamHistory[entry.memberName] ?? [];
368
+ teamHistory[entry.memberName] = [
369
+ entry,
370
+ ...existing.filter((t) => t.toolUseId !== entry.toolUseId),
371
+ ].slice(0, MAX_TOOL_HISTORY_PER_MEMBER);
372
+ return { ...history, [teamName]: teamHistory };
373
+ };
374
+ const upsertMemberToolEntry = (
375
+ teamState: Record<string, Record<string, ActiveToolCall>> | undefined,
376
+ entry: ActiveToolCall
377
+ ): Record<string, Record<string, ActiveToolCall>> => ({
378
+ ...(teamState ?? {}),
379
+ [entry.memberName]: {
380
+ ...((teamState ?? {})[entry.memberName] ?? {}),
381
+ [entry.toolUseId]: entry,
382
+ },
383
+ });
384
+ const removeMemberToolEntry = (
385
+ teamState: Record<string, Record<string, ActiveToolCall>> | undefined,
386
+ memberName: string,
387
+ toolUseId: string
388
+ ): Record<string, Record<string, ActiveToolCall>> => {
389
+ if (!teamState?.[memberName]?.[toolUseId]) return teamState ?? {};
390
+ const nextTeamState = { ...(teamState ?? {}) };
391
+ const nextMemberState = { ...(nextTeamState[memberName] ?? {}) };
392
+ delete nextMemberState[toolUseId];
393
+ if (Object.keys(nextMemberState).length === 0) {
394
+ delete nextTeamState[memberName];
395
+ } else {
396
+ nextTeamState[memberName] = nextMemberState;
397
+ }
398
+ return nextTeamState;
399
+ };
400
+ const removeMemberToolGroup = (
401
+ teamState: Record<string, Record<string, ActiveToolCall>> | undefined,
402
+ memberName: string
403
+ ): Record<string, Record<string, ActiveToolCall>> => {
404
+ if (!teamState?.[memberName]) return teamState ?? {};
405
+ const nextTeamState = { ...(teamState ?? {}) };
406
+ delete nextTeamState[memberName];
407
+ return nextTeamState;
408
+ };
409
+ const removeMemberToolEntries = (
410
+ teamState: Record<string, Record<string, ActiveToolCall>> | undefined,
411
+ memberName: string,
412
+ toolUseIds: readonly string[]
413
+ ): Record<string, Record<string, ActiveToolCall>> => {
414
+ if (!teamState?.[memberName] || toolUseIds.length === 0) return teamState ?? {};
415
+ let nextTeamState = teamState ?? {};
416
+ let changed = false;
417
+ for (const toolUseId of toolUseIds) {
418
+ if (!nextTeamState[memberName]?.[toolUseId]) continue;
419
+ nextTeamState = removeMemberToolEntry(nextTeamState, memberName, toolUseId);
420
+ changed = true;
421
+ }
422
+ return changed ? nextTeamState : (teamState ?? {});
423
+ };
424
+ const getBaseProjectId = (projectId: string | null | undefined): string | null => {
425
+ if (!projectId) return null;
426
+ const separatorIndex = projectId.indexOf('::');
427
+ return separatorIndex >= 0 ? projectId.slice(0, separatorIndex) : projectId;
428
+ };
429
+
430
+ const pollVisibleTeamInProgressChangePresence = async (): Promise<void> => {
431
+ if (inProgressChangePresencePollInFlight) {
432
+ return;
433
+ }
434
+
435
+ const state = useStore.getState();
436
+ const visibleTeamNames = Array.from(getVisibleTeamNamesInAnyPane(state));
437
+ if (visibleTeamNames.length === 0) {
438
+ return;
439
+ }
440
+
441
+ // Cleanup cursors for teams that no longer exist (prevent unbounded growth)
442
+ if (inProgressChangePresenceCursorByTeam.size > 50) {
443
+ const teamNames = new Set(useStore.getState().teams.map((t) => t.teamName));
444
+ for (const key of inProgressChangePresenceCursorByTeam.keys()) {
445
+ if (!teamNames.has(key)) {
446
+ inProgressChangePresenceCursorByTeam.delete(key);
447
+ }
448
+ }
449
+ }
450
+
451
+ inProgressChangePresencePollInFlight = true;
452
+ try {
453
+ for (const teamName of visibleTeamNames) {
454
+ const teamData = selectTeamDataForName(state, teamName);
455
+ if (teamData?.teamName !== teamName) {
456
+ if (!isTeamDataRefreshPending(teamName)) {
457
+ void state.refreshTeamData(teamName, { withDedup: true });
458
+ }
459
+ continue;
460
+ }
461
+
462
+ const candidateTasks = teamData.tasks.filter((task) => {
463
+ if (task.status !== 'in_progress') {
464
+ return false;
465
+ }
466
+ return canDisplayTaskChangesForOptions(buildTaskChangeRequestOptions(task));
467
+ });
468
+ if (candidateTasks.length === 0) {
469
+ inProgressChangePresenceCursorByTeam.delete(teamName);
470
+ continue;
471
+ }
472
+
473
+ const cursor = inProgressChangePresenceCursorByTeam.get(teamName) ?? 0;
474
+ const unknownTasks = candidateTasks.filter((task) => task.changePresence === 'unknown');
475
+ const sourceTasks = unknownTasks.length > 0 ? unknownTasks : candidateTasks;
476
+ const nextTask = sourceTasks[cursor % sourceTasks.length];
477
+
478
+ inProgressChangePresenceCursorByTeam.set(teamName, (cursor + 1) % sourceTasks.length);
479
+
480
+ const current = useStore.getState();
481
+ if (!isTeamVisibleInAnyPane(teamName)) {
482
+ continue;
483
+ }
484
+
485
+ const currentTeamData = selectTeamDataForName(current, teamName);
486
+ if (currentTeamData?.teamName !== teamName) {
487
+ if (!isTeamDataRefreshPending(teamName)) {
488
+ void current.refreshTeamData(teamName, { withDedup: true });
489
+ }
490
+ continue;
491
+ }
492
+
493
+ const currentTask = currentTeamData.tasks.find((task) => task.id === nextTask.id);
494
+ if (currentTask?.status !== 'in_progress') {
495
+ continue;
496
+ }
497
+
498
+ const requestOptions = buildTaskChangeRequestOptions(currentTask);
499
+ const cacheKey = buildTaskChangePresenceKey(teamName, currentTask.id, requestOptions);
500
+ current.invalidateTaskChangePresence([cacheKey]);
501
+ await current.checkTaskHasChanges(teamName, currentTask.id, requestOptions);
502
+ }
503
+ } catch {
504
+ // Best-effort polling for in-progress tasks only.
505
+ } finally {
506
+ inProgressChangePresencePollInFlight = false;
507
+ }
508
+ };
509
+
510
+ const scheduleSessionRefresh = (projectId: string, sessionId: string): void => {
511
+ const key = `${projectId}/${sessionId}`;
512
+ // Throttle (not trailing debounce): keep at most one pending refresh per session.
513
+ // Debounce can delay updates indefinitely while the file is continuously appended.
514
+ if (pendingSessionRefreshTimers.has(key)) {
515
+ return;
516
+ }
517
+ const timer = setTimeout(() => {
518
+ pendingSessionRefreshTimers.delete(key);
519
+ const state = useStore.getState();
520
+ void state.refreshSessionInPlace(projectId, sessionId);
521
+ }, SESSION_REFRESH_DEBOUNCE_MS);
522
+ pendingSessionRefreshTimers.set(key, timer);
523
+ };
524
+
525
+ const scheduleProjectRefresh = (projectId: string): void => {
526
+ const existingTimer = pendingProjectRefreshTimers.get(projectId);
527
+ if (existingTimer) {
528
+ clearTimeout(existingTimer);
529
+ }
530
+ const timer = setTimeout(() => {
531
+ pendingProjectRefreshTimers.delete(projectId);
532
+ const state = useStore.getState();
533
+ void state.refreshSessionsInPlace(projectId);
534
+ }, PROJECT_REFRESH_DEBOUNCE_MS);
535
+ pendingProjectRefreshTimers.set(projectId, timer);
536
+ };
537
+
538
+ // Listen for new notifications from main process
539
+ if (api.notifications?.onNew) {
540
+ const cleanup = api.notifications.onNew((_event: unknown, error: unknown) => {
541
+ // Cast the error to DetectedError type
542
+ const notification = error as DetectedError;
543
+ if (notification?.id) {
544
+ // Keep list in sync immediately; unread count is synced via notification:updated/fetch.
545
+ useStore.setState((state) => {
546
+ if (state.notifications.some((n) => n.id === notification.id)) {
547
+ return {};
548
+ }
549
+ return { notifications: [notification, ...state.notifications].slice(0, 200) };
550
+ });
551
+ }
552
+ });
553
+ if (typeof cleanup === 'function') {
554
+ cleanupFns.push(cleanup);
555
+ }
556
+ }
557
+
558
+ // Listen for notification updates from main process
559
+ if (api.notifications?.onUpdated) {
560
+ const cleanup = api.notifications.onUpdated(
561
+ (_event: unknown, payload: { total: number; unreadCount: number }) => {
562
+ const unreadCount =
563
+ typeof payload.unreadCount === 'number' && Number.isFinite(payload.unreadCount)
564
+ ? Math.max(0, Math.floor(payload.unreadCount))
565
+ : 0;
566
+ useStore.setState({ unreadCount });
567
+ }
568
+ );
569
+ if (typeof cleanup === 'function') {
570
+ cleanupFns.push(cleanup);
571
+ }
572
+ }
573
+
574
+ // Navigate to error when user clicks a native OS notification
575
+ if (api.notifications?.onClicked) {
576
+ const cleanup = api.notifications.onClicked((_event: unknown, data: unknown) => {
577
+ const error = data as DetectedError;
578
+ if (error?.id && error?.sessionId && error?.projectId) {
579
+ useStore.getState().navigateToError(error);
580
+ }
581
+ });
582
+ if (typeof cleanup === 'function') {
583
+ cleanupFns.push(cleanup);
584
+ }
585
+ }
586
+
587
+ // fetchNotifications() is called in the parallel init chain above.
588
+
589
+ /**
590
+ * Check if a session is visible in any pane (not just the focused pane's active tab).
591
+ * This ensures file change and task-list listeners refresh sessions shown in any split pane.
592
+ */
593
+ const isSessionVisibleInAnyPane = (sessionId: string): boolean => {
594
+ const { paneLayout } = useStore.getState();
595
+ return paneLayout.panes.some(
596
+ (pane) =>
597
+ pane.activeTabId != null &&
598
+ pane.tabs.some(
599
+ (tab) =>
600
+ tab.id === pane.activeTabId && tab.type === 'session' && tab.sessionId === sessionId
601
+ )
602
+ );
603
+ };
604
+
605
+ const getVisibleTeamNamesInAnyPane = (state = useStore.getState()): Set<string> => {
606
+ const { paneLayout } = state;
607
+ const visibleTeamNames = new Set<string>();
608
+ for (const pane of paneLayout.panes) {
609
+ if (!pane.activeTabId) continue;
610
+ const activeTab = pane.tabs.find((tab) => tab.id === pane.activeTabId);
611
+ if (
612
+ (activeTab?.type === 'team' || activeTab?.type === 'graph') &&
613
+ activeTab.teamName != null
614
+ ) {
615
+ visibleTeamNames.add(activeTab.teamName);
616
+ }
617
+ }
618
+ return visibleTeamNames;
619
+ };
620
+
621
+ const isTeamVisibleInAnyPane = (teamName: string): boolean => {
622
+ return getVisibleTeamNamesInAnyPane().has(teamName);
623
+ };
624
+
625
+ const shouldRefreshTeamMessages = (teamName: string): boolean => {
626
+ return isTeamVisibleInAnyPane(teamName) || hasActiveTeamPendingReplyWait(teamName);
627
+ };
628
+
629
+ const getTrackedTeamMessageRefreshTeams = (): Set<string> => {
630
+ const tracked = getVisibleTeamNamesInAnyPane();
631
+ for (const teamName of getActiveTeamPendingReplyWaits()) {
632
+ tracked.add(teamName);
633
+ }
634
+ return tracked;
635
+ };
636
+
637
+ const getTrackedChangePresenceTeams = (): Set<string> => {
638
+ const state = useStore.getState();
639
+ const tracked = new Set<string>();
640
+ for (const teamName of getVisibleTeamNamesInAnyPane(state)) {
641
+ if (selectTeamDataForName(state, teamName)) {
642
+ tracked.add(teamName);
643
+ }
644
+ }
645
+ return tracked;
646
+ };
647
+
648
+ const getTrackedToolActivityTeams = (): Set<string> => {
649
+ return getVisibleTeamNamesInAnyPane();
650
+ };
651
+
652
+ const noteRelevantTeamActivity = (teamName: string, timestamp = Date.now()): void => {
653
+ teamLastRelevantActivityAt.set(teamName, timestamp);
654
+ };
655
+
656
+ const getFocusedVisibleTeamName = (): string | null => {
657
+ const state = useStore.getState();
658
+ const focusedPane = state.paneLayout.panes.find(
659
+ (pane) => pane.id === state.paneLayout.focusedPaneId
660
+ );
661
+ if (!focusedPane?.activeTabId) {
662
+ return null;
663
+ }
664
+
665
+ const activeTab = focusedPane.tabs.find((tab) => tab.id === focusedPane.activeTabId);
666
+ if ((activeTab?.type !== 'team' && activeTab?.type !== 'graph') || !activeTab.teamName) {
667
+ return null;
668
+ }
669
+
670
+ if (!selectTeamDataForName(state, activeTab.teamName)) {
671
+ return null;
672
+ }
673
+
674
+ return activeTab.teamName;
675
+ };
676
+
677
+ const pollTrackedTeamMessageFallback = async (): Promise<void> => {
678
+ if (teamMessageFallbackPollInFlight) {
679
+ return;
680
+ }
681
+
682
+ const teamNames = getTrackedTeamMessageRefreshTeams();
683
+ if (teamNames.size === 0) {
684
+ return;
685
+ }
686
+
687
+ teamMessageFallbackPollInFlight = true;
688
+ try {
689
+ await Promise.allSettled(
690
+ Array.from(teamNames, (teamName) => refreshTrackedTeamMessages(teamName))
691
+ );
692
+ } finally {
693
+ teamMessageFallbackPollInFlight = false;
694
+ }
695
+ };
696
+
697
+ const pollFocusedVisibleTeamIdleWatchdog = async (): Promise<void> => {
698
+ if (typeof document !== 'undefined' && document.visibilityState === 'hidden') {
699
+ return;
700
+ }
701
+
702
+ const current = useStore.getState();
703
+ const teamName = getFocusedVisibleTeamName();
704
+ if (!teamName || !isTeamVisibleInAnyPane(teamName)) {
705
+ return;
706
+ }
707
+
708
+ if (current.selectedTeamName === teamName && current.selectedTeamLoading) {
709
+ return;
710
+ }
711
+
712
+ if (isTeamDataRefreshPending(teamName)) {
713
+ return;
714
+ }
715
+
716
+ const lastRelevantActivityAt = teamLastRelevantActivityAt.get(teamName) ?? 0;
717
+ const lastResolvedRefreshAt = getLastResolvedTeamDataRefreshAt(teamName) ?? 0;
718
+ const idleBaselineAt = Math.max(lastRelevantActivityAt, lastResolvedRefreshAt);
719
+ if (idleBaselineAt === 0) {
720
+ return;
721
+ }
722
+
723
+ const now = Date.now();
724
+ if (now - idleBaselineAt < TEAM_VISIBLE_IDLE_WATCHDOG_STALE_MS) {
725
+ return;
726
+ }
727
+
728
+ const lastWatchdogRefreshAt = teamLastIdleWatchdogRefreshAt.get(teamName) ?? 0;
729
+ if (lastWatchdogRefreshAt >= idleBaselineAt) {
730
+ return;
731
+ }
732
+
733
+ logger.warn(`[perf] idle-watchdog refresh team=${teamName} idleMs=${now - idleBaselineAt}`);
734
+
735
+ try {
736
+ await current.refreshTeamData(teamName, { withDedup: true });
737
+ } finally {
738
+ teamLastIdleWatchdogRefreshAt.set(
739
+ teamName,
740
+ Math.max(getLastResolvedTeamDataRefreshAt(teamName) ?? 0, idleBaselineAt, Date.now())
741
+ );
742
+ }
743
+ };
744
+
745
+ if (ENABLE_AUTO_TEAM_CHANGE_PRESENCE_TRACKING && api.teams?.setChangePresenceTracking) {
746
+ let trackedTeamNames = new Set<string>();
747
+ const syncVisibleTeamTracking = (): void => {
748
+ const nextTrackedTeamNames = getTrackedChangePresenceTeams();
749
+
750
+ for (const teamName of nextTrackedTeamNames) {
751
+ if (!trackedTeamNames.has(teamName)) {
752
+ void api.teams.setChangePresenceTracking(teamName, true).catch(() => undefined);
753
+ }
754
+ }
755
+
756
+ for (const teamName of trackedTeamNames) {
757
+ if (!nextTrackedTeamNames.has(teamName)) {
758
+ void api.teams.setChangePresenceTracking(teamName, false).catch(() => undefined);
759
+ }
760
+ }
761
+
762
+ trackedTeamNames = nextTrackedTeamNames;
763
+ };
764
+
765
+ syncVisibleTeamTracking();
766
+
767
+ const unsubscribeVisibleTeamTracking = useStore.subscribe((state, prevState) => {
768
+ if (
769
+ state.paneLayout === prevState.paneLayout &&
770
+ state.selectedTeamName === prevState.selectedTeamName &&
771
+ state.selectedTeamData === prevState.selectedTeamData &&
772
+ state.teamDataCacheByName === prevState.teamDataCacheByName
773
+ ) {
774
+ return;
775
+ }
776
+ syncVisibleTeamTracking();
777
+ });
778
+
779
+ cleanupFns.push(() => {
780
+ unsubscribeVisibleTeamTracking();
781
+ for (const teamName of trackedTeamNames) {
782
+ void api.teams.setChangePresenceTracking(teamName, false).catch(() => undefined);
783
+ }
784
+ trackedTeamNames.clear();
785
+ });
786
+ }
787
+
788
+ if (api.teams?.setToolActivityTracking) {
789
+ let trackedTeamNames = new Set<string>();
790
+ const syncVisibleTeamTracking = (): void => {
791
+ const nextTrackedTeamNames = getTrackedToolActivityTeams();
792
+
793
+ for (const teamName of nextTrackedTeamNames) {
794
+ if (!trackedTeamNames.has(teamName)) {
795
+ void api.teams.setToolActivityTracking(teamName, true).catch(() => undefined);
796
+ }
797
+ }
798
+
799
+ for (const teamName of trackedTeamNames) {
800
+ if (!nextTrackedTeamNames.has(teamName)) {
801
+ void api.teams.setToolActivityTracking(teamName, false).catch(() => undefined);
802
+ }
803
+ }
804
+
805
+ trackedTeamNames = nextTrackedTeamNames;
806
+ };
807
+
808
+ syncVisibleTeamTracking();
809
+
810
+ const unsubscribeVisibleTeamTracking = useStore.subscribe((state, prevState) => {
811
+ if (state.paneLayout === prevState.paneLayout) {
812
+ return;
813
+ }
814
+ syncVisibleTeamTracking();
815
+ });
816
+
817
+ cleanupFns.push(() => {
818
+ unsubscribeVisibleTeamTracking();
819
+ for (const teamName of trackedTeamNames) {
820
+ void api.teams.setToolActivityTracking(teamName, false).catch(() => undefined);
821
+ }
822
+ trackedTeamNames.clear();
823
+ });
824
+ }
825
+
826
+ // Listen for task-list file changes to refresh currently viewed session metadata
827
+ if (api.onTodoChange) {
828
+ const cleanup = api.onTodoChange((event) => {
829
+ if (!event.sessionId || event.type === 'unlink') {
830
+ return;
831
+ }
832
+
833
+ const state = useStore.getState();
834
+ const isViewingSession =
835
+ state.selectedSessionId === event.sessionId || isSessionVisibleInAnyPane(event.sessionId);
836
+
837
+ if (isViewingSession) {
838
+ // Find the project ID from any pane's tab that shows this session
839
+ const allTabs = state.getAllPaneTabs();
840
+ const sessionTab = allTabs.find(
841
+ (t) => t.type === 'session' && t.sessionId === event.sessionId
842
+ );
843
+ if (sessionTab?.projectId) {
844
+ scheduleSessionRefresh(sessionTab.projectId, event.sessionId);
845
+ }
846
+ }
847
+
848
+ // Refresh project sessions list if applicable
849
+ const activeTab = state.getActiveTab();
850
+ const activeProjectId =
851
+ activeTab?.type === 'session' && typeof activeTab.projectId === 'string'
852
+ ? activeTab.projectId
853
+ : null;
854
+ if (activeProjectId && activeProjectId === state.selectedProjectId) {
855
+ scheduleProjectRefresh(activeProjectId);
856
+ }
857
+ });
858
+ if (typeof cleanup === 'function') {
859
+ cleanupFns.push(cleanup);
860
+ }
861
+ }
862
+
863
+ // Listen for file changes to auto-refresh current session and detect new sessions
864
+ if (api.onFileChange) {
865
+ const cleanup = api.onFileChange((event) => {
866
+ // Skip unlink events
867
+ if (event.type === 'unlink') {
868
+ return;
869
+ }
870
+
871
+ const state = useStore.getState();
872
+ const selectedProjectId = state.selectedProjectId;
873
+ const selectedProjectBaseId = getBaseProjectId(selectedProjectId);
874
+ const eventProjectBaseId = getBaseProjectId(event.projectId);
875
+ const matchesSelectedProject =
876
+ !!selectedProjectId &&
877
+ (eventProjectBaseId == null || selectedProjectBaseId === eventProjectBaseId);
878
+ const isTopLevelSessionEvent = !event.isSubagent;
879
+ const isUnknownSessionInSidebar =
880
+ event.sessionId == null ||
881
+ !state.sessions.some((session) => session.id === event.sessionId);
882
+ const shouldRefreshForPotentialNewSession =
883
+ isTopLevelSessionEvent &&
884
+ matchesSelectedProject &&
885
+ isUnknownSessionInSidebar &&
886
+ (event.type === 'add' || (state.connectionMode === 'local' && event.type === 'change'));
887
+
888
+ // Refresh sidebar session list only when a truly new top-level session appears.
889
+ // Local fs.watch can report "change" before/without "add" for newly created files.
890
+ if (shouldRefreshForPotentialNewSession) {
891
+ if (matchesSelectedProject && selectedProjectId) {
892
+ scheduleProjectRefresh(selectedProjectId);
893
+ }
894
+ }
895
+
896
+ // Keep opened session view in sync on content changes.
897
+ // Some local writers emit rename/add for in-place updates, so include "add".
898
+ if ((event.type === 'change' || event.type === 'add') && selectedProjectId) {
899
+ const activeSessionId = state.selectedSessionId;
900
+ const eventSessionId = event.sessionId;
901
+ const isViewingEventSession =
902
+ !!eventSessionId &&
903
+ (activeSessionId === eventSessionId || isSessionVisibleInAnyPane(eventSessionId));
904
+ const shouldFallbackRefreshActiveSession =
905
+ matchesSelectedProject && !eventSessionId && !!activeSessionId;
906
+ const sessionIdToRefresh =
907
+ (isViewingEventSession ? eventSessionId : null) ??
908
+ (shouldFallbackRefreshActiveSession ? activeSessionId : null);
909
+
910
+ if (sessionIdToRefresh) {
911
+ const allTabs = state.getAllPaneTabs();
912
+ const visibleSessionTab = allTabs.find(
913
+ (tab) => tab.type === 'session' && tab.sessionId === sessionIdToRefresh
914
+ );
915
+ const refreshProjectId = visibleSessionTab?.projectId ?? selectedProjectId;
916
+
917
+ // Use refreshSessionInPlace to avoid flickering and preserve UI state
918
+ scheduleSessionRefresh(refreshProjectId, sessionIdToRefresh);
919
+ }
920
+ }
921
+ });
922
+ if (typeof cleanup === 'function') {
923
+ cleanupFns.push(cleanup);
924
+ }
925
+ }
926
+
927
+ const teamIdleWatchdogTimer = setInterval(() => {
928
+ void pollFocusedVisibleTeamIdleWatchdog();
929
+ }, TEAM_VISIBLE_IDLE_WATCHDOG_POLL_MS);
930
+ cleanupFns.push(() => {
931
+ clearInterval(teamIdleWatchdogTimer);
932
+ });
933
+ const teamMessageFallbackPollTimer = setInterval(() => {
934
+ void pollTrackedTeamMessageFallback();
935
+ }, TEAM_MESSAGE_FALLBACK_POLL_MS);
936
+ cleanupFns.push(() => {
937
+ clearInterval(teamMessageFallbackPollTimer);
938
+ });
939
+
940
+ if (api.teams?.onTeamChange) {
941
+ const cleanup = api.teams.onTeamChange((_event: unknown, event: TeamChangeEvent) => {
942
+ const messageRefreshRelevant =
943
+ Boolean(event.teamName) && shouldRefreshTeamMessages(event.teamName);
944
+ noteTeamChangeEventBurst(event.teamName, event.type, messageRefreshRelevant);
945
+
946
+ const isIgnoredRuntimeRun = (() => {
947
+ if (!event.runId) return false;
948
+ const state = useStore.getState();
949
+ return (
950
+ state.ignoredProvisioningRunIds[event.runId] === event.teamName ||
951
+ state.ignoredRuntimeRunIds[event.runId] === event.teamName
952
+ );
953
+ })();
954
+ if (isIgnoredRuntimeRun) {
955
+ return;
956
+ }
957
+
958
+ const isStaleRuntimeEvent = (() => {
959
+ if (!event.runId) return false;
960
+ const currentRunId = useStore.getState().currentRuntimeRunIdByTeam[event.teamName];
961
+ return currentRunId != null && currentRunId !== event.runId;
962
+ })();
963
+
964
+ const seedCurrentRunIdIfMissing = (): void => {
965
+ if (!event.runId) return;
966
+ const currentRunId = useStore.getState().currentRuntimeRunIdByTeam[event.teamName];
967
+ if (currentRunId == null) {
968
+ useStore.setState((prev) => ({
969
+ currentRuntimeRunIdByTeam: {
970
+ ...prev.currentRuntimeRunIdByTeam,
971
+ [event.teamName]: event.runId ?? null,
972
+ },
973
+ ignoredRuntimeRunIds: Object.fromEntries(
974
+ Object.entries(prev.ignoredRuntimeRunIds).filter(
975
+ ([, teamName]) => teamName !== event.teamName
976
+ )
977
+ ),
978
+ }));
979
+ }
980
+ };
981
+
982
+ if (RELEVANT_TEAM_CHANGE_EVENT_TYPES.has(event.type) && !isStaleRuntimeEvent) {
983
+ noteRelevantTeamActivity(event.teamName);
984
+ }
985
+
986
+ // Immediate in-memory update for lead activity — no filesystem refresh needed
987
+ if (event.type === 'lead-activity' && event.detail) {
988
+ if (isStaleRuntimeEvent) {
989
+ return;
990
+ }
991
+ seedCurrentRunIdIfMissing();
992
+ const nextActivity = event.detail as 'active' | 'idle' | 'offline';
993
+ useStore.setState((prev) => {
994
+ const nextState: Partial<typeof prev> = {
995
+ leadActivityByTeam: {
996
+ ...prev.leadActivityByTeam,
997
+ [event.teamName]: nextActivity,
998
+ },
999
+ };
1000
+
1001
+ const baseTeamData =
1002
+ prev.teamDataCacheByName[event.teamName] ??
1003
+ (prev.selectedTeamName === event.teamName ? prev.selectedTeamData : null);
1004
+ const nextTeamData =
1005
+ baseTeamData && baseTeamData.isAlive !== (nextActivity !== 'offline')
1006
+ ? {
1007
+ ...baseTeamData,
1008
+ isAlive: nextActivity !== 'offline',
1009
+ }
1010
+ : baseTeamData;
1011
+
1012
+ if (nextTeamData) {
1013
+ nextState.teamDataCacheByName = {
1014
+ ...prev.teamDataCacheByName,
1015
+ [event.teamName]: nextTeamData,
1016
+ };
1017
+ }
1018
+
1019
+ if (prev.selectedTeamName === event.teamName && nextTeamData) {
1020
+ nextState.selectedTeamData = nextTeamData;
1021
+ }
1022
+
1023
+ // Clear context data when lead goes offline
1024
+ if (nextActivity === 'offline') {
1025
+ nextState.leadContextByTeam = { ...prev.leadContextByTeam };
1026
+ delete nextState.leadContextByTeam[event.teamName];
1027
+ Object.assign(nextState, clearRuntimeToolStateForTeam(prev, event.teamName));
1028
+ nextState.currentRuntimeRunIdByTeam = { ...prev.currentRuntimeRunIdByTeam };
1029
+ delete nextState.currentRuntimeRunIdByTeam[event.teamName];
1030
+ nextState.ignoredRuntimeRunIds = event.runId
1031
+ ? {
1032
+ ...prev.ignoredRuntimeRunIds,
1033
+ [event.runId]: event.teamName,
1034
+ }
1035
+ : prev.ignoredRuntimeRunIds;
1036
+ clearToolActivityTimersForTeam(event.teamName);
1037
+ }
1038
+
1039
+ return nextState as typeof prev;
1040
+ });
1041
+ return;
1042
+ }
1043
+
1044
+ // Immediate in-memory update for lead context usage — no filesystem refresh needed
1045
+ if (event.type === 'lead-context' && event.detail) {
1046
+ if (isStaleRuntimeEvent) {
1047
+ return;
1048
+ }
1049
+ seedCurrentRunIdIfMissing();
1050
+ try {
1051
+ const ctx = JSON.parse(event.detail) as LeadContextUsage;
1052
+ useStore.setState((prev) => ({
1053
+ ...prev,
1054
+ leadContextByTeam: { ...prev.leadContextByTeam, [event.teamName]: ctx },
1055
+ }));
1056
+ } catch {
1057
+ /* ignore malformed detail */
1058
+ }
1059
+ return;
1060
+ }
1061
+
1062
+ if (event.type === 'tool-activity' && event.detail) {
1063
+ if (isStaleRuntimeEvent) {
1064
+ return;
1065
+ }
1066
+ seedCurrentRunIdIfMissing();
1067
+ try {
1068
+ const payload = JSON.parse(event.detail) as ToolActivityEventPayload;
1069
+ if (payload.action === 'start' && payload.activity) {
1070
+ const activity: ActiveToolCall = {
1071
+ memberName: payload.activity.memberName,
1072
+ toolUseId: payload.activity.toolUseId,
1073
+ toolName: payload.activity.toolName,
1074
+ preview: payload.activity.preview,
1075
+ startedAt: payload.activity.startedAt,
1076
+ source: payload.activity.source,
1077
+ state: 'running',
1078
+ };
1079
+
1080
+ useStore.setState((prev) => ({
1081
+ activeToolsByTeam: {
1082
+ ...prev.activeToolsByTeam,
1083
+ [event.teamName]: upsertMemberToolEntry(
1084
+ prev.activeToolsByTeam[event.teamName],
1085
+ activity
1086
+ ),
1087
+ },
1088
+ }));
1089
+ } else if (payload.action === 'finish' && payload.memberName && payload.toolUseId) {
1090
+ const memberName = payload.memberName;
1091
+ const toolUseId = payload.toolUseId;
1092
+ useStore.setState((prev) => {
1093
+ const current = prev.activeToolsByTeam[event.teamName]?.[memberName]?.[toolUseId];
1094
+ if (!current) {
1095
+ return {};
1096
+ }
1097
+
1098
+ const completed: ActiveToolCall = {
1099
+ ...current,
1100
+ state: payload.isError ? 'error' : 'complete',
1101
+ finishedAt: payload.finishedAt ?? new Date().toISOString(),
1102
+ resultPreview: payload.resultPreview,
1103
+ };
1104
+
1105
+ scheduleToolActivityTimer(
1106
+ event.teamName,
1107
+ memberName,
1108
+ toolUseId,
1109
+ 'fade',
1110
+ FINISHED_TOOL_DISPLAY_MS,
1111
+ () => {
1112
+ useStore.setState((state) => {
1113
+ const nextCurrent =
1114
+ state.finishedVisibleByTeam[event.teamName]?.[memberName]?.[toolUseId];
1115
+ if (!nextCurrent) {
1116
+ return {};
1117
+ }
1118
+ return {
1119
+ finishedVisibleByTeam: {
1120
+ ...state.finishedVisibleByTeam,
1121
+ [event.teamName]: removeMemberToolEntry(
1122
+ state.finishedVisibleByTeam[event.teamName],
1123
+ memberName,
1124
+ toolUseId
1125
+ ),
1126
+ },
1127
+ };
1128
+ });
1129
+ }
1130
+ );
1131
+
1132
+ return {
1133
+ activeToolsByTeam: {
1134
+ ...prev.activeToolsByTeam,
1135
+ [event.teamName]: removeMemberToolEntry(
1136
+ prev.activeToolsByTeam[event.teamName],
1137
+ memberName,
1138
+ toolUseId
1139
+ ),
1140
+ },
1141
+ finishedVisibleByTeam: {
1142
+ ...prev.finishedVisibleByTeam,
1143
+ [event.teamName]: upsertMemberToolEntry(
1144
+ prev.finishedVisibleByTeam[event.teamName],
1145
+ completed
1146
+ ),
1147
+ },
1148
+ toolHistoryByTeam: pushToolHistoryEntry(
1149
+ prev.toolHistoryByTeam,
1150
+ event.teamName,
1151
+ completed
1152
+ ),
1153
+ };
1154
+ });
1155
+ } else if (payload.action === 'reset') {
1156
+ if (payload.memberName) {
1157
+ const memberName = payload.memberName;
1158
+ const toolUseIds =
1159
+ Array.isArray(payload.toolUseIds) && payload.toolUseIds.length > 0
1160
+ ? payload.toolUseIds
1161
+ : null;
1162
+ useStore.setState((prev) => {
1163
+ if (!prev.activeToolsByTeam[event.teamName]?.[memberName]) {
1164
+ return {};
1165
+ }
1166
+ return {
1167
+ activeToolsByTeam: {
1168
+ ...prev.activeToolsByTeam,
1169
+ [event.teamName]: toolUseIds
1170
+ ? removeMemberToolEntries(
1171
+ prev.activeToolsByTeam[event.teamName],
1172
+ memberName,
1173
+ toolUseIds
1174
+ )
1175
+ : removeMemberToolGroup(prev.activeToolsByTeam[event.teamName], memberName),
1176
+ },
1177
+ };
1178
+ });
1179
+ } else {
1180
+ useStore.setState((prev) => ({
1181
+ activeToolsByTeam: { ...prev.activeToolsByTeam, [event.teamName]: {} },
1182
+ }));
1183
+ }
1184
+ }
1185
+ } catch {
1186
+ /* ignore malformed detail */
1187
+ }
1188
+ return;
1189
+ }
1190
+
1191
+ // Member spawn status change: fetch updated spawn statuses for the team.
1192
+ if (event.type === 'member-spawn') {
1193
+ if (isStaleRuntimeEvent) {
1194
+ return;
1195
+ }
1196
+ seedCurrentRunIdIfMissing();
1197
+ scheduleMemberSpawnStatusesRefresh(event.teamName);
1198
+ scheduleTeamAgentRuntimeRefresh(event.teamName);
1199
+ return;
1200
+ }
1201
+
1202
+ if (event.type === 'inbox') {
1203
+ scheduleTrackedTeamMessageRefresh(event.teamName);
1204
+ return;
1205
+ }
1206
+
1207
+ // Live lead-message events refresh only the tracked message feed surface
1208
+ // (visible team or local pending-reply wait), not the structural snapshot.
1209
+ if (event.type === 'lead-message') {
1210
+ if (isStaleRuntimeEvent) {
1211
+ return;
1212
+ }
1213
+ seedCurrentRunIdIfMissing();
1214
+ scheduleTrackedTeamMessageRefresh(event.teamName);
1215
+ return;
1216
+ }
1217
+
1218
+ if (event.type === 'log-source-change') {
1219
+ if (!event?.teamName || !isTeamVisibleInAnyPane(event.teamName)) {
1220
+ return;
1221
+ }
1222
+ if (teamPresenceRefreshTimers.has(event.teamName)) {
1223
+ return;
1224
+ }
1225
+ const timer = setTimeout(() => {
1226
+ teamPresenceRefreshTimers.delete(event.teamName);
1227
+ const current = useStore.getState();
1228
+ void current.refreshTeamChangePresence(event.teamName);
1229
+ }, TEAM_PRESENCE_REFRESH_THROTTLE_MS);
1230
+ teamPresenceRefreshTimers.set(event.teamName, timer);
1231
+ return;
1232
+ }
1233
+
1234
+ // Throttled refresh of summary list (keeps TeamListView current without flooding).
1235
+ if (!teamListRefreshTimer) {
1236
+ teamListRefreshTimer = setTimeout(() => {
1237
+ teamListRefreshTimer = null;
1238
+ void useStore.getState().fetchTeams();
1239
+ }, TEAM_LIST_REFRESH_THROTTLE_MS);
1240
+ }
1241
+
1242
+ const shouldRefreshGlobalTasks = event.type === 'task' || event.type === 'config';
1243
+
1244
+ // Throttled refresh of global tasks list for sidebar.
1245
+ if (shouldRefreshGlobalTasks && !globalTasksRefreshTimer) {
1246
+ globalTasksRefreshTimer = setTimeout(() => {
1247
+ globalTasksRefreshTimer = null;
1248
+ void useStore.getState().fetchAllTasks();
1249
+ }, GLOBAL_TASKS_REFRESH_THROTTLE_MS);
1250
+ }
1251
+
1252
+ if (!event?.teamName || !isTeamVisibleInAnyPane(event.teamName)) {
1253
+ return;
1254
+ }
1255
+
1256
+ // Per-team throttle (not debounce): keep at most one pending detail refresh per team.
1257
+ // Debounce would delay indefinitely while inbox messages keep arriving.
1258
+ if (teamRefreshTimers.has(event.teamName)) {
1259
+ return;
1260
+ }
1261
+
1262
+ const timer = setTimeout(() => {
1263
+ teamRefreshTimers.delete(event.teamName);
1264
+ const current = useStore.getState();
1265
+ void current.refreshTeamData(event.teamName, { withDedup: true });
1266
+ }, TEAM_REFRESH_THROTTLE_MS);
1267
+ teamRefreshTimers.set(event.teamName, timer);
1268
+ });
1269
+
1270
+ if (typeof cleanup === 'function') {
1271
+ cleanupFns.push(() => {
1272
+ cleanup();
1273
+ for (const t of teamRefreshTimers.values()) clearTimeout(t);
1274
+ teamRefreshTimers = new Map();
1275
+ for (const t of teamMessageRefreshTimers.values()) clearTimeout(t);
1276
+ teamMessageRefreshTimers = new Map();
1277
+ for (const t of teamPresenceRefreshTimers.values()) clearTimeout(t);
1278
+ teamPresenceRefreshTimers = new Map();
1279
+ for (const t of memberSpawnRefreshTimers.values()) clearTimeout(t);
1280
+ memberSpawnRefreshTimers = new Map();
1281
+ for (const t of teamAgentRuntimeRefreshTimers.values()) clearTimeout(t);
1282
+ teamAgentRuntimeRefreshTimers = new Map();
1283
+ for (const t of toolActivityTimers.values()) clearTimeout(t);
1284
+ toolActivityTimers = new Map();
1285
+ teamLastRelevantActivityAt.clear();
1286
+ teamLastIdleWatchdogRefreshAt.clear();
1287
+ if (teamListRefreshTimer) {
1288
+ clearTimeout(teamListRefreshTimer);
1289
+ teamListRefreshTimer = null;
1290
+ }
1291
+ if (globalTasksRefreshTimer) {
1292
+ clearTimeout(globalTasksRefreshTimer);
1293
+ globalTasksRefreshTimer = null;
1294
+ }
1295
+ });
1296
+ }
1297
+ }
1298
+
1299
+ if (api.teams?.onProjectBranchChange) {
1300
+ const cleanup = api.teams.onProjectBranchChange((_event: unknown, event) => {
1301
+ if (!event?.projectPath) return;
1302
+ const normalizedPath = normalizePath(event.projectPath);
1303
+ if (!normalizedPath) return;
1304
+ useStore.setState((prev) => {
1305
+ const current = prev.branchByPath[normalizedPath];
1306
+ if (current === event.branch) {
1307
+ return {};
1308
+ }
1309
+ return {
1310
+ branchByPath: {
1311
+ ...prev.branchByPath,
1312
+ [normalizedPath]: event.branch,
1313
+ },
1314
+ };
1315
+ });
1316
+ });
1317
+ if (typeof cleanup === 'function') {
1318
+ cleanupFns.push(cleanup);
1319
+ }
1320
+ }
1321
+
1322
+ // Tool approval events from CLI control_request protocol
1323
+ if (api.teams?.onToolApprovalEvent) {
1324
+ const cleanup = api.teams.onToolApprovalEvent((_event: unknown, data: unknown) => {
1325
+ const event = data as ToolApprovalEvent;
1326
+ if ('autoResolved' in event && event.autoResolved) {
1327
+ // Timeout or auto-allow resolved in main — remove from UI and record result
1328
+ const allowed = event.reason !== 'timeout_deny';
1329
+ useStore.setState((s) => {
1330
+ const next = new Map(s.resolvedApprovals);
1331
+ next.set(event.requestId, allowed);
1332
+ return {
1333
+ pendingApprovals: s.pendingApprovals.filter(
1334
+ (a) => !(a.runId === event.runId && a.requestId === event.requestId)
1335
+ ),
1336
+ resolvedApprovals: next,
1337
+ };
1338
+ });
1339
+ } else if ('dismissed' in event && event.dismissed) {
1340
+ const dismiss = event;
1341
+ useStore.setState((s) => ({
1342
+ pendingApprovals: s.pendingApprovals.filter(
1343
+ (a) => !(a.teamName === dismiss.teamName && a.runId === dismiss.runId)
1344
+ ),
1345
+ }));
1346
+ } else {
1347
+ const request = event as ToolApprovalRequest;
1348
+ useStore.setState((s) => ({
1349
+ pendingApprovals: [...s.pendingApprovals, request],
1350
+ }));
1351
+ }
1352
+ });
1353
+ if (typeof cleanup === 'function') {
1354
+ cleanupFns.push(cleanup);
1355
+ }
1356
+
1357
+ // Sync saved tool approval settings to main process on startup
1358
+ const savedSettings = useStore.getState().toolApprovalSettings;
1359
+ const activeTeam = useStore.getState().selectedTeamName ?? '__global__';
1360
+ api.teams.updateToolApprovalSettings?.(activeTeam, savedSettings).catch(() => {
1361
+ // Silently ignore — settings will use defaults until next update
1362
+ });
1363
+ }
1364
+
1365
+ // Listen for editor file change events (chokidar watcher → renderer)
1366
+ if (api.editor?.onEditorChange) {
1367
+ const cleanup = api.editor.onEditorChange((event) => {
1368
+ const state = useStore.getState();
1369
+ if (state.editorProjectPath) {
1370
+ state.handleExternalFileChange(event);
1371
+ }
1372
+ });
1373
+ if (typeof cleanup === 'function') {
1374
+ cleanupFns.push(cleanup);
1375
+ }
1376
+ }
1377
+
1378
+ // Listen for schedule change events from main process
1379
+ if (api.schedules?.onScheduleChange) {
1380
+ const cleanup = api.schedules.onScheduleChange((_event: unknown, data: unknown) => {
1381
+ const event = data as ScheduleChangeEvent;
1382
+ if (event?.scheduleId) {
1383
+ void useStore.getState().applyScheduleChange(event.scheduleId);
1384
+ }
1385
+ });
1386
+ if (typeof cleanup === 'function') {
1387
+ cleanupFns.push(cleanup);
1388
+ }
1389
+ }
1390
+
1391
+ // fetchCliStatus() is deferred 5s after app start (heavy on Windows).
1392
+
1393
+ // Listen for CLI installer progress events from main process
1394
+ let cliCompletedRevertTimer: ReturnType<typeof setTimeout> | null = null;
1395
+ if (api.cliInstaller?.onProgress) {
1396
+ const cleanup = api.cliInstaller.onProgress((_event: unknown, data: unknown) => {
1397
+ const progress = data as CliInstallerProgress;
1398
+
1399
+ // Clear any pending auto-revert timer on new events
1400
+ if (progress.type !== 'completed' && cliCompletedRevertTimer) {
1401
+ clearTimeout(cliCompletedRevertTimer);
1402
+ cliCompletedRevertTimer = null;
1403
+ }
1404
+
1405
+ const detail = progress.detail ?? null;
1406
+
1407
+ switch (progress.type) {
1408
+ case 'checking':
1409
+ useStore.setState({ cliInstallerState: 'checking', cliInstallerDetail: detail });
1410
+ break;
1411
+ case 'downloading':
1412
+ useStore.setState({
1413
+ cliInstallerState: 'downloading',
1414
+ cliDownloadProgress: progress.percent ?? 0,
1415
+ cliDownloadTransferred: progress.transferred ?? 0,
1416
+ cliDownloadTotal: progress.total ?? 0,
1417
+ cliInstallerDetail: detail,
1418
+ });
1419
+ break;
1420
+ case 'verifying':
1421
+ useStore.setState({ cliInstallerState: 'verifying', cliInstallerDetail: detail });
1422
+ break;
1423
+ case 'installing': {
1424
+ // Accumulate log lines and raw chunks for xterm.js rendering
1425
+ const prevLogs = useStore.getState().cliInstallerLogs;
1426
+ const prevRaw = useStore.getState().cliInstallerRawChunks;
1427
+ const newLogs = detail ? [...prevLogs, detail].slice(-50) : prevLogs;
1428
+ const newRaw = progress.rawChunk ? [...prevRaw, progress.rawChunk].slice(-200) : prevRaw;
1429
+ useStore.setState({
1430
+ cliInstallerState: 'installing',
1431
+ cliInstallerDetail: detail,
1432
+ cliInstallerLogs: newLogs,
1433
+ cliInstallerRawChunks: newRaw,
1434
+ });
1435
+ break;
1436
+ }
1437
+ case 'completed':
1438
+ {
1439
+ const multimodelEnabled =
1440
+ useStore.getState().appConfig?.general?.multimodelEnabled ?? false;
1441
+ void refreshCliStatusForCurrentMode({
1442
+ multimodelEnabled,
1443
+ bootstrapCliStatus: useStore.getState().bootstrapCliStatus,
1444
+ fetchCliStatus: useStore.getState().fetchCliStatus,
1445
+ });
1446
+ }
1447
+ useStore.setState({
1448
+ cliInstallerState: 'completed',
1449
+ cliCompletedVersion: progress.version ?? null,
1450
+ cliInstallerDetail: null,
1451
+ });
1452
+ // Re-fetch status after install and auto-revert to idle after 3s
1453
+ cliCompletedRevertTimer = setTimeout(() => {
1454
+ cliCompletedRevertTimer = null;
1455
+ // Only revert if still in 'completed' state (not overwritten by a new install)
1456
+ if (useStore.getState().cliInstallerState === 'completed') {
1457
+ useStore.setState({ cliInstallerState: 'idle' });
1458
+ }
1459
+ }, 3000);
1460
+ break;
1461
+ case 'error':
1462
+ useStore.setState({
1463
+ cliInstallerState: 'error',
1464
+ cliInstallerError: progress.error ?? 'Unknown error',
1465
+ });
1466
+ break;
1467
+ case 'status':
1468
+ if (progress.status) {
1469
+ let modelOnlyFallbackProviderIds: CliProviderId[] = [];
1470
+ useStore.setState((state) => {
1471
+ const nextStatus = mergeCliStatusPreservingHydratedProviders(
1472
+ state.cliStatus,
1473
+ progress.status!
1474
+ );
1475
+ const incompleteProviderIds = getIncompleteMultimodelProviderIds(nextStatus);
1476
+ modelOnlyFallbackProviderIds = getModelOnlyFallbackProviderIds(nextStatus);
1477
+
1478
+ return {
1479
+ cliStatus: nextStatus,
1480
+ cliProviderStatusLoading:
1481
+ incompleteProviderIds.length > 0
1482
+ ? {
1483
+ ...state.cliProviderStatusLoading,
1484
+ ...Object.fromEntries(
1485
+ incompleteProviderIds.map((providerId) => [providerId, true])
1486
+ ),
1487
+ }
1488
+ : state.cliProviderStatusLoading,
1489
+ };
1490
+ });
1491
+ for (const providerId of modelOnlyFallbackProviderIds) {
1492
+ void useStore.getState().fetchCliProviderStatus(providerId, { silent: false });
1493
+ }
1494
+ }
1495
+ break;
1496
+ }
1497
+ });
1498
+ if (typeof cleanup === 'function') {
1499
+ cleanupFns.push(() => {
1500
+ cleanup();
1501
+ if (cliCompletedRevertTimer) {
1502
+ clearTimeout(cliCompletedRevertTimer);
1503
+ cliCompletedRevertTimer = null;
1504
+ }
1505
+ });
1506
+ }
1507
+ }
1508
+
1509
+ // Listen for SSH connection status changes from main process
1510
+ // NOTE: Only syncs connection status here. Data fetching is handled by
1511
+ // connectionSlice.connectSsh/disconnectSsh and contextSlice.switchContext.
1512
+ if (api.ssh?.onStatus) {
1513
+ const cleanup = api.ssh.onStatus((_event: unknown, status: unknown) => {
1514
+ const s = status as { state: string; host: string | null; error: string | null };
1515
+ useStore
1516
+ .getState()
1517
+ .setConnectionStatus(
1518
+ s.state as 'disconnected' | 'connecting' | 'connected' | 'error',
1519
+ s.host,
1520
+ s.error
1521
+ );
1522
+ });
1523
+ if (typeof cleanup === 'function') {
1524
+ cleanupFns.push(cleanup);
1525
+ }
1526
+ }
1527
+
1528
+ // Listen for context changes from main process (e.g., SSH disconnect)
1529
+ if (api.context?.onChanged) {
1530
+ const cleanup = api.context.onChanged((_event: unknown, data: unknown) => {
1531
+ const { id } = data as { id: string; type: string };
1532
+ const currentContextId = useStore.getState().activeContextId;
1533
+ if (id !== currentContextId) {
1534
+ // Main process switched context externally (e.g., SSH disconnect)
1535
+ // Trigger renderer-side context switch to sync state
1536
+ void useStore.getState().switchContext(id);
1537
+ }
1538
+ });
1539
+ if (typeof cleanup === 'function') {
1540
+ cleanupFns.push(cleanup);
1541
+ }
1542
+ }
1543
+
1544
+ // Return cleanup function
1545
+ return () => {
1546
+ for (const timer of pendingSessionRefreshTimers.values()) {
1547
+ clearTimeout(timer);
1548
+ }
1549
+ pendingSessionRefreshTimers.clear();
1550
+ for (const timer of pendingProjectRefreshTimers.values()) {
1551
+ clearTimeout(timer);
1552
+ }
1553
+ pendingProjectRefreshTimers.clear();
1554
+ cleanupFns.forEach((fn) => fn());
1555
+ };
1556
+ }