@openscout/scout 0.2.92 → 0.2.94

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 (507) hide show
  1. package/README.md +22 -28
  2. package/bin/scoutd +0 -0
  3. package/dist/build-manifest.json +3 -3
  4. package/dist/client/apple-touch-icon.png +0 -0
  5. package/dist/client/assets/ActivityScreen--eANwuxa.js +1 -0
  6. package/dist/client/assets/{AddProjectForm-CpyytDf2.js → AddProjectForm-CcD6qvV8.js} +1 -1
  7. package/dist/client/assets/AgentAvatar-CYhf6twS.js +1 -0
  8. package/dist/client/assets/AgentConfigurationScreen-BTI24HQX.js +1 -0
  9. package/dist/client/assets/AgentDefinitionsWorkspace-srmN6-vj.js +1 -0
  10. package/dist/client/assets/{AgentDetailCard-BTiOmh-a.js → AgentDetailCard-UqPNpcvB.js} +1 -1
  11. package/dist/client/assets/AgentFloorView-XXNgI5Cj.js +1 -0
  12. package/dist/client/assets/AgentInfoScreen-CimdOnZ9.js +1 -0
  13. package/dist/client/assets/{AgentLaneCard-lfRNb7JD.js → AgentLaneCard-Z-aOBR3W.js} +1 -1
  14. package/dist/client/assets/{AgentLaneChrome-Dlwrbq3g.js → AgentLaneChrome-CyhA1reW.js} +1 -1
  15. package/dist/client/assets/AgentLaneDetailSheet-BNzjMjIH.js +4 -0
  16. package/dist/client/assets/{AgentLaneSummaryResize-6SOEWUnr.js → AgentLaneSummaryResize-Box8-_rS.js} +1 -1
  17. package/dist/client/assets/AgentLanesEmbedScreen-BmLnN4on.js +1 -0
  18. package/dist/client/assets/{AgentLanesPreflight-C3uOiOzd.js → AgentLanesPreflight-5B6sXvRB.js} +1 -1
  19. package/dist/client/assets/AgentLanesView-DHyzVBk6.js +2 -0
  20. package/dist/client/assets/{AgentLiveActions-BJ5dIfL3.js → AgentLiveActions-BwuzOE8h.js} +1 -1
  21. package/dist/client/assets/AgentSessions-CsZwoukw.js +6 -0
  22. package/dist/client/assets/AgentsConsole-KCao4XmX.js +1 -0
  23. package/dist/client/assets/AgentsScreen-CtPAmwRX.js +1 -0
  24. package/dist/client/assets/AgentsSubnav-CDMjKeYC.js +1 -0
  25. package/dist/client/assets/AstronautSuit-Ckx7lu7G.js +1 -0
  26. package/dist/client/assets/AtopView-DYlpgEHf.js +1 -0
  27. package/dist/client/assets/{BackToPicker-D1LV6Cqp.js → BackToPicker-4JaeRvDm.js} +1 -1
  28. package/dist/client/assets/BriefingDetailScreen-D6-xqrpo.js +1 -0
  29. package/dist/client/assets/BriefingsScreen-DKxSDEmk.js +1 -0
  30. package/dist/client/assets/{BrokerMetadataPanel-BhjECqOK.js → BrokerMetadataPanel-BbREmsbK.js} +1 -1
  31. package/dist/client/assets/BrokerScreen-fbPIouMw.js +5 -0
  32. package/dist/client/assets/CastPicker-BcA2vDDV.js +1 -0
  33. package/dist/client/assets/CastPicker-zXsnkTIy.css +1 -0
  34. package/dist/client/assets/ChatCollapsedStrip-Ycm0ecaX.js +1 -0
  35. package/dist/client/assets/{CodeDiffPane-Bx_2VAzv.js → CodeDiffPane-Cn8Y9hAt.js} +1 -1
  36. package/dist/client/assets/{CodeProjectPicker-C1yOJKvs.js → CodeProjectPicker-nPFktrco.js} +1 -1
  37. package/dist/client/assets/CodeScreen-BlAxtxE5.js +1 -0
  38. package/dist/client/assets/ConversationComposer-2HjbGPL9.js +1 -0
  39. package/dist/client/assets/ConversationFeedRows-C6wUqJrx.js +1 -0
  40. package/dist/client/assets/ConversationHeader-C8vfXaTF.js +1 -0
  41. package/dist/client/assets/ConversationPanels-CNCIbpqU.js +6 -0
  42. package/dist/client/assets/ConversationScreen-BNULZAp2.js +2 -0
  43. package/dist/client/assets/ConversationScreen-CkWnKXt6.css +1 -0
  44. package/dist/client/assets/ConversationStatus-DZuyKsWN.js +1 -0
  45. package/dist/client/assets/CrewAvatar-CTIuxp4G.js +1 -0
  46. package/dist/client/assets/CrewAvatar-D0c9z5Qr.css +1 -0
  47. package/dist/client/assets/CrewWorkspaces-CJhBKVoZ.css +1 -0
  48. package/dist/client/assets/CrewWorkspaces-CkPYIA46.js +1 -0
  49. package/dist/client/assets/{DataTable-CJbbgBdA.js → DataTable-6IDhanr5.js} +1 -1
  50. package/dist/client/assets/DispatchAftermath-DC1u9itO.js +1 -0
  51. package/dist/client/assets/DocumentFocusViewer-DZVhS7as.js +1 -0
  52. package/dist/client/assets/{EmbeddableSurfacesLab-BdsYRDky.js → EmbeddableSurfacesLab-BKUFJMCV.js} +1 -1
  53. package/dist/client/assets/{EmptyState-BRY5jTpz.js → EmptyState-CeBl0iGd.js} +1 -1
  54. package/dist/client/assets/{FileViewerPane-9Bveqm9c.js → FileViewerPane-DQlpNt2S.js} +2 -2
  55. package/dist/client/assets/FlightObserveScreen-CDWGSKZg.js +1 -0
  56. package/dist/client/assets/FollowScreen-BXHOp3gb.js +1 -0
  57. package/dist/client/assets/{HarnessMark-BPAphNjx.js → HarnessMark-D5CA5uSp.js} +1 -1
  58. package/dist/client/assets/HarnessesScreen-DhFXq1qz.js +1 -0
  59. package/dist/client/assets/{HerdrSession-BujfGzrP.js → HerdrSession-BRhs5LIR.js} +1 -1
  60. package/dist/client/assets/HomeHero-7JwycwFY.css +1 -0
  61. package/dist/client/assets/HomeHero-DMABJuze.js +1 -0
  62. package/dist/client/assets/HostAdvisorView-RAociATV.js +1 -0
  63. package/dist/client/assets/{KnowledgeSearchInspector-B4ZY24xE.js → KnowledgeSearchInspector-CZPyVNSw.js} +1 -1
  64. package/dist/client/assets/KnowledgeSearchScreen-mGTKIg00.js +1 -0
  65. package/dist/client/assets/{LaneToolHoverCard-B7KdvQvf.js → LaneToolHoverCard-D_DMlBeT.js} +1 -1
  66. package/dist/client/assets/LaneTraceDetailSheet-BEHg3LmH.js +1 -0
  67. package/dist/client/assets/{LaneTraceEventFocus-mkMw2wJU.js → LaneTraceEventFocus-DVimcizS.js} +1 -1
  68. package/dist/client/assets/{MeshCanvas-CpKcWxKy.js → MeshCanvas-BOuZx4AM.js} +2 -2
  69. package/dist/client/assets/{MeshCanvasMinimap-C9IoGHbe.js → MeshCanvasMinimap-wL-1N94e.js} +1 -1
  70. package/dist/client/assets/MeshScreen-DMY9Bmh5.js +1 -0
  71. package/dist/client/assets/{MeshTopologyView-DFzr0IZM.js → MeshTopologyView-DiDcX5f4.js} +2 -2
  72. package/dist/client/assets/MessagesScreen-Eulveud3.js +1 -0
  73. package/dist/client/assets/{MissionContextRail-Y8QxUZGE.js → MissionContextRail-DrNKXG5u.js} +1 -1
  74. package/dist/client/assets/MissionControlView-ByBlHVN8.js +1 -0
  75. package/dist/client/assets/MissionFocusOverlay-D1i6R6Zt.js +1 -0
  76. package/dist/client/assets/MissionLeftAgentRow-DN9NcCML.js +1 -0
  77. package/dist/client/assets/MissionLogPane-DSeIv3Xo.js +1 -0
  78. package/dist/client/assets/NewAgentModal-V7yK6J6j.js +1 -0
  79. package/dist/client/assets/NewChatComposer-hlWT-nbR.js +19 -0
  80. package/dist/client/assets/{NewChatOrigin-DmuJ32wa.js → NewChatOrigin-DdpzE4kz.js} +1 -1
  81. package/dist/client/assets/ObserveEmbedScreen-l_Q3ts2q.js +2 -0
  82. package/dist/client/assets/ObserveTextFlow-BSEtYTxU.js +2 -0
  83. package/dist/client/assets/ObservedTopologyPanel-CdGUXxGR.js +2 -0
  84. package/dist/client/assets/OpenScoutAppShell-DN8dOSK4.js +79 -0
  85. package/dist/client/assets/OpsAgentsView-ntGr4pz4.js +1 -0
  86. package/dist/client/assets/OpsScreen-Ppen_Lmj.js +1 -0
  87. package/dist/client/assets/OpsSubnav-GAKsoSor.js +1 -0
  88. package/dist/client/assets/ProjectAgentProfile-BLlp2e6t.js +1 -0
  89. package/dist/client/assets/{ProjectAgentProfileBar-BLVg5EeA.js → ProjectAgentProfileBar-BQET-qrY.js} +1 -1
  90. package/dist/client/assets/ProjectAgentProfileHero-Ck8mThtx.js +1 -0
  91. package/dist/client/assets/ProjectsInbox-Dlt8OQ8O.js +2 -0
  92. package/dist/client/assets/ProjectsRail-DCfNMmnW.js +1 -0
  93. package/dist/client/assets/ProjectsScreen-BP-hmI1m.js +1 -0
  94. package/dist/client/assets/ProjectsThreadAside-CWpMjGIH.js +1 -0
  95. package/dist/client/assets/Provider-B2xuo3rf.js +1 -0
  96. package/dist/client/assets/RailRow-B-GycCBx.js +1 -0
  97. package/dist/client/assets/RailRow-B0sRaJc6.css +1 -0
  98. package/dist/client/assets/RawSessionsTable-AQThi6sm.js +1 -0
  99. package/dist/client/assets/RealtimeVoiceScreen-D7zZHK_t.js +1 -0
  100. package/dist/client/assets/{RepoDiffEmbedScreen-BCDXFE3D.js → RepoDiffEmbedScreen-DXWoRF_c.js} +1 -1
  101. package/dist/client/assets/{RepoDiffPageScreen-m62FiWXC.js → RepoDiffPageScreen-D_274ExO.js} +1 -1
  102. package/dist/client/assets/RepoDiffViewer-DbedmHDX.js +7 -0
  103. package/dist/client/assets/RepoDiffViewerLazy-C0--fPtk.js +2 -0
  104. package/dist/client/assets/ReposScreen-D39_YG4H.js +6 -0
  105. package/dist/client/assets/ScoutDeckSurface-CKT3qdqY.js +1 -0
  106. package/dist/client/assets/{ScoutSurface-CkgT7A-c.js → ScoutSurface-UsRy0t-I.js} +1 -1
  107. package/dist/client/assets/{ScoutbotFxLab-D-kV5j4T.js → ScoutbotFxLab-Fmdfboxs.js} +1 -1
  108. package/dist/client/assets/{SecondaryNav-_wyKjwNf.js → SecondaryNav-o2RL9H8H.js} +1 -1
  109. package/dist/client/assets/{SessionEmbedScreen-CJZmIBV7.js → SessionEmbedScreen-RD5XOx7R.js} +1 -1
  110. package/dist/client/assets/{SessionObserve-yYA8Gy5s.js → SessionObserve-Dsd0j05N.js} +9 -9
  111. package/dist/client/assets/{SessionObserveEvidence-cHdjYOJe.js → SessionObserveEvidence-DopQYDkD.js} +1 -1
  112. package/dist/client/assets/SessionRefScreen-B_cTv47v.js +1 -0
  113. package/dist/client/assets/SessionsScreen-Bq0Z77On.js +1 -0
  114. package/dist/client/assets/SettingsDrawer-R8a0TlJD.css +1 -0
  115. package/dist/client/assets/SettingsDrawer-_AwuopMS.js +3 -0
  116. package/dist/client/assets/SettingsScreen-Cw4DDfJP.js +1 -0
  117. package/dist/client/assets/{ShikiPane-dBS9hD-z.js → ShikiPane-BfHc_3pM.js} +1 -1
  118. package/dist/client/assets/{SlidePanel-CH-3-8_2.js → SlidePanel-C-q7XwTa.js} +1 -1
  119. package/dist/client/assets/SpriteAvatar-Bs68ZENy.js +1 -0
  120. package/dist/client/assets/{StatusPill-C8m9ZymF.js → StatusPill-ZZQwxB1a.js} +1 -1
  121. package/dist/client/assets/{TailView-B0BSopPs.js → TailView-Q4FVMsUH.js} +2 -2
  122. package/dist/client/assets/Terminal-D7zqHwHV.js +1 -0
  123. package/dist/client/assets/TerminalEmbedScreen-CXIJ7qv6.js +1 -0
  124. package/dist/client/assets/TerminalHeaderMount-BnBLOPbb.js +1 -0
  125. package/dist/client/assets/{TextDocumentSurface-BWJCGBZf.js → TextDocumentSurface-CKQP-cBT.js} +1 -1
  126. package/dist/client/assets/{TmuxPeek-B4QdHbGm.js → TmuxPeek-V9dGESfO.js} +1 -1
  127. package/dist/client/assets/{VoicePermissionsPanel-Dd4ITJy_.js → VoicePermissionsPanel-k7sbLXx2.js} +1 -1
  128. package/dist/client/assets/WorkDetailScreen-60p9litn.js +5 -0
  129. package/dist/client/assets/WorkFilesViewer-BjJS7GyM.js +1 -0
  130. package/dist/client/assets/{activity-CC8JzJNH.js → activity-Bj3Hnbj3.js} +1 -1
  131. package/dist/client/assets/{addon-fit-CaZ-uLrg.js → addon-fit-BL-NTWRU.js} +1 -1
  132. package/dist/client/assets/{addon-webgl-B8utL3bM.js → addon-webgl-CIMgmNjg.js} +1 -1
  133. package/dist/client/assets/{ScoutbotBroadcastChip-CxtYZWPZ.css → agent-autocomplete-C7xwIcwd.css} +1 -1
  134. package/dist/client/assets/agent-autocomplete-DXlvdc4b.js +10 -0
  135. package/dist/client/assets/{agent-essentials-B3wcxg_v.js → agent-essentials-BOMHR0_U.js} +1 -1
  136. package/dist/client/assets/{agent-lane-card-model-q4cwzLX4.js → agent-lane-card-model-CTLxf3R4.js} +1 -1
  137. package/dist/client/assets/agent-lane-detail-ppJId6Jc.js +2 -0
  138. package/dist/client/assets/{agent-lane-preview-C33Dwpn7.js → agent-lane-preview-BhplDYGf.js} +1 -1
  139. package/dist/client/assets/{agent-lanes-BDNktFBZ.css → agent-lanes-DlqcEf0l.css} +1 -1
  140. package/dist/client/assets/{agent-lanes-model-VYQ5a68i.js → agent-lanes-model-AfrjRNK5.js} +2 -2
  141. package/dist/client/assets/agent-specialization-BIPIBW8u.js +1 -0
  142. package/dist/client/assets/api-Co9aQ2Jw.js +1 -0
  143. package/dist/client/assets/{api-BkjHJfgJ.js → api-HFH8wFyb.js} +1 -1
  144. package/dist/client/assets/{arc.es-uFv9UrHn.js → arc.es-IR5r6sj_.js} +1 -1
  145. package/dist/client/assets/archive-BjcGiAy8.js +1 -0
  146. package/dist/client/assets/{arrow-down-w1HPzDSE.js → arrow-down-BydciYFZ.js} +1 -1
  147. package/dist/client/assets/{arrow-left-B-3GJ7ct.js → arrow-left-CghA0kTw.js} +1 -1
  148. package/dist/client/assets/arrow-right-iJFv3jNh.js +1 -0
  149. package/dist/client/assets/{arrow-up-right-G6bJXxhK.js → arrow-up-right-CCfZXPqD.js} +1 -1
  150. package/dist/client/assets/{bot-DzCOGKi6.js → bot-B5sub1-i.js} +1 -1
  151. package/dist/client/assets/broker-display-Q75fupqG.js +2 -0
  152. package/dist/client/assets/{cache-Dr0why2k.js → cache-CeWH_KzJ.js} +1 -1
  153. package/dist/client/assets/{check-BX8nRgop.js → check-C18YQC90.js} +1 -1
  154. package/dist/client/assets/{chevron-down-B3VVRJcV.js → chevron-down-Mp9mu_yd.js} +1 -1
  155. package/dist/client/assets/{chevron-right-BYMV1511.js → chevron-right-CzH-TaSF.js} +1 -1
  156. package/dist/client/assets/{chunk-HRAB3GC3-dRd2eQMJ.js → chunk-HRAB3GC3-swV8PA2k.js} +1 -1
  157. package/dist/client/assets/{chunk-JTPDIGGW-BjX67kHU.js → chunk-JTPDIGGW-BKXqcLKw.js} +3 -3
  158. package/dist/client/assets/{chunk-T65CQEWV-kP6nJjkU.js → chunk-T65CQEWV-vYbNJ8E6.js} +1 -1
  159. package/dist/client/assets/{chunk-YOZR3KYS-C13bZPVd.js → chunk-YOZR3KYS-U65yUmqt.js} +1 -1
  160. package/dist/client/assets/{clock-B9ukVaVn.js → clock-B4PTFi5m.js} +1 -1
  161. package/dist/client/assets/{code-xml-BFc3TMSm.js → code-xml-Jtxsp5d1.js} +1 -1
  162. package/dist/client/assets/collapsed-strip-raJWthAH.css +1 -0
  163. package/dist/client/assets/compass-0_54-vz3.js +1 -0
  164. package/dist/client/assets/content-6RvWTrtk.js +1 -0
  165. package/dist/client/assets/content-BCgwMUqz.js +1 -0
  166. package/dist/client/assets/content-Bf2VLhx0.js +1 -0
  167. package/dist/client/assets/content-BrU_38-m.js +1 -0
  168. package/dist/client/assets/content-BvvJN8rN.js +1 -0
  169. package/dist/client/assets/content-CAeEqYPw.js +1 -0
  170. package/dist/client/assets/content-CHghn-rT.js +1 -0
  171. package/dist/client/assets/{content-Uqt8AG-s.css → content-CINHz-rZ.css} +1 -1
  172. package/dist/client/assets/content-CI_Z9DXk.js +1 -0
  173. package/dist/client/assets/content-CbyKONhW.js +1 -0
  174. package/dist/client/assets/content-Czogvp43.js +1 -0
  175. package/dist/client/assets/content-DFk0zNzX.js +1 -0
  176. package/dist/client/assets/content-DHe4DgkA.js +1 -0
  177. package/dist/client/assets/content-DMbawvqU.js +1 -0
  178. package/dist/client/assets/content-DTz7cKjo.js +1 -0
  179. package/dist/client/assets/content-E3kudY-W.js +1 -0
  180. package/dist/client/assets/content-LpO0aO_U.js +1 -0
  181. package/dist/client/assets/{conversation-icons-gpsv650H.js → conversation-icons-BV10B2Me.js} +1 -1
  182. package/dist/client/assets/conversation-model-CwF6Y9gx.js +1 -0
  183. package/dist/client/assets/conversation-motion-features-BKkCRaWR.js +1 -0
  184. package/dist/client/assets/{copy-BFmOcWof.js → copy-Dtpx4FOE.js} +1 -1
  185. package/dist/client/assets/cpu-BjVis9mc.js +1 -0
  186. package/dist/client/assets/{createLucideIcon-CFBn0Sdk.js → createLucideIcon-DXpqZP7I.js} +1 -1
  187. package/dist/client/assets/credentials-BTce3VP1.js +1 -0
  188. package/dist/client/assets/ctx-panel-D_HJ3nhb.css +1 -0
  189. package/dist/client/assets/discover-CHbrEItO.js +2 -0
  190. package/dist/client/assets/embed-entry-vil28MyU.js +2 -0
  191. package/dist/client/assets/{external-link-B1TI5yIt.js → external-link-Ckiyzjwo.js} +1 -1
  192. package/dist/client/assets/{eye-1J4yOUoG.js → eye-CpfyvdLq.js} +1 -1
  193. package/dist/client/assets/file-code-corner-7mo7EviR.js +1 -0
  194. package/dist/client/assets/{file-text-DcYSrI4v.js → file-text-KijGBnME.js} +1 -1
  195. package/dist/client/assets/gauge-y-Xg8Mrv.js +1 -0
  196. package/dist/client/assets/gestures-Bq9XnSqY.js +1 -0
  197. package/dist/client/assets/git-branch-BQ_x8KZL.js +1 -0
  198. package/dist/client/assets/harnesses-screen-2z36fJKE.css +1 -0
  199. package/dist/client/assets/home-moving-signal-DMguaRWR.css +1 -0
  200. package/dist/client/assets/home-moving-signal-DtRpiNa0.js +1 -0
  201. package/dist/client/assets/home-now-card-DFb4GOgM.js +1 -0
  202. package/dist/client/assets/{home-now-card-nano-y1EhBvVL.js → home-now-card-nano-D--m9jpq.js} +1 -1
  203. package/dist/client/assets/hooks-9d1SoaQA.js +2 -0
  204. package/dist/client/assets/host-advisor-B2Fqs5Dd.css +1 -0
  205. package/dist/client/assets/index-BVlMw8x_.js +1 -0
  206. package/dist/client/assets/index-CZ-05hKz.js +10 -0
  207. package/dist/client/assets/index-Cn0GR-q1.js +1 -0
  208. package/dist/client/assets/index-DosI4AG9.js +1 -0
  209. package/dist/client/assets/index-i7TMxlwW.css +1 -0
  210. package/dist/client/assets/index-wLwc74Pu.css +1 -0
  211. package/dist/client/assets/inspector-panel-C-EhEDYy.js +2 -0
  212. package/dist/client/assets/{keyboard-nav-h1IdakpD.js → keyboard-nav-DFhAJkW3.js} +1 -1
  213. package/dist/client/assets/{lane-observe-BA3g9aVd.js → lane-observe-vfyACHi0.js} +1 -1
  214. package/dist/client/assets/{lane-roster-store-71vFgAem.js → lane-roster-store-gUBsydNf.js} +1 -1
  215. package/dist/client/assets/layers-CGou-LwV.js +1 -0
  216. package/dist/client/assets/layout-grid-BrZt31QH.js +1 -0
  217. package/dist/client/assets/left-B_o51JV6.js +1 -0
  218. package/dist/client/assets/left-BpgWnaah.js +1 -0
  219. package/dist/client/assets/left-CwHZCGO3.js +2 -0
  220. package/dist/client/assets/left-CwLs0okF.js +1 -0
  221. package/dist/client/assets/left-Cx0kv6pe.js +1 -0
  222. package/dist/client/assets/left-DA0amyfu.js +1 -0
  223. package/dist/client/assets/left-DH44V4I_.css +1 -0
  224. package/dist/client/assets/left-R2OOE7VG.css +1 -0
  225. package/dist/client/assets/left-advisor-DU3s01gk.js +1 -0
  226. package/dist/client/assets/left-agents-qL5PpUY-.js +1 -0
  227. package/dist/client/assets/left-default-uvuvDmt0.js +1 -0
  228. package/dist/client/assets/left-lanes-DnNLgec8.js +1 -0
  229. package/dist/client/assets/left-mission-DN3-NLPC.js +1 -0
  230. package/dist/client/assets/left-z-6CkuBe.js +2 -0
  231. package/dist/client/assets/library-DIo5NiGP.js +1 -0
  232. package/dist/client/assets/{loader-circle-d6PKL_KD.js → loader-circle-BiohlpM3.js} +1 -1
  233. package/dist/client/assets/{local-agents-B5pq17tZ.js → local-agents-wUIaBcEr.js} +1 -1
  234. package/dist/client/assets/{mentions-agCGDgyA.js → mentions-CcPFMbmZ.js} +1 -1
  235. package/dist/client/assets/mesh-buckets-ByyFXdKT.js +1 -0
  236. package/dist/client/assets/{mesh-ops-5pZCYptW.js → mesh-ops-CvGyjK84.js} +1 -1
  237. package/dist/client/assets/mesh-roster-n2nDpEmA.js +1 -0
  238. package/dist/client/assets/{mesh-screen-BSDUjrnV.css → mesh-screen-D1Yvo8fU.css} +1 -1
  239. package/dist/client/assets/{mesh-view-store-KJzABIkN.js → mesh-view-store-BpxGm71b.js} +1 -1
  240. package/dist/client/assets/{message-circle-CJO-pi7b.js → message-circle-B2ddzBrX.js} +1 -1
  241. package/dist/client/assets/{message-markup-CyRDLdOn.js → message-markup-RkfmDfME.js} +1 -1
  242. package/dist/client/assets/{message-square-D1hMsMj_.js → message-square-D9YYWE0x.js} +1 -1
  243. package/dist/client/assets/message-visibility-DwxgcgYK.js +1 -0
  244. package/dist/client/assets/mission-control-CnU7dNt1.css +1 -0
  245. package/dist/client/assets/{mission-control-store-Ce6dOvnZ.js → mission-control-store-Bf4b54MV.js} +1 -1
  246. package/dist/client/assets/{observe-BSWVM8YA.js → observe-CJRIvOCn.js} +1 -1
  247. package/dist/client/assets/{operator-attention-BwSPeheT.js → operator-attention-RqieiSY8.js} +1 -1
  248. package/dist/client/assets/{page-status-D2FQLJOX.js → page-status-BptpTdQ-.js} +1 -1
  249. package/dist/client/assets/{paperclip-iZmDMOS5.js → paperclip-B1UNGl5d.js} +1 -1
  250. package/dist/client/assets/perf-PX8Rx0EP.js +1 -0
  251. package/dist/client/assets/persistent-state-YI-WHSCF.js +1 -0
  252. package/dist/client/assets/{plus-gZ0T0eBI.js → plus-CuU_X0-8.js} +1 -1
  253. package/dist/client/assets/profile-rY8jO38P.js +1 -0
  254. package/dist/client/assets/projects-inbox-BBs1hG13.css +1 -0
  255. package/dist/client/assets/projects-inbox-D-zAb9Gp.js +1 -0
  256. package/dist/client/assets/proxy-DnLpZIi9.js +1 -0
  257. package/dist/client/assets/{radio-RMLfV4EO.js → radio-Dm1ItnA4.js} +1 -1
  258. package/dist/client/assets/{refresh-cw-C4x1x6b_.js → refresh-cw-BRn9Oxxl.js} +1 -1
  259. package/dist/client/assets/resolve-panes-DO6LkwhQ.js +1 -0
  260. package/dist/client/assets/resolve-sidebar-context-CIF288wY.js +1 -0
  261. package/dist/client/assets/right-BJltPRnd.js +1 -0
  262. package/dist/client/assets/right-BbyYdzHn.js +1 -0
  263. package/dist/client/assets/right-Beh3nCUB.js +1 -0
  264. package/dist/client/assets/right-C1yumXNx.js +1 -0
  265. package/dist/client/assets/{right-D-k9Z1Fe.js → right-CJnB_Bg7.js} +2 -2
  266. package/dist/client/assets/right-CPP7GyOm.js +1 -0
  267. package/dist/client/assets/right-D3aTKf1F.js +1 -0
  268. package/dist/client/assets/right-DI1B79nR.js +1 -0
  269. package/dist/client/assets/right-DtsRNX5b.js +1 -0
  270. package/dist/client/assets/right-Shpw_xDy.js +1 -0
  271. package/dist/client/assets/{rocket-CMM-IdLy.js → rocket-DOwXHKWA.js} +1 -1
  272. package/dist/client/assets/router-DJj2WbDg.js +1 -0
  273. package/dist/client/assets/{scope-views-BIfMTXU4.js → scope-views-A4_vP97W.js} +1 -1
  274. package/dist/client/assets/scout-voice-BhPzrc6P.js +1 -0
  275. package/dist/client/assets/{scoutbot-BTIErYHo.js → scoutbot-BJIamJOH.js} +2 -2
  276. package/dist/client/assets/scoutbot-markdown-jh7tzFB1.js +6 -0
  277. package/dist/client/assets/{scroll-text-DPPYrqB9.js → scroll-text-DO0GQzvN.js} +1 -1
  278. package/dist/client/assets/{search-DAyagUtF.js → search-D1tJSAWe.js} +1 -1
  279. package/dist/client/assets/secondaryNavConfig-B9IF8wXl.js +1 -0
  280. package/dist/client/assets/{selection-bridge-BXw09aRF.js → selection-bridge-i2S9zpf8.js} +1 -1
  281. package/dist/client/assets/{send-horizontal-IcG46D2M.js → send-horizontal-CgLppsIC.js} +1 -1
  282. package/dist/client/assets/{server-BySujhDV.js → server-Dymv5Emh.js} +1 -1
  283. package/dist/client/assets/{session-catalog-ClS9xf6i.js → session-catalog-DNaOEzoQ.js} +1 -1
  284. package/dist/client/assets/{session-table-BdpHs1GN.js → session-table-PTQVoTyc.js} +1 -1
  285. package/dist/client/assets/settings-2fC_G9nX.js +1 -0
  286. package/dist/client/assets/{sliders-horizontal-R5pWUUcH.js → sliders-horizontal-BPSMHhbm.js} +1 -1
  287. package/dist/client/assets/{sparkles-DJOBD_8l.js → sparkles-Dy8p5xN8.js} +1 -1
  288. package/dist/client/assets/sse-CiOSzE5n.js +1 -0
  289. package/dist/client/assets/system-surfaces-redesign-QVXNeGYw.css +1 -0
  290. package/dist/client/assets/{tail-display-BRcJltQa.js → tail-display-DcliDVkW.js} +1 -1
  291. package/dist/client/assets/{tail-events-BdvqZHLr.js → tail-events-BMQmSx1n.js} +1 -1
  292. package/dist/client/assets/{terminal-relay-TffuSPGs.js → terminal-relay-9lhzEp2V.js} +1 -1
  293. package/dist/client/assets/terminal-screen-BLk4PAYt.css +1 -0
  294. package/dist/client/assets/terminal-sessions-BQ6t92tJ.js +1 -0
  295. package/dist/client/assets/{terminal-takeover-BOFPRPjR.js → terminal-takeover-DANQfTcy.js} +1 -1
  296. package/dist/client/assets/{terminal-DJPUp_Qn.js → terminal-yN9xN-h9.js} +1 -1
  297. package/dist/client/assets/{runtime-picker--IW3cRry.js → text-CnZ0e1-V.js} +1 -1
  298. package/dist/client/assets/text-rLpBg4_z.css +1 -0
  299. package/dist/client/assets/use-conversation-list-D9BNLfnW.js +1 -0
  300. package/dist/client/assets/{use-fleet-active-asks-BHzeBZSW.js → use-fleet-active-asks-BeAdcl09.js} +1 -1
  301. package/dist/client/assets/{use-mesh-ops-items-KmaauBr_.js → use-mesh-ops-items-BIvIHlqe.js} +1 -1
  302. package/dist/client/assets/use-reduced-motion-CKkhq9c5.js +1 -0
  303. package/dist/client/assets/{use-scout-dev-flags-BJbw87PK.js → use-scout-dev-flags-B2KCzPxn.js} +1 -1
  304. package/dist/client/assets/{useAgentHoverCard-C6o0tlat.js → useAgentHoverCard-CHBsxcbp.js} +1 -1
  305. package/dist/client/assets/useContentSecondaryNav-D0mUhxTF.js +1 -0
  306. package/dist/client/assets/{usePierreRuntime-Cm7-qdm0.js → usePierreRuntime-DUuXH5yp.js} +1 -1
  307. package/dist/client/assets/{wrench-CvRjjByE.js → wrench-YcXMlsh2.js} +1 -1
  308. package/dist/client/assets/{x-C8ayPBtj.js → x-e3h2hDsp.js} +1 -1
  309. package/dist/client/assets/{xterm-B0ci4Q9a.js → xterm-Byp1Hep_.js} +1 -1
  310. package/dist/client/assets/zap-nMcjPoWB.js +1 -0
  311. package/dist/client/favicon-16.png +0 -0
  312. package/dist/client/favicon-32.png +0 -0
  313. package/dist/client/favicon.ico +0 -0
  314. package/dist/client/favicon.svg +20 -47
  315. package/dist/client/index.html +5 -5
  316. package/dist/client/openscout-icon.png +0 -0
  317. package/dist/client/site.webmanifest +2 -2
  318. package/dist/client/web-app-icon-192.png +0 -0
  319. package/dist/client/web-app-icon-512.png +0 -0
  320. package/dist/main.mjs +20093 -78203
  321. package/dist/node/main.mjs +322 -252
  322. package/dist/pairing-runtime-controller.mjs +1032 -804
  323. package/dist/runtime/base-daemon.mjs +49 -121
  324. package/dist/runtime/broker-daemon.mjs +1105 -281
  325. package/dist/runtime/broker-process-manager.mjs +6 -0
  326. package/dist/runtime/mesh-discover.mjs +6 -0
  327. package/dist/scout-control-plane-web.mjs +3326 -1912
  328. package/package.json +7 -4
  329. package/dist/client/assets/ActivityScreen-DkUP7V7M.js +0 -1
  330. package/dist/client/assets/AgentAvatar-D8ZtMluU.js +0 -1
  331. package/dist/client/assets/AgentConfigurationScreen-BlGI6fuM.js +0 -1
  332. package/dist/client/assets/AgentDefinitionsWorkspace-CfaDVCVt.js +0 -1
  333. package/dist/client/assets/AgentFloorView-DjNLILLt.js +0 -1
  334. package/dist/client/assets/AgentInfoScreen-DG5dlHb_.js +0 -1
  335. package/dist/client/assets/AgentLaneDetailSheet-BzYzBfcW.js +0 -4
  336. package/dist/client/assets/AgentLanesEmbedScreen-Crxx1srt.js +0 -1
  337. package/dist/client/assets/AgentLanesView-ChNlmY-F.js +0 -2
  338. package/dist/client/assets/AgentSessions-DpY0htZV.js +0 -6
  339. package/dist/client/assets/AgentsConsole-CHyXrjhm.js +0 -1
  340. package/dist/client/assets/AgentsScreen-BhCjX2lD.js +0 -1
  341. package/dist/client/assets/AgentsSubnav-az_VDkri.js +0 -1
  342. package/dist/client/assets/AtopView-BjjPM8OX.js +0 -1
  343. package/dist/client/assets/BriefingDetailScreen-B7qJ90Np.js +0 -6
  344. package/dist/client/assets/BriefingsScreen-CW6N829d.js +0 -1
  345. package/dist/client/assets/BrokerScreen-X3z50712.js +0 -5
  346. package/dist/client/assets/ChatCollapsedStrip-DNR9osDy.js +0 -1
  347. package/dist/client/assets/CodeScreen-CIKK1LcZ.js +0 -1
  348. package/dist/client/assets/ContextMenu-CHIuVKz7.js +0 -1
  349. package/dist/client/assets/ConversationComposer-Bf7Ga_49.js +0 -1
  350. package/dist/client/assets/ConversationFeedRows-Cm1Lgo43.js +0 -1
  351. package/dist/client/assets/ConversationHeader-B_GXrKR0.js +0 -1
  352. package/dist/client/assets/ConversationPanels-BTBbEvrP.js +0 -2
  353. package/dist/client/assets/ConversationScreen-B3l2m3JI.js +0 -1
  354. package/dist/client/assets/ConversationScreen-yIKEsm-8.css +0 -1
  355. package/dist/client/assets/ConversationStatus-BqhUHD85.js +0 -1
  356. package/dist/client/assets/DispatchAftermath-BDA9CrOd.js +0 -1
  357. package/dist/client/assets/DocumentFocusViewer-B9vodVmG.js +0 -1
  358. package/dist/client/assets/FleetSearch-Bj9SCl2f.js +0 -1
  359. package/dist/client/assets/FleetSearch-EXOe8ulE.css +0 -1
  360. package/dist/client/assets/FlightObserveScreen-BVMdsiCC.js +0 -1
  361. package/dist/client/assets/FollowScreen-BifwHWOV.js +0 -1
  362. package/dist/client/assets/HarnessesScreen-fMnbnrD4.js +0 -1
  363. package/dist/client/assets/HomeHero-BgM6S39l.js +0 -1
  364. package/dist/client/assets/HomeHero-DEl-WBsT.css +0 -1
  365. package/dist/client/assets/KnowledgeSearchScreen-Ch_WENUC.js +0 -1
  366. package/dist/client/assets/LaneTraceDetailSheet-H3AnN-vN.js +0 -1
  367. package/dist/client/assets/MeshScreen-48QkJSDI.js +0 -1
  368. package/dist/client/assets/MessageComposerSuggestions-FdVHnT_q.js +0 -1
  369. package/dist/client/assets/MessagesScreen-BMOOfbWX.js +0 -1
  370. package/dist/client/assets/MissionControlView-BpsHKu1F.js +0 -1
  371. package/dist/client/assets/MissionFocusOverlay-BPnAEA3F.js +0 -1
  372. package/dist/client/assets/MissionLeftAgentRow-iOZ6ds9L.js +0 -1
  373. package/dist/client/assets/MissionLogPane-B0csI89E.js +0 -1
  374. package/dist/client/assets/NewAgentModal-DBHJR9Qm.js +0 -1
  375. package/dist/client/assets/NewChatComposer-Hd7pI5Ac.js +0 -19
  376. package/dist/client/assets/ObserveEmbedScreen-DyArn7Id.js +0 -2
  377. package/dist/client/assets/ObserveTextFlow-CkMrtT8s.js +0 -2
  378. package/dist/client/assets/ObservedTopologyPanel-CaSZZP05.js +0 -2
  379. package/dist/client/assets/OpenScoutAppShell-BtlKkiuF.js +0 -87
  380. package/dist/client/assets/OpsAgentsView-CnqrwbC2.js +0 -1
  381. package/dist/client/assets/OpsScreen-DOlmlVkP.js +0 -1
  382. package/dist/client/assets/OpsSubnav-Dj3ShAKv.js +0 -1
  383. package/dist/client/assets/PlanView-BLGdWDx6.js +0 -1
  384. package/dist/client/assets/ProjectAgentProfile-Dv1sVnQl.js +0 -1
  385. package/dist/client/assets/ProjectAgentProfileHero-0-GDhsPT.js +0 -1
  386. package/dist/client/assets/ProjectsInbox-B3DpAI5b.js +0 -2
  387. package/dist/client/assets/ProjectsRail-BDl7U9Jq.js +0 -1
  388. package/dist/client/assets/ProjectsScreen-Dl2FcGrR.js +0 -1
  389. package/dist/client/assets/ProjectsThreadAside-BcGC5mHE.js +0 -1
  390. package/dist/client/assets/Provider-cJCdHAxu.js +0 -1
  391. package/dist/client/assets/RailRow-CLcVmywd.js +0 -1
  392. package/dist/client/assets/RailRow-Cf9LOiEj.css +0 -1
  393. package/dist/client/assets/RawSessionsTable-DBto4Ts-.js +0 -1
  394. package/dist/client/assets/RealtimeVoiceScreen-DXEU5v3g.js +0 -1
  395. package/dist/client/assets/RepoDiffViewer-PaNeZMhJ.js +0 -7
  396. package/dist/client/assets/RepoDiffViewerLazy-CWE5GxMP.js +0 -2
  397. package/dist/client/assets/ReposScreen-Cksv1cAD.js +0 -6
  398. package/dist/client/assets/ScoutDeckSurface-BCjPl7C4.js +0 -1
  399. package/dist/client/assets/ScoutbotBroadcastChip-DkiRCHuK.js +0 -2
  400. package/dist/client/assets/ScoutbotRealtimeVoiceCall-1ixiEn1L.js +0 -1
  401. package/dist/client/assets/SessionRefScreen-OkTY7Szg.js +0 -1
  402. package/dist/client/assets/SessionsScreen-B-GFjxIA.js +0 -1
  403. package/dist/client/assets/SettingsDrawer-Co11RFX0.js +0 -3
  404. package/dist/client/assets/SettingsDrawer-UX7pFJU_.css +0 -1
  405. package/dist/client/assets/SettingsScreen-Cn09nq5_.js +0 -1
  406. package/dist/client/assets/SpriteAvatar-DS6Tmyua.js +0 -1
  407. package/dist/client/assets/Terminal-U8gjIdm3.js +0 -1
  408. package/dist/client/assets/TerminalEmbedScreen-CTmdE7us.js +0 -1
  409. package/dist/client/assets/WorkDetailScreen-mJs0mb99.js +0 -5
  410. package/dist/client/assets/WorkFilesViewer-ODzLXKxj.js +0 -1
  411. package/dist/client/assets/agent-identity-BxCsXnDp.js +0 -1
  412. package/dist/client/assets/agent-lane-detail-BNNm6FNu.js +0 -2
  413. package/dist/client/assets/api-h5zurxmi.js +0 -1
  414. package/dist/client/assets/broker-display-pp33bLsu.js +0 -2
  415. package/dist/client/assets/collapsed-strip-Dz-of2SM.css +0 -1
  416. package/dist/client/assets/content-B8gahuBy.js +0 -1
  417. package/dist/client/assets/content-BIqX06OQ.js +0 -1
  418. package/dist/client/assets/content-BKDZ6Fxe.js +0 -1
  419. package/dist/client/assets/content-C15Ya-iu.js +0 -1
  420. package/dist/client/assets/content-CDE9tJDF.js +0 -1
  421. package/dist/client/assets/content-CSAfI-PX.js +0 -1
  422. package/dist/client/assets/content-CTF9D60D.js +0 -1
  423. package/dist/client/assets/content-CbAGkYQO.js +0 -1
  424. package/dist/client/assets/content-CtqLJOVp.js +0 -1
  425. package/dist/client/assets/content-Dvs1KRfo.js +0 -1
  426. package/dist/client/assets/content-DyJdVZjI.js +0 -1
  427. package/dist/client/assets/content-Ji7ATaf7.js +0 -1
  428. package/dist/client/assets/content-eqZXKWcP.js +0 -1
  429. package/dist/client/assets/content-iyyQKwvA.js +0 -1
  430. package/dist/client/assets/content-pDE7Fpb9.js +0 -1
  431. package/dist/client/assets/content-pPSd2dua.js +0 -1
  432. package/dist/client/assets/conversation-model-CHwHZNw-.js +0 -1
  433. package/dist/client/assets/conversation-motion-features-DXtKlmuM.js +0 -1
  434. package/dist/client/assets/ctx-panel-B4s49N9e.css +0 -1
  435. package/dist/client/assets/discover-DKf0aTr_.js +0 -2
  436. package/dist/client/assets/embed-entry-RlQUTtc4.js +0 -2
  437. package/dist/client/assets/gestures-CcEOV6Sr.js +0 -1
  438. package/dist/client/assets/harnesses-screen-DBZoTZz8.css +0 -1
  439. package/dist/client/assets/home-moving-signal-Bh2FugbH.js +0 -1
  440. package/dist/client/assets/home-moving-signal-CAa0V91u.css +0 -1
  441. package/dist/client/assets/home-now-card-ByRH5fFx.js +0 -1
  442. package/dist/client/assets/hooks-DUZwL3Aq.js +0 -2
  443. package/dist/client/assets/index-BBznYVWk.css +0 -1
  444. package/dist/client/assets/index-BTuq-8Iv.js +0 -1
  445. package/dist/client/assets/index-CmwGCxUk.js +0 -1
  446. package/dist/client/assets/index-CvF09yvf.css +0 -1
  447. package/dist/client/assets/index-DmFAhGPj.js +0 -10
  448. package/dist/client/assets/index-Dtaswdsh.js +0 -1
  449. package/dist/client/assets/inspector-panel-DzgS5_Mv.js +0 -2
  450. package/dist/client/assets/left-8NITBvFX.js +0 -1
  451. package/dist/client/assets/left-B2HEqrTM.js +0 -2
  452. package/dist/client/assets/left-Bk3XnxPD.css +0 -1
  453. package/dist/client/assets/left-CCoobxPS.css +0 -1
  454. package/dist/client/assets/left-CTYUvXbe.js +0 -1
  455. package/dist/client/assets/left-CwDRT50z.js +0 -2
  456. package/dist/client/assets/left-CxlDLJlw.js +0 -1
  457. package/dist/client/assets/left-XFXxNd4g.js +0 -1
  458. package/dist/client/assets/left-agents-Ck4Xn-R8.js +0 -1
  459. package/dist/client/assets/left-default-BeOyS0bR.js +0 -1
  460. package/dist/client/assets/left-lanes-DZp3jJMo.js +0 -1
  461. package/dist/client/assets/left-mission-CuKFQ5xL.js +0 -1
  462. package/dist/client/assets/left-p1hkO6P0.js +0 -1
  463. package/dist/client/assets/left-plan-3rrFENhp.js +0 -2
  464. package/dist/client/assets/library-E--gKzEZ.js +0 -1
  465. package/dist/client/assets/mesh-buckets-CfAukILK.js +0 -1
  466. package/dist/client/assets/message-visibility-kJM8XcSG.js +0 -1
  467. package/dist/client/assets/mission-control-m3BTDQ9l.css +0 -1
  468. package/dist/client/assets/model-Co0zkMIc.js +0 -1
  469. package/dist/client/assets/plan-view-D56fneVF.css +0 -1
  470. package/dist/client/assets/profile-Dxj3VVOM.js +0 -1
  471. package/dist/client/assets/projects-inbox-COZ23dLR.css +0 -1
  472. package/dist/client/assets/projects-inbox-Dzt_GQDv.js +0 -1
  473. package/dist/client/assets/resolve-panes-C9gF0w4e.js +0 -1
  474. package/dist/client/assets/resolve-sidebar-context-DxbY5RCH.js +0 -1
  475. package/dist/client/assets/right-5L7Tn0zG.js +0 -1
  476. package/dist/client/assets/right-CYtkMmRu.js +0 -1
  477. package/dist/client/assets/right-CreoQzPP.js +0 -1
  478. package/dist/client/assets/right-D9xFfy2b.js +0 -1
  479. package/dist/client/assets/right-DI7zHADe.js +0 -1
  480. package/dist/client/assets/right-DUbJ3WVc.js +0 -1
  481. package/dist/client/assets/right-DiybhsiK.js +0 -1
  482. package/dist/client/assets/right-Jh_1Q88s.js +0 -1
  483. package/dist/client/assets/right-udr1qTJG.js +0 -1
  484. package/dist/client/assets/router-Cn_s9IGH.js +0 -1
  485. package/dist/client/assets/runtime-picker-vhm0gtLs.css +0 -1
  486. package/dist/client/assets/scout-voice-CwbOz6EN.js +0 -1
  487. package/dist/client/assets/secondaryNavConfig-Dw3gS1jR.js +0 -1
  488. package/dist/client/assets/sse-CxXt4tqI.js +0 -1
  489. package/dist/client/assets/system-surfaces-redesign-B7GQhfpw.css +0 -1
  490. package/dist/client/assets/terminal-screen-BqVnCwl0.css +0 -1
  491. package/dist/client/assets/terminal-sessions-AmSgHklm.js +0 -1
  492. package/dist/client/assets/text-DsBWV_4k.js +0 -1
  493. package/dist/client/assets/use-conversation-list-C-dPcjQe.js +0 -1
  494. package/dist/client/assets/use-reduced-motion-CYqhYqHO.js +0 -1
  495. package/dist/client/assets/useContentSecondaryNav-DjHBrgnS.js +0 -1
  496. package/dist/highlights-eq9cgrbb.scm +0 -604
  497. package/dist/highlights-ghv9g403.scm +0 -205
  498. package/dist/highlights-hk7bwhj4.scm +0 -284
  499. package/dist/highlights-r812a2qc.scm +0 -150
  500. package/dist/highlights-x6tmsnaa.scm +0 -115
  501. package/dist/injections-73j83es3.scm +0 -27
  502. package/dist/tree-sitter-javascript-nd0q4pe9.wasm +0 -0
  503. package/dist/tree-sitter-markdown-411r6y9b.wasm +0 -0
  504. package/dist/tree-sitter-markdown_inline-j5349f42.wasm +0 -0
  505. package/dist/tree-sitter-typescript-zxjzwt75.wasm +0 -0
  506. package/dist/tree-sitter-zig-e78zbjpm.wasm +0 -0
  507. /package/dist/client/assets/{document-focus-viewer-BSC_JwVE.css → DocumentFocusViewer-BSC_JwVE.css} +0 -0
@@ -3182,12 +3182,12 @@ function checkDaemonBinaryStale() {
3182
3182
  debug22(`daemon binary path changed: ${info.binaryPath} \u2192 ${currentBinaryPath}`);
3183
3183
  } else {
3184
3184
  try {
3185
- const stat7 = fs2.statSync(currentBinaryPath);
3186
- if (stat7.mtimeMs === info.binaryMtimeMs) {
3185
+ const stat8 = fs2.statSync(currentBinaryPath);
3186
+ if (stat8.mtimeMs === info.binaryMtimeMs) {
3187
3187
  debug22("daemon binary is current \u2014 no restart needed");
3188
3188
  return;
3189
3189
  }
3190
- debug22(`daemon binary mtime changed: ${info.binaryMtimeMs} \u2192 ${stat7.mtimeMs}`);
3190
+ debug22(`daemon binary mtime changed: ${info.binaryMtimeMs} \u2192 ${stat8.mtimeMs}`);
3191
3191
  } catch {
3192
3192
  return;
3193
3193
  }
@@ -3207,10 +3207,10 @@ function checkDaemonBinaryStale() {
3207
3207
  }
3208
3208
  function writeDaemonInfo(binaryPath) {
3209
3209
  try {
3210
- const stat7 = fs2.statSync(binaryPath);
3210
+ const stat8 = fs2.statSync(binaryPath);
3211
3211
  fs2.writeFileSync(getDaemonInfoPath(), JSON.stringify({
3212
3212
  binaryPath,
3213
- binaryMtimeMs: stat7.mtimeMs
3213
+ binaryMtimeMs: stat8.mtimeMs
3214
3214
  }));
3215
3215
  } catch {}
3216
3216
  }
@@ -3448,8 +3448,8 @@ function getParentSessionId() {
3448
3448
  const chain = [process.pid];
3449
3449
  let current = process.pid;
3450
3450
  for (let i = 0;i < 64; i++) {
3451
- const stat7 = fs2.readFileSync(`/proc/${current}/stat`, "utf-8");
3452
- const fields = stat7.split(") ");
3451
+ const stat8 = fs2.readFileSync(`/proc/${current}/stat`, "utf-8");
3452
+ const fields = stat8.split(") ");
3453
3453
  if (fields.length < 2)
3454
3454
  break;
3455
3455
  const ppid = parseInt(fields[1].split(" ")[1], 10);
@@ -4594,8 +4594,8 @@ async function withDirLock(lockPath, opts, fn) {
4594
4594
  }
4595
4595
  try {
4596
4596
  const owner = readLockOwner(lockPath);
4597
- const stat7 = fs.statSync(lockPath);
4598
- const ageMs = Date.now() - stat7.mtimeMs;
4597
+ const stat8 = fs.statSync(lockPath);
4598
+ const ageMs = Date.now() - stat8.mtimeMs;
4599
4599
  if (owner ? !isLockOwnerAlive(owner) : ageMs > OWNER_GRACE_MS) {
4600
4600
  debug4("stealing abandoned lock %s (owner pid %s)", lockPath, owner?.pid ?? "unknown");
4601
4601
  stealLock(lockPath);
@@ -23960,8 +23960,8 @@ function writeBackValue(itemKey, newValueStr, sourceFilePath) {
23960
23960
  }
23961
23961
  function getParentPidViaProc(pid) {
23962
23962
  try {
23963
- const stat7 = readFileSync19(`/proc/${pid}/stat`, "utf8");
23964
- const after = stat7.slice(stat7.lastIndexOf(")") + 2);
23963
+ const stat8 = readFileSync19(`/proc/${pid}/stat`, "utf8");
23964
+ const after = stat8.slice(stat8.lastIndexOf(")") + 2);
23965
23965
  const fields = after.split(" ");
23966
23966
  const ppid = Number(fields[1]);
23967
23967
  return Number.isFinite(ppid) ? ppid : undefined;
@@ -26972,7 +26972,7 @@ var require_tslib2 = __commonJS((exports, module) => {
26972
26972
  // packages/runtime/src/broker-daemon.ts
26973
26973
  import { createHash as createHash16, randomUUID as randomUUID9 } from "crypto";
26974
26974
  import { createServer } from "http";
26975
- import { mkdir as mkdir14, readFile as readFile15, rename as rename3, stat as stat7, unlink as unlink3, writeFile as writeFile11 } from "fs/promises";
26975
+ import { mkdir as mkdir14, readFile as readFile15, rename as rename3, stat as stat8, unlink as unlink3, writeFile as writeFile11 } from "fs/promises";
26976
26976
  import { createRequire as createRequire4 } from "module";
26977
26977
  import { hostname as hostname4 } from "os";
26978
26978
  import { basename as basename24, dirname as dirname33, join as join56, resolve as resolve22 } from "path";
@@ -43866,7 +43866,6 @@ function formatScoutPermissionProfiles() {
43866
43866
 
43867
43867
  // packages/protocol/src/presence.ts
43868
43868
  var PRESENCE_STALE_AFTER_MS = 45000;
43869
- var PRESENCE_REFRESH_INTERVAL_MS = 30000;
43870
43869
  var PRESENCE_GONE_AFTER_STALE_MS = 60000;
43871
43870
  function presenceLifecycle(beat, now, options = {}) {
43872
43871
  if (now < beat.staleAt)
@@ -44660,7 +44659,7 @@ function isScoutLaunchableHarness(value) {
44660
44659
  if (!value)
44661
44660
  return false;
44662
44661
  const normalized = value.trim().toLowerCase();
44663
- return SCOUT_LAUNCHABLE_HARNESSES.includes(normalized);
44662
+ return normalized === "oc" || SCOUT_LAUNCHABLE_HARNESSES.includes(normalized);
44664
44663
  }
44665
44664
  function normalizeScoutReasoningEffort(value) {
44666
44665
  const normalized = value?.trim().toLowerCase();
@@ -45353,12 +45352,12 @@ function patchConsoleForSecrets() {
45353
45352
  }
45354
45353
 
45355
45354
  // packages/runtime/src/tail/claude-source.ts
45356
- import { closeSync, existsSync as existsSync4, openSync, readdirSync, readSync, statSync } from "fs";
45355
+ import { closeSync, existsSync as existsSync4, openSync, readdirSync, readSync, statSync as statSync2 } from "fs";
45357
45356
  import { homedir as homedir4 } from "os";
45358
45357
  import { basename, join as join4, relative } from "path";
45359
45358
 
45360
45359
  // packages/runtime/src/user-config.ts
45361
- import { existsSync as existsSync2, readFileSync, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
45360
+ import { existsSync as existsSync2, readFileSync, statSync, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
45362
45361
  import { homedir as homedir2 } from "os";
45363
45362
  import { dirname, join as join2 } from "path";
45364
45363
 
@@ -45441,15 +45440,41 @@ function ensureOpenScoutCleanSlateSync() {
45441
45440
  function userConfigPath() {
45442
45441
  return join2(process.env.OPENSCOUT_HOME ?? join2(homedir2(), ".openscout"), "user.json");
45443
45442
  }
45444
- function loadUserConfig() {
45445
- const configPath = userConfigPath();
45446
- if (!existsSync2(configPath))
45447
- return {};
45443
+ var userConfigCache = null;
45444
+ var USER_CONFIG_STAT_INTERVAL_MS = 100;
45445
+ function userConfigFileKey(configPath) {
45448
45446
  try {
45449
- return JSON.parse(readFileSync(configPath, "utf8"));
45447
+ const stats = statSync(configPath);
45448
+ return `${stats.ino}:${stats.mtimeMs}:${stats.size}`;
45450
45449
  } catch {
45451
- return {};
45450
+ return "missing";
45451
+ }
45452
+ }
45453
+ function readUserConfigFromDisk(configPath, now) {
45454
+ const fileKey = userConfigFileKey(configPath);
45455
+ let value = {};
45456
+ if (existsSync2(configPath)) {
45457
+ try {
45458
+ value = JSON.parse(readFileSync(configPath, "utf8"));
45459
+ } catch {
45460
+ value = {};
45461
+ }
45462
+ }
45463
+ userConfigCache = { path: configPath, value, fileKey, statCheckedAt: now };
45464
+ return { ...value };
45465
+ }
45466
+ function loadUserConfig(now = Date.now()) {
45467
+ const configPath = userConfigPath();
45468
+ if (userConfigCache && userConfigCache.path === configPath) {
45469
+ if (now - userConfigCache.statCheckedAt < USER_CONFIG_STAT_INTERVAL_MS) {
45470
+ return { ...userConfigCache.value };
45471
+ }
45472
+ if (userConfigFileKey(configPath) === userConfigCache.fileKey) {
45473
+ userConfigCache.statCheckedAt = now;
45474
+ return { ...userConfigCache.value };
45475
+ }
45452
45476
  }
45477
+ return readUserConfigFromDisk(configPath, now);
45453
45478
  }
45454
45479
  function readSettingsOperatorName() {
45455
45480
  const settingsPath = resolveOpenScoutSupportPaths().settingsPath;
@@ -47558,7 +47583,7 @@ function listRecentClaudeProjectTranscripts(root, scope) {
47558
47583
  for (const entry of projectDirs) {
47559
47584
  const projectDir = join4(root, entry);
47560
47585
  try {
47561
- if (!statSync(projectDir).isDirectory())
47586
+ if (!statSync2(projectDir).isDirectory())
47562
47587
  continue;
47563
47588
  } catch {
47564
47589
  continue;
@@ -47566,13 +47591,13 @@ function listRecentClaudeProjectTranscripts(root, scope) {
47566
47591
  for (const file2 of listJsonlFiles(projectDir)) {
47567
47592
  const path = join4(projectDir, file2);
47568
47593
  try {
47569
- const stats = statSync(path);
47594
+ const stats = statSync2(path);
47570
47595
  const subagentsDir = join4(projectDir, basename(path, ".jsonl"), "subagents");
47571
47596
  const activeSubagents = [];
47572
47597
  for (const subagentFile of listClaudeSubagentFiles(subagentsDir)) {
47573
47598
  const subagentPath = join4(subagentsDir, subagentFile);
47574
47599
  try {
47575
- const subagentStats = statSync(subagentPath);
47600
+ const subagentStats = statSync2(subagentPath);
47576
47601
  if (subagentStats.mtimeMs < cutoff)
47577
47602
  continue;
47578
47603
  activeSubagents.push({
@@ -47809,7 +47834,7 @@ var ClaudeSource = {
47809
47834
  };
47810
47835
 
47811
47836
  // packages/runtime/src/tail/codex-source.ts
47812
- import { closeSync as closeSync2, existsSync as existsSync5, openSync as openSync2, readdirSync as readdirSync2, readSync as readSync2, statSync as statSync2 } from "fs";
47837
+ import { closeSync as closeSync2, existsSync as existsSync5, openSync as openSync2, readdirSync as readdirSync2, readSync as readSync2, statSync as statSync3 } from "fs";
47813
47838
  import { homedir as homedir5 } from "os";
47814
47839
  import { basename as basename2, join as join5 } from "path";
47815
47840
  var SOURCE_NAME2 = "codex";
@@ -47962,7 +47987,7 @@ function walkRecentJsonlFiles(root, scope) {
47962
47987
  const path = join5(dir, entry);
47963
47988
  let stats;
47964
47989
  try {
47965
- stats = statSync2(path);
47990
+ stats = statSync3(path);
47966
47991
  } catch {
47967
47992
  continue;
47968
47993
  }
@@ -48230,7 +48255,7 @@ var CodexSource = {
48230
48255
  };
48231
48256
 
48232
48257
  // packages/runtime/src/tail/cursor-source.ts
48233
- import { closeSync as closeSync3, existsSync as existsSync6, openSync as openSync3, readdirSync as readdirSync3, readSync as readSync3, statSync as statSync3 } from "fs";
48258
+ import { closeSync as closeSync3, existsSync as existsSync6, openSync as openSync3, readdirSync as readdirSync3, readSync as readSync3, statSync as statSync4 } from "fs";
48234
48259
  import { homedir as homedir6 } from "os";
48235
48260
  import { basename as basename3, join as join6 } from "path";
48236
48261
  var SOURCE_NAME3 = "cursor";
@@ -48357,7 +48382,7 @@ function walkRecentMonitorLogs(root, scope) {
48357
48382
  continue;
48358
48383
  const path = join6(root, entry);
48359
48384
  try {
48360
- const stats = statSync3(path);
48385
+ const stats = statSync4(path);
48361
48386
  if (!stats.isFile() || stats.mtimeMs < cutoff)
48362
48387
  continue;
48363
48388
  found.push({ path, mtimeMs: stats.mtimeMs, size: stats.size });
@@ -48430,7 +48455,7 @@ var CursorSource = {
48430
48455
  };
48431
48456
 
48432
48457
  // packages/runtime/src/tail/grok-source.ts
48433
- import { closeSync as closeSync4, existsSync as existsSync7, openSync as openSync4, readdirSync as readdirSync4, readFileSync as readFileSync2, readSync as readSync4, statSync as statSync4 } from "fs";
48458
+ import { closeSync as closeSync4, existsSync as existsSync7, openSync as openSync4, readdirSync as readdirSync4, readFileSync as readFileSync2, readSync as readSync4, statSync as statSync5 } from "fs";
48434
48459
  import { homedir as homedir7 } from "os";
48435
48460
  import { basename as basename4, dirname as dirname2, join as join7 } from "path";
48436
48461
  var SOURCE_NAME4 = "grok";
@@ -48600,7 +48625,7 @@ function walkRecentGrokEventFiles(root, scope) {
48600
48625
  const path = join7(dir, entry);
48601
48626
  let stats;
48602
48627
  try {
48603
- stats = statSync4(path);
48628
+ stats = statSync5(path);
48604
48629
  } catch {
48605
48630
  continue;
48606
48631
  }
@@ -48722,7 +48747,7 @@ function grokMatcherForTranscript(transcriptPath) {
48722
48747
  return null;
48723
48748
  let updatesMtimeMs = 0;
48724
48749
  try {
48725
- updatesMtimeMs = statSync4(updatesPath).mtimeMs;
48750
+ updatesMtimeMs = statSync5(updatesPath).mtimeMs;
48726
48751
  } catch {
48727
48752
  return null;
48728
48753
  }
@@ -48912,7 +48937,7 @@ var GrokSource = {
48912
48937
  };
48913
48938
 
48914
48939
  // packages/runtime/src/tail/kimi-source.ts
48915
- import { existsSync as existsSync8, readdirSync as readdirSync5, readFileSync as readFileSync3, statSync as statSync5 } from "fs";
48940
+ import { existsSync as existsSync8, readdirSync as readdirSync5, readFileSync as readFileSync3, statSync as statSync6 } from "fs";
48916
48941
  import { homedir as homedir8 } from "os";
48917
48942
  import { basename as basename5, dirname as dirname3, join as join8 } from "path";
48918
48943
  var SOURCE_NAME5 = "kimi";
@@ -49014,7 +49039,7 @@ function walkRecentKimiWireFiles(root, scope) {
49014
49039
  const path = join8(directory, entry);
49015
49040
  let stats;
49016
49041
  try {
49017
- stats = statSync5(path);
49042
+ stats = statSync6(path);
49018
49043
  } catch {
49019
49044
  continue;
49020
49045
  }
@@ -49034,7 +49059,7 @@ function readKimiTranscriptMetadata(file2) {
49034
49059
  let stateMtimeMs = null;
49035
49060
  let stateSize = null;
49036
49061
  try {
49037
- const stateStat = statSync5(statePath);
49062
+ const stateStat = statSync6(statePath);
49038
49063
  stateMtimeMs = stateStat.mtimeMs;
49039
49064
  stateSize = stateStat.size;
49040
49065
  } catch {}
@@ -49253,7 +49278,7 @@ var KimiSource = {
49253
49278
  };
49254
49279
 
49255
49280
  // packages/runtime/src/tail/opencode-source.ts
49256
- import { closeSync as closeSync5, existsSync as existsSync9, openSync as openSync5, readdirSync as readdirSync6, readFileSync as readFileSync4, readSync as readSync5, statSync as statSync6 } from "fs";
49281
+ import { closeSync as closeSync5, existsSync as existsSync9, openSync as openSync5, readdirSync as readdirSync6, readFileSync as readFileSync4, readSync as readSync5, statSync as statSync7 } from "fs";
49257
49282
  import { homedir as homedir9 } from "os";
49258
49283
  import { basename as basename6, join as join9, sep } from "path";
49259
49284
  var SOURCE_NAME6 = "opencode";
@@ -49390,7 +49415,7 @@ function walkRecentSessionFiles(root, scope) {
49390
49415
  const path = join9(dir, entry);
49391
49416
  let stats;
49392
49417
  try {
49393
- stats = statSync6(path);
49418
+ stats = statSync7(path);
49394
49419
  } catch {
49395
49420
  continue;
49396
49421
  }
@@ -49418,38 +49443,63 @@ function walkRecentMessageSessionFiles(root, scope) {
49418
49443
  for (const sessionId of sessionDirs) {
49419
49444
  const dir = join9(messageRoot, sessionId);
49420
49445
  let entries = [];
49446
+ let messageDirectoryMtime = 0;
49421
49447
  try {
49422
- const stats = statSync6(dir);
49448
+ const stats = statSync7(dir);
49423
49449
  if (!stats.isDirectory())
49424
49450
  continue;
49451
+ messageDirectoryMtime = stats.mtimeMs;
49425
49452
  entries = readdirSync6(dir);
49426
49453
  } catch {
49427
49454
  continue;
49428
49455
  }
49429
- let latestMessageMtime = 0;
49456
+ let latestDependencyMtime = messageDirectoryMtime;
49457
+ let dependencySize = entries.length;
49430
49458
  for (const entry of entries) {
49431
49459
  if (!entry.endsWith(".json"))
49432
49460
  continue;
49433
49461
  try {
49434
- const stats = statSync6(join9(dir, entry));
49435
- if (stats.isFile() && stats.mtimeMs >= cutoff && stats.mtimeMs > latestMessageMtime) {
49436
- latestMessageMtime = stats.mtimeMs;
49462
+ const stats = statSync7(join9(dir, entry));
49463
+ if (!stats.isFile())
49464
+ continue;
49465
+ latestDependencyMtime = Math.max(latestDependencyMtime, stats.mtimeMs);
49466
+ dependencySize += stats.size;
49467
+ const messageId = entry.replace(/\.json$/u, "");
49468
+ const partDir = join9(root, "part", messageId);
49469
+ const partDirStats = statSync7(partDir);
49470
+ if (!partDirStats.isDirectory())
49471
+ continue;
49472
+ latestDependencyMtime = Math.max(latestDependencyMtime, partDirStats.mtimeMs);
49473
+ const partEntries = readdirSync6(partDir);
49474
+ dependencySize += partEntries.length;
49475
+ for (const partEntry of partEntries) {
49476
+ if (!partEntry.endsWith(".json"))
49477
+ continue;
49478
+ try {
49479
+ const partStats = statSync7(join9(partDir, partEntry));
49480
+ if (!partStats.isFile())
49481
+ continue;
49482
+ latestDependencyMtime = Math.max(latestDependencyMtime, partStats.mtimeMs);
49483
+ dependencySize += partStats.size;
49484
+ } catch {
49485
+ continue;
49486
+ }
49437
49487
  }
49438
49488
  } catch {
49439
49489
  continue;
49440
49490
  }
49441
49491
  }
49442
- if (latestMessageMtime <= 0)
49492
+ if (latestDependencyMtime < cutoff)
49443
49493
  continue;
49444
49494
  const sessionPath = join9(root, "session", "global", `${sessionId}.json`);
49445
49495
  try {
49446
- const sessionStats = statSync6(sessionPath);
49496
+ const sessionStats = statSync7(sessionPath);
49447
49497
  if (!sessionStats.isFile())
49448
49498
  continue;
49449
49499
  found.set(sessionPath, {
49450
49500
  path: sessionPath,
49451
- mtimeMs: Math.max(sessionStats.mtimeMs, latestMessageMtime),
49452
- size: sessionStats.size
49501
+ mtimeMs: Math.max(sessionStats.mtimeMs, latestDependencyMtime),
49502
+ size: sessionStats.size + dependencySize
49453
49503
  });
49454
49504
  } catch {
49455
49505
  continue;
@@ -49475,8 +49525,15 @@ function discoverOpenCodeTranscripts(scope) {
49475
49525
  ...walkRecentMessageSessionFiles(root, scope)
49476
49526
  ]) {
49477
49527
  const existing = byPath.get(file2.path);
49478
- if (!existing || file2.mtimeMs > existing.mtimeMs)
49528
+ if (!existing) {
49479
49529
  byPath.set(file2.path, file2);
49530
+ } else {
49531
+ byPath.set(file2.path, {
49532
+ path: file2.path,
49533
+ mtimeMs: Math.max(existing.mtimeMs, file2.mtimeMs),
49534
+ size: Math.max(existing.size, file2.size)
49535
+ });
49536
+ }
49480
49537
  }
49481
49538
  }
49482
49539
  return [...byPath.values()].sort((a, b) => b.mtimeMs - a.mtimeMs).slice(0, discoveryLimit6(scope)).map((file2) => {
@@ -49511,7 +49568,7 @@ function readOpenCodeMessages(root, sessionId) {
49511
49568
  const path = join9(dir, entry);
49512
49569
  let stats;
49513
49570
  try {
49514
- stats = statSync6(path);
49571
+ stats = statSync7(path);
49515
49572
  } catch {
49516
49573
  continue;
49517
49574
  }
@@ -49539,7 +49596,7 @@ function readOpenCodeParts(root, messageId) {
49539
49596
  const path = join9(dir, entry);
49540
49597
  let stats;
49541
49598
  try {
49542
- stats = statSync6(path);
49599
+ stats = statSync7(path);
49543
49600
  } catch {
49544
49601
  continue;
49545
49602
  }
@@ -49666,7 +49723,7 @@ var OpenCodeSource = {
49666
49723
  };
49667
49724
 
49668
49725
  // packages/runtime/src/tail/pi-source.ts
49669
- import { closeSync as closeSync6, existsSync as existsSync10, openSync as openSync6, readdirSync as readdirSync7, readSync as readSync6, statSync as statSync7 } from "fs";
49726
+ import { closeSync as closeSync6, existsSync as existsSync10, openSync as openSync6, readdirSync as readdirSync7, readSync as readSync6, statSync as statSync8 } from "fs";
49670
49727
  import { homedir as homedir10 } from "os";
49671
49728
  import { basename as basename7, join as join10, relative as relative2 } from "path";
49672
49729
  var SOURCE_NAME7 = "pi";
@@ -49821,7 +49878,7 @@ function listRecentPiProjectTranscripts(root, scope) {
49821
49878
  for (const entry of projectDirs) {
49822
49879
  const projectDir = join10(root, entry);
49823
49880
  try {
49824
- if (!statSync7(projectDir).isDirectory())
49881
+ if (!statSync8(projectDir).isDirectory())
49825
49882
  continue;
49826
49883
  } catch {
49827
49884
  continue;
@@ -49829,7 +49886,7 @@ function listRecentPiProjectTranscripts(root, scope) {
49829
49886
  for (const file2 of listJsonlFiles2(projectDir)) {
49830
49887
  const path = join10(projectDir, file2);
49831
49888
  try {
49832
- const stats = statSync7(path);
49889
+ const stats = statSync8(path);
49833
49890
  if (stats.mtimeMs < cutoff)
49834
49891
  continue;
49835
49892
  found.push({ path, mtimeMs: stats.mtimeMs, size: stats.size });
@@ -50011,6 +50068,7 @@ var SHALLOW_DISCOVERY_INTERVAL_MS = readPositiveIntEnv8("OPENSCOUT_TAIL_SHALLOW_
50011
50068
  var DEEP_DISCOVERY_INTERVAL_MS = readPositiveIntEnv8("OPENSCOUT_TAIL_DEEP_DISCOVERY_INTERVAL_MS", 60 * 60000);
50012
50069
  var PER_SESSION_BUFFER_LIMIT = 2000;
50013
50070
  var AGGREGATE_BUFFER_LIMIT = 1e4;
50071
+ var ASSISTANT_BUFFER_LIMIT = 1e4;
50014
50072
  var QUIET_EVENT_COALESCE_WINDOW_MS = readPositiveIntEnv8("OPENSCOUT_TAIL_QUIET_EVENT_COALESCE_WINDOW_MS", 5000);
50015
50073
  var QUIET_EVENT_COALESCE_MAX_KEYS = readPositiveIntEnv8("OPENSCOUT_TAIL_QUIET_EVENT_COALESCE_MAX_KEYS", 2000);
50016
50074
  var RAW_MAX_DEPTH = 5;
@@ -50019,12 +50077,19 @@ var RAW_MAX_ARRAY_ITEMS = 25;
50019
50077
  var RAW_MAX_OBJECT_KEYS = 50;
50020
50078
  var RECENT_TRANSCRIPT_READ_BYTES = 512 * 1024;
50021
50079
  var SESSION_TRANSCRIPT_READ_BYTES = 8 * 1024 * 1024;
50080
+ var RECENT_TRANSCRIPT_KIND_SCAN_READ_BYTES = 32 * 1024 * 1024;
50022
50081
  var RECENT_TRANSCRIPT_LINES_PER_FILE = 200;
50082
+ var RECENT_TRANSCRIPT_KIND_SCAN_MAX_LINES = 65536;
50023
50083
  var RECENT_TRANSCRIPT_MAX_FILES = readPositiveIntEnv8("OPENSCOUT_TAIL_RECENT_TRANSCRIPT_MAX_FILES", 24);
50024
50084
  var NATIVE_TAIL_SOURCES = new Set(["grok", "kimi", "opencode", "cursor"]);
50085
+ var TRANSCRIPT_REPLAY_MEMO_MAX_ENTRIES = readPositiveIntEnv8("OPENSCOUT_TAIL_REPLAY_MEMO_MAX_ENTRIES", 256);
50086
+ var TRANSCRIPT_REPLAY_ACTIVE_GRACE_MS = readPositiveIntEnv8("OPENSCOUT_TAIL_REPLAY_MEMO_ACTIVE_GRACE_MS", 2000);
50087
+ var transcriptReplayMemo = new Map;
50088
+ var transcriptReplayInFlight = new Map;
50025
50089
  var sources = [GrokSource, KimiSource, ClaudeSource, CodexSource, CursorSource, OpenCodeSource, PiSource];
50026
50090
  var watchers = new Map;
50027
50091
  var aggregateBuffer = [];
50092
+ var assistantBuffer = [];
50028
50093
  var perSessionBuffer = new Map;
50029
50094
  var subscribers2 = new Set;
50030
50095
  var knownTranscripts = new Map;
@@ -50232,6 +50297,12 @@ function pushEvent(rawEvent) {
50232
50297
  if (aggregateBuffer.length > AGGREGATE_BUFFER_LIMIT) {
50233
50298
  aggregateBuffer.splice(0, aggregateBuffer.length - AGGREGATE_BUFFER_LIMIT);
50234
50299
  }
50300
+ if (event.kind === "assistant") {
50301
+ assistantBuffer.push(event);
50302
+ if (assistantBuffer.length > ASSISTANT_BUFFER_LIMIT) {
50303
+ assistantBuffer.splice(0, assistantBuffer.length - ASSISTANT_BUFFER_LIMIT);
50304
+ }
50305
+ }
50235
50306
  let bucket = perSessionBuffer.get(event.sessionId);
50236
50307
  if (!bucket) {
50237
50308
  bucket = [];
@@ -50562,14 +50633,16 @@ function subscribeTail(handler) {
50562
50633
  function snapshotRecentEvents(limit = 500) {
50563
50634
  return aggregateBuffer.slice(-limit);
50564
50635
  }
50565
- async function readRecentLiveEvents(limit = 500) {
50636
+ async function readRecentLiveEvents(limit = 500, options) {
50566
50637
  if (watchers.size === 0) {
50567
50638
  scheduleDiscovery("shallow", { pruneMissing: true });
50568
50639
  } else if (!lastDiscovery || Date.now() - lastDiscovery.generatedAt > DISCOVERY_CACHE_MAX_AGE_MS) {
50569
50640
  scheduleDiscovery("hot", { pruneMissing: false });
50570
50641
  }
50571
50642
  pumpAllWatchers();
50572
- return snapshotRecentEvents(limit);
50643
+ const kinds = options?.kinds?.length ? new Set(options.kinds) : null;
50644
+ const source = kinds?.size === 1 && kinds.has("assistant") ? assistantBuffer : aggregateBuffer;
50645
+ return kinds ? source.filter((event) => kinds.has(event.kind)).slice(-limit) : snapshotRecentEvents(limit);
50573
50646
  }
50574
50647
  async function readRecentTranscriptLines(path, maxLines = RECENT_TRANSCRIPT_LINES_PER_FILE, maxBytes = RECENT_TRANSCRIPT_READ_BYTES) {
50575
50648
  let handle = null;
@@ -50594,6 +50667,44 @@ async function readRecentTranscriptLines(path, maxLines = RECENT_TRANSCRIPT_LINE
50594
50667
  await handle?.close().catch(() => {});
50595
50668
  }
50596
50669
  }
50670
+ async function parseRecentTranscriptLineEvents(input) {
50671
+ let fileSize = 0;
50672
+ try {
50673
+ fileSize = (await stat(input.transcriptPath)).size;
50674
+ } catch {
50675
+ return [];
50676
+ }
50677
+ let lineLimit = Math.max(1, input.lineLimit);
50678
+ let readBytes = Math.max(1, Math.min(input.initialReadBytes, input.maxReadBytes));
50679
+ const kindQuota = input.kinds?.size ? Math.max(1, input.kindQuota ?? 1) : null;
50680
+ const maxLines = kindQuota ? Math.max(lineLimit, RECENT_TRANSCRIPT_KIND_SCAN_MAX_LINES) : lineLimit;
50681
+ while (true) {
50682
+ const lines = await readRecentTranscriptLines(input.transcriptPath, lineLimit, readBytes);
50683
+ const parseState = {};
50684
+ const parsed = [];
50685
+ let index = 0;
50686
+ for (const line of lines) {
50687
+ const event = input.source.parseLine(line, {
50688
+ ...input.context,
50689
+ lineOffset: index,
50690
+ state: parseState
50691
+ });
50692
+ index++;
50693
+ if (event)
50694
+ parsed.push(compactEvent(event));
50695
+ }
50696
+ const matchingCount = kindQuota ? parsed.reduce((count, event) => count + (input.kinds.has(event.kind) ? 1 : 0), 0) : 0;
50697
+ const exhaustedFile = readBytes >= fileSize && lines.length < lineLimit;
50698
+ if (!kindQuota || matchingCount >= kindQuota || exhaustedFile)
50699
+ return parsed;
50700
+ const nextLineLimit = Math.min(maxLines, lineLimit * 2);
50701
+ const nextReadBytes = Math.min(input.maxReadBytes, readBytes * 2);
50702
+ if (nextLineLimit === lineLimit && nextReadBytes === readBytes)
50703
+ return parsed;
50704
+ lineLimit = nextLineLimit;
50705
+ readBytes = nextReadBytes;
50706
+ }
50707
+ }
50597
50708
  function rememberTranscriptEvent(events, seenEvents, event, dedupeKey) {
50598
50709
  const compacted = compactEvent(event);
50599
50710
  const key = dedupeKey ?? compacted.id;
@@ -50602,45 +50713,108 @@ function rememberTranscriptEvent(events, seenEvents, event, dedupeKey) {
50602
50713
  seenEvents.add(key);
50603
50714
  events.push(compacted);
50604
50715
  }
50605
- async function appendWatcherTranscriptEvents(events, seenEvents, watcher, perTranscriptLineLimit) {
50716
+ async function memoizedTranscriptReplay(transcriptPath, variant, load, dependency) {
50717
+ const cacheKey = `${transcriptPath}\x00${variant}`;
50718
+ const inFlight = transcriptReplayInFlight.get(cacheKey);
50719
+ if (inFlight)
50720
+ return [...await inFlight];
50721
+ let stats;
50722
+ try {
50723
+ stats = await stat(transcriptPath);
50724
+ } catch {
50725
+ transcriptReplayMemo.delete(cacheKey);
50726
+ return [];
50727
+ }
50728
+ const fingerprint = [
50729
+ stats.size,
50730
+ stats.mtimeMs,
50731
+ dependency?.size ?? "",
50732
+ dependency?.mtimeMs ?? ""
50733
+ ].join(":");
50734
+ const effectiveMtimeMs = Math.max(stats.mtimeMs, dependency?.mtimeMs ?? 0);
50735
+ const cached2 = transcriptReplayMemo.get(cacheKey);
50736
+ const unchanged = cached2 && cached2.fingerprint === fingerprint;
50737
+ if (unchanged) {
50738
+ cached2.staleSinceMs = undefined;
50739
+ return [...cached2.events];
50740
+ }
50741
+ const now = Date.now();
50742
+ if (cached2 && now - effectiveMtimeMs < TRANSCRIPT_REPLAY_ACTIVE_GRACE_MS) {
50743
+ cached2.staleSinceMs ??= now;
50744
+ if (now - cached2.staleSinceMs < TRANSCRIPT_REPLAY_ACTIVE_GRACE_MS) {
50745
+ return [...cached2.events];
50746
+ }
50747
+ }
50748
+ const promise2 = (async () => {
50749
+ const events = await load();
50750
+ transcriptReplayMemo.delete(cacheKey);
50751
+ transcriptReplayMemo.set(cacheKey, {
50752
+ events: [...events],
50753
+ fingerprint
50754
+ });
50755
+ while (transcriptReplayMemo.size > TRANSCRIPT_REPLAY_MEMO_MAX_ENTRIES) {
50756
+ const oldest = transcriptReplayMemo.keys().next().value;
50757
+ if (typeof oldest !== "string")
50758
+ break;
50759
+ transcriptReplayMemo.delete(oldest);
50760
+ }
50761
+ return events;
50762
+ })().finally(() => transcriptReplayInFlight.delete(cacheKey));
50763
+ transcriptReplayInFlight.set(cacheKey, promise2);
50764
+ return [...await promise2];
50765
+ }
50766
+ async function appendWatcherTranscriptEvents(events, seenEvents, watcher, options) {
50606
50767
  const { source, transcript, process: process3, transcriptPath } = watcher;
50607
50768
  if (source.parseFile) {
50608
- const text2 = await readTranscriptText(transcriptPath);
50609
- if (!text2)
50610
- return;
50611
- const parsed = parsedEventsToArray(source.parseFile(text2, {
50612
- process: process3,
50613
- transcript,
50614
- transcriptPath,
50615
- lineOffset: 0,
50616
- state: {}
50617
- }));
50618
- for (const event of parsed) {
50769
+ const readBytes = options?.kinds?.size ? RECENT_TRANSCRIPT_KIND_SCAN_READ_BYTES : RECENT_TRANSCRIPT_READ_BYTES;
50770
+ const parsed2 = await memoizedTranscriptReplay(transcriptPath, `recent:file:${source.name}:${sessionRegistryKey(transcript)}:${readBytes}:${[...options?.kinds ?? []].sort().join(",")}`, async () => {
50771
+ const text2 = await readTranscriptText(transcriptPath, readBytes);
50772
+ if (!text2)
50773
+ return [];
50774
+ return parsedEventsToArray(source.parseFile(text2, {
50775
+ process: process3,
50776
+ transcript,
50777
+ transcriptPath,
50778
+ lineOffset: 0,
50779
+ state: {}
50780
+ }));
50781
+ }, { size: transcript.size, mtimeMs: transcript.mtimeMs });
50782
+ for (const event of parsed2) {
50783
+ if (options?.kinds?.size && !options.kinds.has(event.kind))
50784
+ continue;
50619
50785
  rememberTranscriptEvent(events, seenEvents, event);
50620
50786
  }
50621
50787
  return;
50622
50788
  }
50623
- const lines = await readRecentTranscriptLines(transcriptPath, perTranscriptLineLimit);
50624
- const parseState = {};
50625
- lines.forEach((line, index) => {
50626
- const event = source.parseLine(line, {
50789
+ const lineLimit = options?.perTranscriptLineLimit ?? RECENT_TRANSCRIPT_LINES_PER_FILE;
50790
+ const kindKey = [...options?.kinds ?? []].sort().join(",");
50791
+ const parsed = await memoizedTranscriptReplay(transcriptPath, `recent:lines:${source.name}:${sessionRegistryKey(transcript)}:${lineLimit}:${RECENT_TRANSCRIPT_READ_BYTES}:${kindKey}:${options?.kindQuota ?? ""}`, () => parseRecentTranscriptLineEvents({
50792
+ source,
50793
+ transcriptPath,
50794
+ context: {
50627
50795
  process: process3,
50628
50796
  transcript,
50629
50797
  transcriptPath,
50630
- lineOffset: index,
50631
- state: parseState
50632
- });
50633
- if (!event)
50634
- return;
50635
- const compacted = compactEvent(event);
50798
+ lineOffset: 0,
50799
+ state: {}
50800
+ },
50801
+ lineLimit,
50802
+ initialReadBytes: RECENT_TRANSCRIPT_READ_BYTES,
50803
+ maxReadBytes: options?.kinds?.size ? RECENT_TRANSCRIPT_KIND_SCAN_READ_BYTES : RECENT_TRANSCRIPT_READ_BYTES,
50804
+ kinds: options?.kinds,
50805
+ kindQuota: options?.kindQuota
50806
+ }));
50807
+ for (const event of parsed) {
50808
+ if (options?.kinds?.size && !options.kinds.has(event.kind))
50809
+ continue;
50636
50810
  const eventKey = [
50637
- compacted.source,
50638
- compacted.sessionId,
50639
- compacted.kind,
50640
- compacted.summary
50811
+ event.source,
50812
+ event.sessionId,
50813
+ event.kind,
50814
+ event.summary
50641
50815
  ].join("\x00");
50642
50816
  rememberTranscriptEvent(events, seenEvents, event, eventKey);
50643
- });
50817
+ }
50644
50818
  }
50645
50819
  async function readRecentTranscriptEvents(limit = 50, options) {
50646
50820
  if (watchers.size === 0) {
@@ -50657,24 +50831,34 @@ async function readRecentTranscriptEvents(limit = 50, options) {
50657
50831
  const seenTranscriptPaths = new Set;
50658
50832
  const transcriptReadLimit = Math.min(RECENT_TRANSCRIPT_MAX_FILES, Math.max(12, limit));
50659
50833
  const lineLimit = options?.perTranscriptLineLimit ?? RECENT_TRANSCRIPT_LINES_PER_FILE;
50834
+ const kinds = options?.kinds?.length ? new Set(options.kinds) : null;
50835
+ const kindQuota = kinds ? Math.max(1, options?.perTranscriptKindLimit ?? limit) : undefined;
50660
50836
  const activeWatchers = [...watchers.values()].sort((left, right) => right.transcript.mtimeMs - left.transcript.mtimeMs).slice(0, transcriptReadLimit);
50661
50837
  for (const watcher of activeWatchers) {
50662
50838
  seenTranscriptPaths.add(watcher.transcriptPath);
50663
- await appendWatcherTranscriptEvents(events, seenEvents, watcher, lineLimit);
50839
+ await appendWatcherTranscriptEvents(events, seenEvents, watcher, {
50840
+ perTranscriptLineLimit: lineLimit,
50841
+ kinds,
50842
+ kindQuota
50843
+ });
50664
50844
  }
50665
50845
  if (options?.discovery?.transcripts?.length) {
50666
50846
  const discoveryTranscripts = [...options.discovery.transcripts].filter((transcript) => !seenTranscriptPaths.has(transcript.transcriptPath)).sort((left, right) => right.mtimeMs - left.mtimeMs).slice(0, transcriptReadLimit);
50667
50847
  for (const transcript of discoveryTranscripts) {
50668
- const parsed = await parseTranscriptSessionEvents(transcript, options.discovery.processes, lineLimit);
50848
+ const parsed = await parseTranscriptSessionEvents(transcript, options.discovery.processes, lineLimit, {
50849
+ kinds,
50850
+ kindQuota,
50851
+ initialReadBytes: RECENT_TRANSCRIPT_READ_BYTES
50852
+ });
50669
50853
  for (const event of parsed) {
50670
50854
  rememberTranscriptEvent(events, seenEvents, event);
50671
50855
  }
50672
50856
  seenTranscriptPaths.add(transcript.transcriptPath);
50673
50857
  }
50674
50858
  }
50675
- return events.sort((left, right) => right.ts - left.ts).slice(0, limit);
50859
+ return events.filter((event) => !kinds || kinds.has(event.kind)).sort((left, right) => right.ts - left.ts).slice(0, limit);
50676
50860
  }
50677
- async function parseTranscriptSessionEvents(transcript, processes, limit) {
50861
+ async function parseTranscriptSessionEvents(transcript, processes, limit, options) {
50678
50862
  const source = sources.find((candidate) => candidate.name === transcript.source);
50679
50863
  if (!source)
50680
50864
  return [];
@@ -50686,25 +50870,29 @@ async function parseTranscriptSessionEvents(transcript, processes, limit) {
50686
50870
  lineOffset: 0,
50687
50871
  state: {}
50688
50872
  };
50689
- if (source.parseFile) {
50690
- const text2 = await readTranscriptText(transcript.transcriptPath, SESSION_TRANSCRIPT_READ_BYTES);
50691
- if (!text2)
50692
- return [];
50693
- return parsedEventsToArray(source.parseFile(text2, ctxBase)).map(redactTailEvent).sort((left, right) => left.ts - right.ts).slice(-limit);
50694
- }
50695
50873
  const lineBudget = Math.max(limit, RECENT_TRANSCRIPT_LINES_PER_FILE);
50696
- const lines = await readRecentTranscriptLines(transcript.transcriptPath, lineBudget, SESSION_TRANSCRIPT_READ_BYTES);
50697
- const events = [];
50698
- lines.forEach((line, index) => {
50699
- const event = source.parseLine(line, {
50700
- ...ctxBase,
50701
- lineOffset: index
50702
- });
50703
- if (event) {
50704
- events.push(compactEvent(event));
50874
+ const kindKey = [...options?.kinds ?? []].sort().join(",");
50875
+ const maxReadBytes = options?.kinds?.size ? RECENT_TRANSCRIPT_KIND_SCAN_READ_BYTES : SESSION_TRANSCRIPT_READ_BYTES;
50876
+ const replayVariant = source.parseFile ? `session:file:${source.name}:${sessionRegistryKey(transcript)}:${maxReadBytes}:${kindKey}` : `session:lines:${source.name}:${sessionRegistryKey(transcript)}:${lineBudget}:${maxReadBytes}:${kindKey}:${options?.kindQuota ?? ""}`;
50877
+ const parsed = await memoizedTranscriptReplay(transcript.transcriptPath, replayVariant, async () => {
50878
+ if (source.parseFile) {
50879
+ const text2 = await readTranscriptText(transcript.transcriptPath, maxReadBytes);
50880
+ if (!text2)
50881
+ return [];
50882
+ return parsedEventsToArray(source.parseFile(text2, ctxBase)).map(redactTailEvent);
50705
50883
  }
50706
- });
50707
- return events.sort((left, right) => left.ts - right.ts).slice(-limit);
50884
+ return parseRecentTranscriptLineEvents({
50885
+ source,
50886
+ transcriptPath: transcript.transcriptPath,
50887
+ context: ctxBase,
50888
+ lineLimit: lineBudget,
50889
+ initialReadBytes: options?.initialReadBytes ?? SESSION_TRANSCRIPT_READ_BYTES,
50890
+ maxReadBytes,
50891
+ kinds: options?.kinds,
50892
+ kindQuota: options?.kindQuota
50893
+ });
50894
+ }, source.parseFile ? { size: transcript.size, mtimeMs: transcript.mtimeMs } : undefined);
50895
+ return parsed.filter((event) => !options?.kinds?.size || options.kinds.has(event.kind)).sort((left, right) => left.ts - right.ts).slice(-limit);
50708
50896
  }
50709
50897
  // packages/runtime/src/tail/display.ts
50710
50898
  var GROK_STREAMING_PHASES = new Set([
@@ -50771,7 +50959,7 @@ import { createHash } from "crypto";
50771
50959
  import { homedir as homedir15 } from "os";
50772
50960
 
50773
50961
  // packages/agent-sessions/src/adapters/claude-code/team-topology.ts
50774
- import { existsSync as existsSync11, readdirSync as readdirSync8, readFileSync as readFileSync5, statSync as statSync8 } from "fs";
50962
+ import { existsSync as existsSync11, readdirSync as readdirSync8, readFileSync as readFileSync5, statSync as statSync9 } from "fs";
50775
50963
  import { homedir as homedir11 } from "os";
50776
50964
  import { basename as basename8, dirname as dirname4, join as join11, relative as relative3 } from "path";
50777
50965
  var TOPOLOGY_SCHEMA_VERSION = "openscout.observed-harness-topology.v1";
@@ -50824,14 +51012,14 @@ function readJsonObject(path) {
50824
51012
  }
50825
51013
  function statIsDirectory(path) {
50826
51014
  try {
50827
- return statSync8(path).isDirectory();
51015
+ return statSync9(path).isDirectory();
50828
51016
  } catch {
50829
51017
  return false;
50830
51018
  }
50831
51019
  }
50832
51020
  function statIsFile(path) {
50833
51021
  try {
50834
- return statSync8(path).isFile();
51022
+ return statSync9(path).isFile();
50835
51023
  } catch {
50836
51024
  return false;
50837
51025
  }
@@ -51224,7 +51412,7 @@ function readClaudeAgentTeamTopology(options = {}) {
51224
51412
  }
51225
51413
 
51226
51414
  // packages/agent-sessions/src/adapters/claude-code/subagent-topology.ts
51227
- import { existsSync as existsSync12, readdirSync as readdirSync9, readFileSync as readFileSync6, statSync as statSync9 } from "fs";
51415
+ import { existsSync as existsSync12, readdirSync as readdirSync9, readFileSync as readFileSync6, statSync as statSync10 } from "fs";
51228
51416
  import { homedir as homedir12 } from "os";
51229
51417
  import { join as join12, normalize, sep as sep2 } from "path";
51230
51418
  var TOPOLOGY_SCHEMA_VERSION2 = "openscout.observed-harness-topology.v1";
@@ -51248,21 +51436,21 @@ function sourceRefId2(kind, value) {
51248
51436
  }
51249
51437
  function statIsDirectory2(path) {
51250
51438
  try {
51251
- return statSync9(path).isDirectory();
51439
+ return statSync10(path).isDirectory();
51252
51440
  } catch {
51253
51441
  return false;
51254
51442
  }
51255
51443
  }
51256
51444
  function statIsFile2(path) {
51257
51445
  try {
51258
- return statSync9(path).isFile();
51446
+ return statSync10(path).isFile();
51259
51447
  } catch {
51260
51448
  return false;
51261
51449
  }
51262
51450
  }
51263
51451
  function statMtimeMs(path) {
51264
51452
  try {
51265
- return statSync9(path).mtimeMs;
51453
+ return statSync10(path).mtimeMs;
51266
51454
  } catch {
51267
51455
  return 0;
51268
51456
  }
@@ -51744,7 +51932,7 @@ function readClaudeSubagentTopology(options = {}) {
51744
51932
  }
51745
51933
 
51746
51934
  // packages/agent-sessions/src/adapters/claude-code/workflow-topology.ts
51747
- import { existsSync as existsSync13, readdirSync as readdirSync10, readFileSync as readFileSync7, statSync as statSync10 } from "fs";
51935
+ import { existsSync as existsSync13, readdirSync as readdirSync10, readFileSync as readFileSync7, statSync as statSync11 } from "fs";
51748
51936
  import { homedir as homedir13 } from "os";
51749
51937
  import { basename as basename10, join as join13, normalize as normalize2, relative as relative4, sep as sep3 } from "path";
51750
51938
  var TOPOLOGY_SCHEMA_VERSION3 = "openscout.observed-harness-topology.v1";
@@ -51767,21 +51955,21 @@ function sourceRefId3(kind, value) {
51767
51955
  }
51768
51956
  function statIsDirectory3(path) {
51769
51957
  try {
51770
- return statSync10(path).isDirectory();
51958
+ return statSync11(path).isDirectory();
51771
51959
  } catch {
51772
51960
  return false;
51773
51961
  }
51774
51962
  }
51775
51963
  function statIsFile3(path) {
51776
51964
  try {
51777
- return statSync10(path).isFile();
51965
+ return statSync11(path).isFile();
51778
51966
  } catch {
51779
51967
  return false;
51780
51968
  }
51781
51969
  }
51782
51970
  function statMtimeMs2(path) {
51783
51971
  try {
51784
- return statSync10(path).mtimeMs;
51972
+ return statSync11(path).mtimeMs;
51785
51973
  } catch {
51786
51974
  return 0;
51787
51975
  }
@@ -52469,7 +52657,7 @@ function readClaudeWorkflowTopology(options = {}) {
52469
52657
  }
52470
52658
 
52471
52659
  // packages/agent-sessions/src/adapters/codex/topology.ts
52472
- import { existsSync as existsSync14, readdirSync as readdirSync11, readFileSync as readFileSync8, statSync as statSync11 } from "fs";
52660
+ import { existsSync as existsSync14, readdirSync as readdirSync11, readFileSync as readFileSync8, statSync as statSync12 } from "fs";
52473
52661
  import { homedir as homedir14 } from "os";
52474
52662
  import { basename as basename11, join as join14 } from "path";
52475
52663
  var TOPOLOGY_SCHEMA_VERSION4 = "openscout.observed-harness-topology.v1";
@@ -52496,14 +52684,14 @@ function sourceRefId4(kind, value) {
52496
52684
  }
52497
52685
  function statIsDirectory4(path) {
52498
52686
  try {
52499
- return statSync11(path).isDirectory();
52687
+ return statSync12(path).isDirectory();
52500
52688
  } catch {
52501
52689
  return false;
52502
52690
  }
52503
52691
  }
52504
52692
  function statIsFile4(path) {
52505
52693
  try {
52506
- return statSync11(path).isFile();
52694
+ return statSync12(path).isFile();
52507
52695
  } catch {
52508
52696
  return false;
52509
52697
  }
@@ -52914,7 +53102,12 @@ class CodexObservedTopologyTracker {
52914
53102
 
52915
53103
  // packages/runtime/src/harness-topology/service.ts
52916
53104
  var DEFAULT_POLL_INTERVAL_MS = readPositiveIntEnv9("OPENSCOUT_TOPOLOGY_POLL_INTERVAL_MS", 1e4);
53105
+ var DEFAULT_MIN_SCAN_INTERVAL_MS = 15000;
52917
53106
  var EVENT_BUFFER_LIMIT = 500;
53107
+ function minScanIntervalMs() {
53108
+ const raw = Number.parseInt(process.env.SCOUT_TOPOLOGY_MIN_SCAN_INTERVAL_MS ?? "", 10);
53109
+ return Number.isFinite(raw) && raw >= 0 ? raw : DEFAULT_MIN_SCAN_INTERVAL_MS;
53110
+ }
52918
53111
  function readPositiveIntEnv9(name, fallback) {
52919
53112
  const raw = Number.parseInt(process.env[name] ?? "", 10);
52920
53113
  return Number.isFinite(raw) && raw > 0 ? raw : fallback;
@@ -53016,6 +53209,7 @@ class HarnessTopologyObserver {
53016
53209
  scanInFlight = null;
53017
53210
  eventCounter = 0;
53018
53211
  lastSnapshot = null;
53212
+ lastScanCompletedAt = 0;
53019
53213
  constructor(options = {}) {
53020
53214
  this.options = options;
53021
53215
  }
@@ -53027,16 +53221,28 @@ class HarnessTopologyObserver {
53027
53221
  });
53028
53222
  return this.scanInFlight;
53029
53223
  }
53224
+ scanThrottled() {
53225
+ if (this.scanInFlight)
53226
+ return this.scanInFlight;
53227
+ const interval = minScanIntervalMs();
53228
+ if (this.lastSnapshot && interval > 0 && Date.now() - this.lastScanCompletedAt < interval) {
53229
+ return Promise.resolve(this.lastSnapshot);
53230
+ }
53231
+ return this.scan();
53232
+ }
53030
53233
  async getSnapshot(force = false) {
53031
- if (force || !this.lastSnapshot) {
53234
+ if (force) {
53032
53235
  return this.scan();
53033
53236
  }
53237
+ if (!this.lastSnapshot) {
53238
+ return this.scanThrottled();
53239
+ }
53034
53240
  return this.lastSnapshot;
53035
53241
  }
53036
53242
  subscribe(handler) {
53037
53243
  this.subscribers.add(handler);
53038
53244
  this.ensureLoopRunning();
53039
- this.scan();
53245
+ this.scanThrottled();
53040
53246
  return () => {
53041
53247
  this.subscribers.delete(handler);
53042
53248
  if (this.subscribers.size === 0) {
@@ -53084,6 +53290,7 @@ class HarnessTopologyObserver {
53084
53290
  });
53085
53291
  }
53086
53292
  this.lastSnapshot = this.buildSnapshot(nowMs2);
53293
+ this.lastScanCompletedAt = Date.now();
53087
53294
  return this.lastSnapshot;
53088
53295
  }
53089
53296
  buildSnapshot(generatedAt) {
@@ -53127,7 +53334,7 @@ class HarnessTopologyObserver {
53127
53334
  if (this.timer)
53128
53335
  return;
53129
53336
  this.timer = setInterval(() => {
53130
- this.scan();
53337
+ this.scanThrottled();
53131
53338
  }, this.options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS);
53132
53339
  }
53133
53340
  stopLoop() {
@@ -53148,7 +53355,7 @@ function snapshotRecentHarnessTopologyEvents(limit = EVENT_BUFFER_LIMIT) {
53148
53355
  return defaultObserver.snapshotRecentEvents(limit);
53149
53356
  }
53150
53357
  function nudgeHarnessTopologyScan() {
53151
- return defaultObserver.scan();
53358
+ return defaultObserver.getSnapshot(true);
53152
53359
  }
53153
53360
  // packages/runtime/src/broker-trpc-router.ts
53154
53361
  var t = initTRPC.create();
@@ -53367,41 +53574,28 @@ var controlRouter = t.router({
53367
53574
  events: t.procedure.input(controlEventsInput).subscription(async function* ({ input, signal }) {
53368
53575
  const kinds = input?.kinds;
53369
53576
  const filter = kinds && kinds.length > 0 ? new Set(kinds) : null;
53370
- const liveIterator = controlEventIterable(kinds, signal)[Symbol.asyncIterator]();
53371
- const replayedIds = new Set;
53372
- try {
53373
- const backlog = snapshotRecentControlEvents(CONTROL_BACKLOG_LIMIT);
53374
- let startIdx = 0;
53375
- if (input?.since) {
53376
- const idx = backlog.findIndex((event) => event.id === input.since);
53377
- if (idx >= 0)
53378
- startIdx = idx + 1;
53379
- }
53380
- for (let i = startIdx;i < backlog.length; i++) {
53381
- const event = backlog[i];
53382
- if (!event)
53383
- continue;
53384
- if (filter && !filter.has(event.kind))
53385
- continue;
53386
- replayedIds.add(event.id);
53387
- yield tracked(event.id, event);
53388
- }
53389
- for (const event of snapshotPresenceControlEvents()) {
53390
- if (filter && !filter.has(event.kind))
53391
- continue;
53392
- replayedIds.add(event.id);
53393
- yield tracked(event.id, event);
53394
- }
53395
- while (true) {
53396
- const next = await liveIterator.next();
53397
- if (next.done)
53398
- return;
53399
- if (replayedIds.delete(next.value.id))
53400
- continue;
53401
- yield tracked(next.value.id, next.value);
53402
- }
53403
- } finally {
53404
- await liveIterator.return?.();
53577
+ const backlog = snapshotRecentControlEvents(CONTROL_BACKLOG_LIMIT);
53578
+ let startIdx = 0;
53579
+ if (input?.since) {
53580
+ const idx = backlog.findIndex((event) => event.id === input.since);
53581
+ if (idx >= 0)
53582
+ startIdx = idx + 1;
53583
+ }
53584
+ for (let i = startIdx;i < backlog.length; i++) {
53585
+ const event = backlog[i];
53586
+ if (!event)
53587
+ continue;
53588
+ if (filter && !filter.has(event.kind))
53589
+ continue;
53590
+ yield tracked(event.id, event);
53591
+ }
53592
+ for (const event of snapshotPresenceControlEvents()) {
53593
+ if (filter && !filter.has(event.kind))
53594
+ continue;
53595
+ yield tracked(event.id, event);
53596
+ }
53597
+ for await (const event of controlEventIterable(kinds, signal)) {
53598
+ yield tracked(event.id, event);
53405
53599
  }
53406
53600
  })
53407
53601
  });
@@ -53636,18 +53830,20 @@ function activeCollaboration(record3) {
53636
53830
  }
53637
53831
  function queryRuntimeRegistrySnapshot(snapshot, query = {}) {
53638
53832
  const since = finiteTimestamp(query.since);
53639
- if (since === null) {
53833
+ const conversationScoped = query.scope === "conversations";
53834
+ if (since === null && !conversationScoped) {
53640
53835
  return snapshot;
53641
53836
  }
53642
- const messages = Object.values(snapshot.messages).filter((message) => message.createdAt >= since);
53643
- const recentInvocationIds = new Set(Object.values(snapshot.invocations).filter((invocation) => invocation.createdAt >= since).map((invocation) => invocation.id));
53644
- const flights = Object.values(snapshot.flights).filter((flight) => ACTIVE_FLIGHT_STATES.has(flight.state) || recordTimestamp(flight) >= since || recentInvocationIds.has(flight.invocationId));
53837
+ const cutoff = since ?? 0;
53838
+ const messages = Object.values(snapshot.messages).filter((message) => message.createdAt >= cutoff);
53839
+ const recentInvocationIds = new Set(Object.values(snapshot.invocations).filter((invocation) => invocation.createdAt >= cutoff).map((invocation) => invocation.id));
53840
+ const flights = Object.values(snapshot.flights).filter((flight) => ACTIVE_FLIGHT_STATES.has(flight.state) || recordTimestamp(flight) >= cutoff || recentInvocationIds.has(flight.invocationId));
53645
53841
  const retainedInvocationIds = new Set([
53646
53842
  ...recentInvocationIds,
53647
53843
  ...flights.map((flight) => flight.invocationId)
53648
53844
  ]);
53649
53845
  const invocations = Object.values(snapshot.invocations).filter((invocation) => retainedInvocationIds.has(invocation.id));
53650
- const collaborationRecords = Object.values(snapshot.collaborationRecords).filter((record3) => activeCollaboration(record3) || record3.updatedAt >= since);
53846
+ const collaborationRecords = Object.values(snapshot.collaborationRecords).filter((record3) => activeCollaboration(record3) || record3.updatedAt >= cutoff);
53651
53847
  const conversationIds = new Set;
53652
53848
  for (const message of messages)
53653
53849
  conversationIds.add(message.conversationId);
@@ -53661,7 +53857,7 @@ function queryRuntimeRegistrySnapshot(snapshot, query = {}) {
53661
53857
  }
53662
53858
  for (const conversation of Object.values(snapshot.conversations)) {
53663
53859
  const timestamp = recordTimestamp(conversation);
53664
- if (timestamp === 0 || timestamp >= since)
53860
+ if (timestamp === 0 || timestamp >= cutoff)
53665
53861
  conversationIds.add(conversation.id);
53666
53862
  }
53667
53863
  const conversations = [];
@@ -53677,22 +53873,52 @@ function queryRuntimeRegistrySnapshot(snapshot, query = {}) {
53677
53873
  pendingConversationIds.push(conversation.parentConversationId);
53678
53874
  }
53679
53875
  }
53876
+ let scopedInvocations = invocations;
53877
+ let scopedFlights = flights;
53878
+ if (conversationScoped) {
53879
+ const activeFlightInvocationIds = new Set(flights.filter((flight) => ACTIVE_FLIGHT_STATES.has(flight.state)).map((flight) => flight.invocationId));
53880
+ const newestByConversation = new Map;
53881
+ for (const invocation of invocations) {
53882
+ const conversationId = invocation.conversationId;
53883
+ if (!conversationId || !conversationIds.has(conversationId))
53884
+ continue;
53885
+ const bucket = newestByConversation.get(conversationId) ?? [];
53886
+ bucket.push(invocation);
53887
+ newestByConversation.set(conversationId, bucket);
53888
+ }
53889
+ scopedInvocations = [...newestByConversation.values()].flatMap((bucket) => {
53890
+ const sorted = bucket.sort((left, right) => right.createdAt - left.createdAt);
53891
+ const selected = sorted.slice(0, 12);
53892
+ const selectedIds = new Set(selected.map((invocation) => invocation.id));
53893
+ for (const invocation of sorted) {
53894
+ if (activeFlightInvocationIds.has(invocation.id) && !selectedIds.has(invocation.id)) {
53895
+ selected.push(invocation);
53896
+ selectedIds.add(invocation.id);
53897
+ }
53898
+ }
53899
+ return selected;
53900
+ });
53901
+ const scopedInvocationIds = new Set(scopedInvocations.map((invocation) => invocation.id));
53902
+ scopedFlights = flights.filter((flight) => scopedInvocationIds.has(flight.invocationId));
53903
+ }
53680
53904
  const actorIds = new Set;
53681
53905
  const agentIds = new Set;
53682
- for (const agent of Object.values(snapshot.agents)) {
53683
- if (currentAgent(agent))
53684
- agentIds.add(agent.id);
53906
+ const currentEndpointAgentIds = new Set(Object.values(snapshot.endpoints).filter((endpoint) => currentOrRecentEndpoint(endpoint, cutoff)).map((endpoint) => endpoint.agentId));
53907
+ for (const conversation of conversations) {
53908
+ const keepWholeRoster = !conversationScoped || conversation.kind === "direct" || conversation.kind === "group_direct";
53909
+ for (const [index, participantId] of conversation.participantIds.entries()) {
53910
+ if (keepWholeRoster || index < 32 || snapshot.actors[participantId]?.kind === "person" || currentEndpointAgentIds.has(participantId)) {
53911
+ actorIds.add(participantId);
53912
+ }
53913
+ }
53685
53914
  }
53686
- const endpoints = Object.values(snapshot.endpoints).filter((endpoint) => currentOrRecentEndpoint(endpoint, since));
53687
- for (const endpoint of endpoints)
53688
- agentIds.add(endpoint.agentId);
53689
53915
  for (const message of messages)
53690
53916
  actorIds.add(message.actorId);
53691
- for (const invocation of invocations) {
53917
+ for (const invocation of scopedInvocations) {
53692
53918
  actorIds.add(invocation.requesterId);
53693
53919
  agentIds.add(invocation.targetAgentId);
53694
53920
  }
53695
- for (const flight of flights) {
53921
+ for (const flight of scopedFlights) {
53696
53922
  actorIds.add(flight.requesterId);
53697
53923
  agentIds.add(flight.targetAgentId);
53698
53924
  }
@@ -53703,10 +53929,19 @@ function queryRuntimeRegistrySnapshot(snapshot, query = {}) {
53703
53929
  if (record3.nextMoveOwnerId)
53704
53930
  actorIds.add(record3.nextMoveOwnerId);
53705
53931
  }
53706
- for (const conversation of conversations) {
53707
- for (const participantId of conversation.participantIds)
53708
- actorIds.add(participantId);
53932
+ if (!conversationScoped) {
53933
+ for (const agent of Object.values(snapshot.agents)) {
53934
+ if (currentAgent(agent))
53935
+ agentIds.add(agent.id);
53936
+ }
53709
53937
  }
53938
+ for (const actorId of actorIds) {
53939
+ if (snapshot.agents[actorId])
53940
+ agentIds.add(actorId);
53941
+ }
53942
+ const endpoints = Object.values(snapshot.endpoints).filter((endpoint) => currentOrRecentEndpoint(endpoint, cutoff) && (!conversationScoped || agentIds.has(endpoint.agentId) || actorIds.has(endpoint.agentId)));
53943
+ for (const endpoint of endpoints)
53944
+ agentIds.add(endpoint.agentId);
53710
53945
  for (const agentId of agentIds)
53711
53946
  actorIds.add(agentId);
53712
53947
  const agents = Object.values(snapshot.agents).filter((agent) => agentIds.has(agent.id) || actorIds.has(agent.id));
@@ -53725,8 +53960,8 @@ function queryRuntimeRegistrySnapshot(snapshot, query = {}) {
53725
53960
  bindings: recordById(Object.values(snapshot.bindings).filter((binding) => conversationIds.has(binding.conversationId))),
53726
53961
  messages: recordById(messages),
53727
53962
  readCursors: Object.fromEntries(Object.entries(snapshot.readCursors).filter(([, cursor]) => conversationIds.has(cursor.conversationId))),
53728
- invocations: recordById(invocations),
53729
- flights: recordById(flights),
53963
+ invocations: recordById(scopedInvocations),
53964
+ flights: recordById(scopedFlights),
53730
53965
  collaborationRecords: recordById(collaborationRecords)
53731
53966
  });
53732
53967
  }
@@ -54844,12 +55079,9 @@ function isTransportInferredStall(status) {
54844
55079
  class BrokerPresenceService {
54845
55080
  deps;
54846
55081
  presence;
54847
- lastPublished = new Map;
54848
- refreshIntervalMs;
54849
55082
  constructor(deps) {
54850
55083
  this.deps = deps;
54851
55084
  this.presence = new BrokerPresenceMap(deps.map);
54852
- this.refreshIntervalMs = Math.max(1, deps.refreshIntervalMs ?? PRESENCE_REFRESH_INTERVAL_MS);
54853
55085
  }
54854
55086
  snapshot(now = this.now()) {
54855
55087
  return this.presence.snapshot(now);
@@ -54873,23 +55105,16 @@ class BrokerPresenceService {
54873
55105
  needRef: needRefForStatus(status),
54874
55106
  boundConversationId: boundConversationIdForStatus(status, snapshot)
54875
55107
  }, now);
54876
- if (!result)
55108
+ if (!result?.transitioned)
54877
55109
  continue;
54878
- const lastPublished = this.lastPublished.get(agentId);
54879
- const refreshDue = !result.transitioned && lastPublished !== undefined && result.beat.updatedAt > lastPublished.updatedAt && now - lastPublished.at >= this.refreshIntervalMs;
54880
- if (!result.transitioned && !refreshDue)
54881
- continue;
54882
- this.deps.publish(this.presenceEvent(result.beat, result.transitioned ? result.previousActivity : undefined, now));
54883
- this.lastPublished.set(agentId, { at: now, updatedAt: result.beat.updatedAt });
55110
+ this.deps.publish(this.presenceEvent(result.beat, result.previousActivity, now));
54884
55111
  published += 1;
54885
55112
  }
54886
- this.forgetPublished(this.presence.prune(now));
55113
+ this.presence.prune(now);
54887
55114
  return published;
54888
55115
  }
54889
55116
  sweep(now = this.now()) {
54890
- const dropped = this.presence.prune(now);
54891
- this.forgetPublished(dropped);
54892
- return dropped;
55117
+ return this.presence.prune(now);
54893
55118
  }
54894
55119
  presenceEvent(beat, previousActivity, now) {
54895
55120
  return {
@@ -54904,10 +55129,6 @@ class BrokerPresenceService {
54904
55129
  now() {
54905
55130
  return this.deps.now?.() ?? Date.now();
54906
55131
  }
54907
- forgetPublished(agentIds) {
54908
- for (const agentId of agentIds)
54909
- this.lastPublished.delete(agentId);
54910
- }
54911
55132
  }
54912
55133
  function needRefForStatus(status) {
54913
55134
  if (status.subjectKind !== "question")
@@ -55058,7 +55279,7 @@ class BrokerDeliveryStore {
55058
55279
  // packages/runtime/src/broker-journal.ts
55059
55280
  import { once as once2 } from "events";
55060
55281
  import { createReadStream, createWriteStream } from "fs";
55061
- import { appendFile, mkdir, rename, unlink } from "fs/promises";
55282
+ import { appendFile, mkdir, rename, stat as stat2, unlink } from "fs/promises";
55062
55283
  import { dirname as dirname6 } from "path";
55063
55284
  import { createInterface } from "readline";
55064
55285
  function cloneSnapshot(snapshot) {
@@ -55146,19 +55367,30 @@ class FileBackedBrokerJournal {
55146
55367
  scoutDispatches: []
55147
55368
  };
55148
55369
  loaded = false;
55370
+ latestLoadReport = null;
55149
55371
  writeQueue = Promise.resolve();
55150
55372
  constructor(filePath) {
55151
55373
  this.filePath = filePath;
55152
55374
  }
55153
55375
  async load() {
55154
55376
  if (this.loaded) {
55155
- return;
55377
+ return this.latestLoadReport;
55156
55378
  }
55379
+ const startedAt = Date.now();
55380
+ const sourceBytes = await stat2(this.filePath).then((value) => value.size).catch((error48) => {
55381
+ const code = error48 && typeof error48 === "object" && "code" in error48 ? error48.code : undefined;
55382
+ if (code === "ENOENT")
55383
+ return 0;
55384
+ throw error48;
55385
+ });
55157
55386
  const latestIndexByKey = new Map;
55158
55387
  const lastFlightById = new Map;
55388
+ const countsByKind = {};
55159
55389
  let compactionRequired = false;
55160
- await this.visitEntries((entry, index) => {
55390
+ const scanStartedAt = Date.now();
55391
+ const scan = await this.visitEntries((entry, index) => {
55161
55392
  this.apply(entry);
55393
+ countsByKind[entry.kind] = (countsByKind[entry.kind] ?? 0) + 1;
55162
55394
  const key = dedupeKey(entry);
55163
55395
  if (key) {
55164
55396
  if (latestIndexByKey.has(key)) {
@@ -55174,10 +55406,37 @@ class FileBackedBrokerJournal {
55174
55406
  lastFlightById.set(entry.flight.id, entry.flight);
55175
55407
  }
55176
55408
  });
55409
+ const scanMs = Date.now() - scanStartedAt;
55410
+ let compactionMs = 0;
55177
55411
  if (compactionRequired) {
55412
+ const compactionStartedAt = Date.now();
55178
55413
  await this.rewriteCompactedEntries(latestIndexByKey);
55414
+ compactionMs = Date.now() - compactionStartedAt;
55179
55415
  }
55180
55416
  this.loaded = true;
55417
+ const completedAt = Date.now();
55418
+ const compactedBytes = await stat2(this.filePath).then((value) => value.size).catch(() => 0);
55419
+ this.latestLoadReport = {
55420
+ startedAt,
55421
+ completedAt,
55422
+ totalMs: completedAt - startedAt,
55423
+ scanMs,
55424
+ compactionMs,
55425
+ sourceBytes,
55426
+ compactedBytes,
55427
+ validEntries: scan.validEntries,
55428
+ invalidLines: scan.invalidLines,
55429
+ blankLines: scan.blankLines,
55430
+ compactionRequired,
55431
+ countsByKind
55432
+ };
55433
+ return this.latestLoadReport;
55434
+ }
55435
+ loadReport() {
55436
+ return this.latestLoadReport ? {
55437
+ ...this.latestLoadReport,
55438
+ countsByKind: { ...this.latestLoadReport.countsByKind }
55439
+ } : null;
55181
55440
  }
55182
55441
  async readEntries() {
55183
55442
  const entries = [];
@@ -55186,8 +55445,27 @@ class FileBackedBrokerJournal {
55186
55445
  });
55187
55446
  return entries;
55188
55447
  }
55189
- async replay(visitor) {
55190
- await this.visitEntries((entry) => visitor(entry));
55448
+ captureReplayBoundary() {
55449
+ let boundary = { endByteExclusive: 0 };
55450
+ const capture = this.writeQueue.then(async () => {
55451
+ boundary = {
55452
+ endByteExclusive: await stat2(this.filePath).then((value) => value.size).catch((error48) => {
55453
+ const code = error48 && typeof error48 === "object" && "code" in error48 ? error48.code : undefined;
55454
+ if (code === "ENOENT")
55455
+ return 0;
55456
+ throw error48;
55457
+ })
55458
+ };
55459
+ });
55460
+ this.writeQueue = capture.then(() => {
55461
+ return;
55462
+ }, () => {
55463
+ return;
55464
+ });
55465
+ return capture.then(() => boundary);
55466
+ }
55467
+ async replay(visitor, boundary) {
55468
+ await this.visitEntries((entry) => visitor(entry), boundary ? { endByteExclusive: boundary.endByteExclusive } : {});
55191
55469
  }
55192
55470
  snapshot() {
55193
55471
  return cloneSnapshot(this.state.snapshot);
@@ -55255,17 +55533,43 @@ class FileBackedBrokerJournal {
55255
55533
  const limit = options.limit ?? 1000;
55256
55534
  return [...this.state.invocationDispatchJobs.values()].filter((job) => !options.state || job.state === options.state).sort((left, right) => left.createdAt - right.createdAt).slice(0, limit);
55257
55535
  }
55258
- async visitEntries(visitor) {
55259
- const input = createReadStream(this.filePath, { encoding: "utf8" });
55536
+ async visitEntries(visitor, options = {}) {
55537
+ const endByteExclusive = options.endByteExclusive;
55538
+ if (endByteExclusive !== undefined && endByteExclusive <= 0) {
55539
+ return {
55540
+ rawLines: 0,
55541
+ validEntries: 0,
55542
+ invalidLines: 0,
55543
+ blankLines: 0
55544
+ };
55545
+ }
55546
+ const input = createReadStream(this.filePath, {
55547
+ encoding: "utf8",
55548
+ ...endByteExclusive === undefined ? {} : { end: endByteExclusive - 1 }
55549
+ });
55260
55550
  const lines = createInterface({ input, crlfDelay: Infinity });
55261
55551
  let index = 0;
55552
+ const report = {
55553
+ rawLines: 0,
55554
+ validEntries: 0,
55555
+ invalidLines: 0,
55556
+ blankLines: 0
55557
+ };
55262
55558
  try {
55263
55559
  for await (const rawLine of lines) {
55560
+ report.rawLines += 1;
55561
+ if (!rawLine.trim()) {
55562
+ report.blankLines += 1;
55563
+ continue;
55564
+ }
55264
55565
  const entry = parseEntry(rawLine);
55265
- if (!entry)
55566
+ if (!entry) {
55567
+ report.invalidLines += 1;
55266
55568
  continue;
55569
+ }
55267
55570
  await visitor(entry, index);
55268
55571
  index += 1;
55572
+ report.validEntries += 1;
55269
55573
  }
55270
55574
  } catch (error48) {
55271
55575
  const code = error48 && typeof error48 === "object" && "code" in error48 ? error48.code : undefined;
@@ -55276,6 +55580,7 @@ class FileBackedBrokerJournal {
55276
55580
  lines.close();
55277
55581
  input.destroy();
55278
55582
  }
55583
+ return report;
55279
55584
  }
55280
55585
  async rewriteCompactedEntries(latestIndexByKey) {
55281
55586
  await mkdir(dirname6(this.filePath), { recursive: true });
@@ -55538,18 +55843,18 @@ class BrokerDurableRecordStore {
55538
55843
  constructor(options) {
55539
55844
  this.options = options;
55540
55845
  }
55541
- upsertNode = async (node) => {
55846
+ upsertNode = async (node, options = {}) => {
55542
55847
  await this.options.durableStore.runWrite(async () => {
55543
55848
  await this.options.durableStore.commitEntries({ kind: "node.upsert", node }, async () => {
55544
55849
  await this.options.runtime.upsertNode(node);
55545
- });
55850
+ }, options);
55546
55851
  });
55547
55852
  };
55548
- upsertActor = async (actor) => {
55853
+ upsertActor = async (actor, options = {}) => {
55549
55854
  await this.options.durableStore.runWrite(async () => {
55550
55855
  await this.options.durableStore.commitEntries({ kind: "actor.upsert", actor }, async () => {
55551
55856
  await this.options.runtime.upsertActor(actor);
55552
- });
55857
+ }, options);
55553
55858
  });
55554
55859
  };
55555
55860
  upsertAgent = async (agent) => {
@@ -55700,6 +56005,41 @@ class BrokerDurableStore {
55700
56005
  };
55701
56006
  }
55702
56007
 
56008
+ // packages/runtime/src/broker-startup-traffic-gate.ts
56009
+ var RESTORING_READ_PATHS = new Set([
56010
+ "/health",
56011
+ "/v1/home",
56012
+ "/v1/node",
56013
+ "/v1/snapshot"
56014
+ ]);
56015
+
56016
+ class BrokerStartupTrafficGate {
56017
+ mutationsAdmitted = false;
56018
+ admits(method, requestTarget = "/") {
56019
+ if (this.mutationsAdmitted) {
56020
+ return true;
56021
+ }
56022
+ const normalizedMethod = (method ?? "GET").toUpperCase();
56023
+ if (normalizedMethod === "OPTIONS") {
56024
+ return true;
56025
+ }
56026
+ if (normalizedMethod !== "GET" && normalizedMethod !== "HEAD") {
56027
+ return false;
56028
+ }
56029
+ const path = requestTarget.split("?", 1)[0] || "/";
56030
+ return RESTORING_READ_PATHS.has(path);
56031
+ }
56032
+ admitMutations() {
56033
+ this.mutationsAdmitted = true;
56034
+ }
56035
+ snapshot() {
56036
+ return {
56037
+ state: this.mutationsAdmitted ? "ready" : "restoring",
56038
+ mutationsAdmitted: this.mutationsAdmitted
56039
+ };
56040
+ }
56041
+ }
56042
+
55703
56043
  // packages/runtime/src/broker-read-cursor-store.ts
55704
56044
  function finitePositiveNumber(value) {
55705
56045
  if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
@@ -56125,7 +56465,7 @@ class BrokerWorkItemStore {
56125
56465
  // packages/runtime/src/local-agents.ts
56126
56466
  import { randomUUID as randomUUID3 } from "crypto";
56127
56467
  import { existsSync as existsSync34, readFileSync as readFileSync18 } from "fs";
56128
- import { mkdir as mkdir9, readFile as readFile9, rm as rm4, stat as stat6, writeFile as writeFile7 } from "fs/promises";
56468
+ import { mkdir as mkdir9, readFile as readFile9, rm as rm4, stat as stat7, writeFile as writeFile7 } from "fs/promises";
56129
56469
  import { basename as basename16, dirname as dirname20, join as join37, resolve as resolve11 } from "path";
56130
56470
  import { fileURLToPath as fileURLToPath6 } from "url";
56131
56471
 
@@ -56766,7 +57106,7 @@ async function requestJsonWithBun2(connect, socketPath, payload, timeoutMs) {
56766
57106
  }
56767
57107
 
56768
57108
  // packages/runtime/src/system-probes/git-build-info.ts
56769
- import { existsSync as existsSync16, realpathSync, statSync as statSync12 } from "fs";
57109
+ import { existsSync as existsSync16, realpathSync, statSync as statSync13 } from "fs";
56770
57110
  import { dirname as dirname8, resolve as resolve2 } from "path";
56771
57111
  var staticMetadataByRepo = new Map;
56772
57112
  function realpathOrResolved(path) {
@@ -56779,8 +57119,8 @@ function realpathOrResolved(path) {
56779
57119
  function directoryOrParent(path) {
56780
57120
  const resolved = resolve2(path);
56781
57121
  try {
56782
- const stat2 = statSync12(resolved);
56783
- return stat2.isDirectory() ? resolved : dirname8(resolved);
57122
+ const stat3 = statSync13(resolved);
57123
+ return stat3.isDirectory() ? resolved : dirname8(resolved);
56784
57124
  } catch {
56785
57125
  return resolved;
56786
57126
  }
@@ -57776,7 +58116,7 @@ var herdrSessionsProbe = defineProbeFamily({
57776
58116
  var herdrTopologyCache = new Map;
57777
58117
  // packages/runtime/src/system-probes/sessions.ts
57778
58118
  import { createReadStream as createReadStream2 } from "fs";
57779
- import { readdir, stat as stat2 } from "fs/promises";
58119
+ import { readdir, stat as stat3 } from "fs/promises";
57780
58120
  import { homedir as homedir18 } from "os";
57781
58121
  import { basename as basename12, dirname as dirname9, join as join17, resolve as resolve3 } from "path";
57782
58122
  import { createInterface as createInterface2 } from "readline";
@@ -57822,7 +58162,7 @@ function detectAgent(filePath, fallback = "unknown") {
57822
58162
  }
57823
58163
  async function directoryExists(path) {
57824
58164
  try {
57825
- return (await stat2(path)).isDirectory();
58165
+ return (await stat3(path)).isDirectory();
57826
58166
  } catch {
57827
58167
  return false;
57828
58168
  }
@@ -57851,7 +58191,7 @@ async function scanJsonlFiles(input) {
57851
58191
  if (!entry.isFile() || !entry.name.endsWith(".jsonl"))
57852
58192
  continue;
57853
58193
  try {
57854
- const info = await stat2(filePath);
58194
+ const info = await stat3(filePath);
57855
58195
  if (!info.isFile() || info.mtimeMs < input.cutoffMs)
57856
58196
  continue;
57857
58197
  out.push({
@@ -61346,7 +61686,7 @@ class SessionRegistry {
61346
61686
 
61347
61687
  // packages/agent-sessions/src/local/transports/codex-app-server.ts
61348
61688
  import { spawn as spawn4 } from "child_process";
61349
- import { appendFile as appendFile2, mkdir as mkdir3, readFile as readFile3, rm, stat as stat3, writeFile as writeFile2 } from "fs/promises";
61689
+ import { appendFile as appendFile2, mkdir as mkdir3, readFile as readFile3, rm, stat as stat4, writeFile as writeFile2 } from "fs/promises";
61350
61690
  import { join as join23 } from "path";
61351
61691
 
61352
61692
  // packages/agent-sessions/src/codex-launch-config.ts
@@ -61521,6 +61861,21 @@ class CodexAppServerRequesterTimeoutError extends Error {
61521
61861
  this.timeoutMs = input.timeoutMs;
61522
61862
  }
61523
61863
  }
61864
+
61865
+ class CodexThreadHeldExternallyError extends Error {
61866
+ code = "CODEX_THREAD_HELD_EXTERNALLY";
61867
+ threadId;
61868
+ agentName;
61869
+ constructor(input) {
61870
+ super(`Codex thread ${input.threadId} is open in another application` + (input.detail ? ` (${input.detail})` : "") + "; it will accept turns once that application releases it.");
61871
+ this.name = "CodexThreadHeldExternallyError";
61872
+ this.threadId = input.threadId;
61873
+ this.agentName = input.agentName;
61874
+ }
61875
+ }
61876
+ function isCodexThreadHeldExternallyError(error48) {
61877
+ return error48 instanceof CodexThreadHeldExternallyError || Boolean(error48 && typeof error48 === "object" && error48.code === "CODEX_THREAD_HELD_EXTERNALLY");
61878
+ }
61524
61879
  function codexAppServerExitMessage(input) {
61525
61880
  if (input.exitKind === "proactive_shutdown") {
61526
61881
  return `Codex app-server session for ${input.agentName} was stopped by OpenScout` + (input.reason ? `: ${input.reason}` : "") + ".";
@@ -61786,7 +62141,7 @@ async function readOptionalFile(filePath) {
61786
62141
  }
61787
62142
  async function assertCodexWorkingDirectory(cwd, agentName) {
61788
62143
  try {
61789
- const stats = await stat3(cwd);
62144
+ const stats = await stat4(cwd);
61790
62145
  if (!stats.isDirectory()) {
61791
62146
  throw new Error(`Codex app-server cwd is not a directory for ${agentName}: ${cwd}`);
61792
62147
  }
@@ -61899,6 +62254,10 @@ function isMissingCodexRolloutError(error48) {
61899
62254
  const message = errorMessage2(error48).toLowerCase();
61900
62255
  return message.includes("no rollout found for thread id");
61901
62256
  }
62257
+ function isCodexThreadWriterConflictError(error48) {
62258
+ const message = errorMessage2(error48).toLowerCase();
62259
+ return message.includes("already has an active writer") || message.includes("thread-store conflict");
62260
+ }
61902
62261
 
61903
62262
  class CodexAppServerTransport {
61904
62263
  options;
@@ -61933,6 +62292,9 @@ class CodexAppServerTransport {
61933
62292
  get currentThreadPath() {
61934
62293
  return this.threadPath;
61935
62294
  }
62295
+ get currentDurableThreadId() {
62296
+ return this.durableThreadId;
62297
+ }
61936
62298
  get stdoutLogFile() {
61937
62299
  return this.stdoutLogPath;
61938
62300
  }
@@ -61969,7 +62331,8 @@ class CodexAppServerTransport {
61969
62331
  throw new Error(`Codex app-server session for ${this.options.agentName} has no active thread.`);
61970
62332
  }
61971
62333
  return {
61972
- threadId: this.threadId
62334
+ threadId: this.threadId,
62335
+ durableThreadId: this.durableThreadId
61973
62336
  };
61974
62337
  }
61975
62338
  async startTurn(prompt) {
@@ -62187,6 +62550,13 @@ class CodexAppServerTransport {
62187
62550
  await this.persistState();
62188
62551
  }
62189
62552
  if (requestedThreadId || this.options.requireExistingThread) {
62553
+ if (isCodexThreadWriterConflictError(error48)) {
62554
+ throw new CodexThreadHeldExternallyError({
62555
+ agentName: this.options.agentName,
62556
+ threadId: storedThreadId,
62557
+ detail: errorMessage2(error48)
62558
+ });
62559
+ }
62190
62560
  throw new Error(`Failed to resume ${threadOrigin} Codex thread ${storedThreadId}: ${errorMessage2(error48)}`);
62191
62561
  }
62192
62562
  }
@@ -62359,7 +62729,7 @@ class CodexAppServerTransport {
62359
62729
  let rolloutExists = false;
62360
62730
  if (this.threadPath) {
62361
62731
  try {
62362
- rolloutExists = (await stat3(this.threadPath)).isFile();
62732
+ rolloutExists = (await stat4(this.threadPath)).isFile();
62363
62733
  } catch {
62364
62734
  rolloutExists = false;
62365
62735
  }
@@ -66449,7 +66819,7 @@ function buildInvocationCollaborationContextPrompt(invocation) {
66449
66819
  }
66450
66820
 
66451
66821
  // packages/runtime/src/pi-rpc.ts
66452
- import { existsSync as existsSync26, readFileSync as readFileSync10, statSync as statSync13 } from "fs";
66822
+ import { existsSync as existsSync26, readFileSync as readFileSync10, statSync as statSync14 } from "fs";
66453
66823
  import { mkdir as mkdir6, writeFile as writeFile4 } from "fs/promises";
66454
66824
  import { execFileSync as execFileSync2 } from "child_process";
66455
66825
  import { homedir as homedir26 } from "os";
@@ -66556,13 +66926,13 @@ function readPiRpcCredentialFile(name, options = {}) {
66556
66926
  return;
66557
66927
  }
66558
66928
  try {
66559
- const directoryStat = statSync13(directory);
66929
+ const directoryStat = statSync14(directory);
66560
66930
  if (!directoryStat.isDirectory() || (directoryStat.mode & 63) !== 0) {
66561
66931
  return;
66562
66932
  }
66563
66933
  const path = join28(directory, name);
66564
- const stat4 = statSync13(path);
66565
- if (!stat4.isFile() || (stat4.mode & 63) !== 0 || stat4.size > 16 * 1024) {
66934
+ const stat5 = statSync14(path);
66935
+ if (!stat5.isFile() || (stat5.mode & 63) !== 0 || stat5.size > 16 * 1024) {
66566
66936
  return;
66567
66937
  }
66568
66938
  const value = readFileSync10(path, "utf8").trim();
@@ -66913,7 +67283,7 @@ async function shutdownPiRpcAgent(options) {
66913
67283
  // packages/runtime/src/setup.ts
66914
67284
  import { execFileSync as execFileSync4 } from "child_process";
66915
67285
  import { existsSync as existsSync29, readFileSync as readFileSync13 } from "fs";
66916
- import { access, chmod, mkdir as mkdir8, readdir as readdir3, readFile as readFile8, realpath, rm as rm3, stat as stat5, writeFile as writeFile6 } from "fs/promises";
67286
+ import { access, chmod, mkdir as mkdir8, readdir as readdir3, readFile as readFile8, realpath, rm as rm3, stat as stat6, writeFile as writeFile6 } from "fs/promises";
66917
67287
  import { homedir as homedir29, hostname as hostname3, userInfo } from "os";
66918
67288
  import { basename as basename15, dirname as dirname16, isAbsolute as isAbsolute2, join as join32, relative as relative6, resolve as resolve9 } from "path";
66919
67289
  import { fileURLToPath as fileURLToPath4 } from "url";
@@ -67866,7 +68236,7 @@ function parse5(toml, { maxDepth = 1000, integersAsBigInt } = {}) {
67866
68236
 
67867
68237
  // packages/runtime/src/harness-catalog.ts
67868
68238
  import { execFileSync as execFileSync3 } from "child_process";
67869
- import { existsSync as existsSync27, statSync as statSync14 } from "fs";
68239
+ import { existsSync as existsSync27, statSync as statSync15 } from "fs";
67870
68240
  import { mkdir as mkdir7, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
67871
68241
  import { homedir as homedir27 } from "os";
67872
68242
  import { dirname as dirname13, join as join29 } from "path";
@@ -68452,7 +68822,7 @@ function defaultRequirementExists(requirement) {
68452
68822
  if (requirement.fileType === "any" || !requirement.fileType)
68453
68823
  return true;
68454
68824
  try {
68455
- const fileStat = statSync14(expanded);
68825
+ const fileStat = statSync15(expanded);
68456
68826
  return requirement.fileType === "directory" ? fileStat.isDirectory() : fileStat.isFile();
68457
68827
  } catch {
68458
68828
  return false;
@@ -68754,6 +69124,38 @@ var NODE_IDENTITY_FILE = "node-identity.json";
68754
69124
  var NODE_FINGERPRINT_PREFIX = "osc1";
68755
69125
  var NODE_CARD_TTL_MS = 24 * 60 * 60 * 1000;
68756
69126
  var stableNodeQualifierCache = new Map;
69127
+ function stripBonjourCollisionSuffix(value) {
69128
+ if (!value || typeof value !== "string")
69129
+ return "";
69130
+ let trimmed = value.trim();
69131
+ const isDotLocal = /\.local\.?$/i.test(trimmed);
69132
+ if (isDotLocal) {
69133
+ trimmed = trimmed.replace(/\.local\.?$/i, "");
69134
+ }
69135
+ const isHyphenLocalOpenscout = /-local-openscout$/i.test(trimmed);
69136
+ const isHyphenLocal = !isHyphenLocalOpenscout && /-local$/i.test(trimmed);
69137
+ if (isHyphenLocalOpenscout) {
69138
+ trimmed = trimmed.replace(/-local-openscout$/i, "");
69139
+ } else if (isHyphenLocal) {
69140
+ trimmed = trimmed.replace(/-local$/i, "");
69141
+ }
69142
+ if (!isDotLocal && !isHyphenLocalOpenscout && !isHyphenLocal) {
69143
+ return trimmed;
69144
+ }
69145
+ trimmed = trimmed.replace(/(?<=[a-zA-Z].*?)(?:-\d+)+$/, "");
69146
+ if (isDotLocal)
69147
+ return `${trimmed}.local`;
69148
+ if (isHyphenLocalOpenscout)
69149
+ return `${trimmed}-local-openscout`;
69150
+ if (isHyphenLocal)
69151
+ return `${trimmed}-local`;
69152
+ return trimmed;
69153
+ }
69154
+ function canonicalMeshNodeId(nodeId) {
69155
+ if (!nodeId || typeof nodeId !== "string")
69156
+ return "";
69157
+ return stripBonjourCollisionSuffix(nodeId);
69158
+ }
68757
69159
  function nodeIdentityPath(supportDirectory) {
68758
69160
  const dir = supportDirectory ?? resolveOpenScoutSupportPaths().supportDirectory;
68759
69161
  return join30(dir, NODE_IDENTITY_FILE);
@@ -68774,6 +69176,12 @@ function loadOrCreateStableNodeQualifier(fallbackName, supportDirectory) {
68774
69176
  const identity2 = loadOrCreateNodeIdentity(supportDirectory);
68775
69177
  const existing = normalizeNodeQualifier(identity2.nodeQualifier);
68776
69178
  if (existing) {
69179
+ if (identity2.nodeQualifier !== existing) {
69180
+ persistNodeIdentity(path, {
69181
+ ...identity2,
69182
+ nodeQualifier: existing
69183
+ });
69184
+ }
68777
69185
  stableNodeQualifierCache.set(path, existing);
68778
69186
  return existing;
68779
69187
  }
@@ -68819,7 +69227,7 @@ function readAndValidateNodeIdentity(path) {
68819
69227
  if (parsed.version !== 1 || !parsed.publicKey || !parsed.privateKey) {
68820
69228
  throw new Error(`Corrupt node identity at ${path}; remove it to generate a fresh one.`);
68821
69229
  }
68822
- if (parsed.nodeQualifier !== undefined && normalizeNodeQualifier(parsed.nodeQualifier) !== parsed.nodeQualifier) {
69230
+ if (parsed.nodeQualifier !== undefined && normalizePersistedNodeQualifier(parsed.nodeQualifier) !== parsed.nodeQualifier) {
68823
69231
  throw new Error(`Corrupt node identity at ${path}; remove it to generate a fresh one.`);
68824
69232
  }
68825
69233
  try {
@@ -68832,9 +69240,12 @@ function readAndValidateNodeIdentity(path) {
68832
69240
  }
68833
69241
  return parsed;
68834
69242
  }
68835
- function normalizeNodeQualifier(value) {
69243
+ function normalizePersistedNodeQualifier(value) {
68836
69244
  return typeof value === "string" ? value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "") : "";
68837
69245
  }
69246
+ function normalizeNodeQualifier(value) {
69247
+ return stripBonjourCollisionSuffix(normalizePersistedNodeQualifier(value));
69248
+ }
68838
69249
  function persistNodeIdentity(path, identity2) {
68839
69250
  const tempPath = `${path}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
68840
69251
  mkdirSync3(dirname14(path), { recursive: true });
@@ -69033,7 +69444,7 @@ function isRecord9(value) {
69033
69444
  }
69034
69445
 
69035
69446
  // packages/runtime/src/user-project-hints.ts
69036
- import { readdir as readdir2, readFile as readFile7, stat as stat4 } from "fs/promises";
69447
+ import { readdir as readdir2, readFile as readFile7, stat as stat5 } from "fs/promises";
69037
69448
  import { homedir as homedir28 } from "os";
69038
69449
  import { dirname as dirname15, join as join31, resolve as resolve8 } from "path";
69039
69450
  import { fileURLToPath as fileURLToPath3 } from "url";
@@ -69067,7 +69478,7 @@ function encodeClaudeProjectsSlug(absolutePath) {
69067
69478
  async function resolveExistingDirectoryHint(pathLike) {
69068
69479
  const absolutePath = resolve8(pathLike);
69069
69480
  try {
69070
- const info = await stat4(absolutePath);
69481
+ const info = await stat5(absolutePath);
69071
69482
  if (info.isDirectory()) {
69072
69483
  return absolutePath;
69073
69484
  }
@@ -69081,7 +69492,7 @@ async function resolveExistingDirectoryHint(pathLike) {
69081
69492
  }
69082
69493
  async function pathExists(pathLike) {
69083
69494
  try {
69084
- await stat4(pathLike);
69495
+ await stat5(pathLike);
69085
69496
  return true;
69086
69497
  } catch {
69087
69498
  return false;
@@ -69159,7 +69570,7 @@ async function appendCodexHistoryPaths(home, roots) {
69159
69570
  for (const filePath of candidates) {
69160
69571
  let st;
69161
69572
  try {
69162
- st = await stat4(filePath);
69573
+ st = await stat5(filePath);
69163
69574
  } catch {
69164
69575
  continue;
69165
69576
  }
@@ -69231,7 +69642,7 @@ async function appendCursorWorkspacePaths(home, roots) {
69231
69642
  }
69232
69643
  let wsStat;
69233
69644
  try {
69234
- wsStat = await stat4(wsFile);
69645
+ wsStat = await stat5(wsFile);
69235
69646
  } catch {
69236
69647
  continue;
69237
69648
  }
@@ -69298,7 +69709,7 @@ async function appendClaudeSessionPaths(home, roots) {
69298
69709
  const sessionPath = join31(projectsDir, projectName, entry);
69299
69710
  let info;
69300
69711
  try {
69301
- info = await stat4(sessionPath);
69712
+ info = await stat5(sessionPath);
69302
69713
  } catch {
69303
69714
  continue;
69304
69715
  }
@@ -69986,6 +70397,9 @@ function defaultSettings() {
69986
70397
  quickHits: [],
69987
70398
  preparedAt: null
69988
70399
  },
70400
+ voice: {
70401
+ realtimeEnabled: false
70402
+ },
69989
70403
  ui: {
69990
70404
  scenes: [],
69991
70405
  activeSceneIdBySurface: {}
@@ -70011,7 +70425,7 @@ async function pathExists2(filePath) {
70011
70425
  }
70012
70426
  async function isDirectory(filePath) {
70013
70427
  try {
70014
- const fileStat = await stat5(filePath);
70428
+ const fileStat = await stat6(filePath);
70015
70429
  return fileStat.isDirectory();
70016
70430
  } catch {
70017
70431
  return false;
@@ -70373,6 +70787,7 @@ async function normalizeSettingsRecord(value, options = {}) {
70373
70787
  const telegram = typeof bridges.telegram === "object" && bridges.telegram ? bridges.telegram : {};
70374
70788
  const network = typeof candidate.network === "object" && candidate.network ? candidate.network : {};
70375
70789
  const phone = typeof candidate.phone === "object" && candidate.phone ? candidate.phone : {};
70790
+ const voice = typeof candidate.voice === "object" && candidate.voice ? candidate.voice : {};
70376
70791
  const ui = typeof candidate.ui === "object" && candidate.ui ? candidate.ui : {};
70377
70792
  const oldOperatorName = typeof candidate.operatorName === "string" ? candidate.operatorName : undefined;
70378
70793
  const seededWorkspaceRoots = await seedWorkspaceRoots({
@@ -70445,6 +70860,9 @@ async function normalizeSettingsRecord(value, options = {}) {
70445
70860
  quickHits: normalizeStringList(phone.quickHits),
70446
70861
  preparedAt: normalizeOptionalTimestamp(phone.preparedAt)
70447
70862
  },
70863
+ voice: {
70864
+ realtimeEnabled: typeof voice.realtimeEnabled === "boolean" ? voice.realtimeEnabled : base.voice.realtimeEnabled
70865
+ },
70448
70866
  ui: normalizeUi(ui)
70449
70867
  };
70450
70868
  }
@@ -73416,6 +73834,14 @@ async function readLocalAgentRegistry() {
73416
73834
  localAgentRecordFromRelayAgentOverride(agentId, override)
73417
73835
  ]));
73418
73836
  }
73837
+ var archivedLocalAgentIdsCache = null;
73838
+ function invalidateArchivedLocalAgentIdsCache() {
73839
+ archivedLocalAgentIdsCache = null;
73840
+ }
73841
+ async function writeRelayAgentOverrides2(overrides) {
73842
+ await writeRelayAgentOverrides(overrides);
73843
+ invalidateArchivedLocalAgentIdsCache();
73844
+ }
73419
73845
  async function writeLocalAgentRegistry(registry3) {
73420
73846
  const overrides = await readRelayAgentOverrides();
73421
73847
  const nextOverrides = {
@@ -73424,7 +73850,7 @@ async function writeLocalAgentRegistry(registry3) {
73424
73850
  for (const [agentId, record3] of Object.entries(registry3)) {
73425
73851
  nextOverrides[agentId] = relayAgentOverrideFromLocalAgentRecord(agentId, record3, overrides[agentId]);
73426
73852
  }
73427
- await writeRelayAgentOverrides(nextOverrides);
73853
+ await writeRelayAgentOverrides2(nextOverrides);
73428
73854
  }
73429
73855
  function expandHomePath4(value) {
73430
73856
  if (value === "~") {
@@ -74063,7 +74489,7 @@ function providerSessionIdFromMetadata(metadata) {
74063
74489
  async function ensureLocalSessionEndpointOnline(endpoint) {
74064
74490
  if (endpoint.transport === "codex_app_server") {
74065
74491
  const result = await ensureCodexAppServerAgentOnline(buildCodexEndpointSessionOptions(endpoint));
74066
- return { externalSessionId: result.threadId };
74492
+ return { externalSessionId: result.durableThreadId };
74067
74493
  }
74068
74494
  if (endpoint.transport === "claude_stream_json") {
74069
74495
  const result = await ensureClaudeStreamJsonAgentOnline(buildClaudeEndpointSessionOptions(endpoint));
@@ -74240,7 +74666,7 @@ function buildCodexEndpointSessionOptions(endpoint) {
74240
74666
  logsDirectory: relayAgentLogsDirectory(agentName),
74241
74667
  env: {
74242
74668
  CODEX_HOME: codexHomeForEndpoint(endpoint),
74243
- ...endpoint.metadata?.placement === "background" ? {
74669
+ ...endpoint.metadata?.placement === "background" && codexHomeForEndpoint(endpoint) !== operatorCodexHome() ? {
74244
74670
  OPENSCOUT_CODEX_AUTH_SOURCE: join37(operatorCodexHome(), "auth.json")
74245
74671
  } : {}
74246
74672
  },
@@ -74252,6 +74678,12 @@ function buildCodexEndpointSessionOptions(endpoint) {
74252
74678
  });
74253
74679
  }
74254
74680
  function codexHomeForEndpoint(endpoint) {
74681
+ const source = endpointMetadataString(endpoint, "source");
74682
+ const scoutOwnsThread = source === "scoutbot" || source?.startsWith("scout-") === true;
74683
+ const externalThreadId = scoutOwnsThread ? undefined : endpointMetadataString(endpoint, "threadId") ?? endpointMetadataString(endpoint, "externalSessionId");
74684
+ if (externalThreadId) {
74685
+ return operatorCodexHome();
74686
+ }
74255
74687
  const placement = endpoint.metadata?.placement === "background" ? "background" : "foreground";
74256
74688
  if (placement === "background") {
74257
74689
  return join37(resolveOpenScoutSupportPaths().runtimeDirectory, "codex-background-home");
@@ -78683,7 +79115,7 @@ class BrokerDeliveryAcceptanceService {
78683
79115
  };
78684
79116
  const aliasResolution = resolved.aliasResolution;
78685
79117
  const receiptSessionId = requestedTargetSessionId ?? (aliasResolution?.target.kind === "session" ? aliasResolution.target.sessionId : undefined) ?? (resolved.kind === "resolved_session" ? resolved.session.sessionId : undefined);
78686
- const unavailable = resolved.kind === "resolved" ? this.options.describeUnavailableDeliveryTarget(this.options.runtimeSnapshot(), resolved.agent, requestedTargetSessionId) : describeUnavailableSessionEndpoint(resolved.session.endpoint);
79118
+ const unavailable = resolved.kind === "resolved" ? this.options.describeUnavailableDeliveryTarget(this.options.runtimeSnapshot(), resolved.agent, requestedTargetSessionId) : null;
78687
79119
  if (unavailable) {
78688
79120
  const targetLabel2 = askedLabel || target.label;
78689
79121
  const { record: record3 } = await this.options.recordScoutDispatch(this.options.buildUnavailableDispatchEnvelope(targetLabel2, unavailable), {
@@ -80131,6 +80563,62 @@ function parsePositiveIntParam(url2, key, cap) {
80131
80563
  return;
80132
80564
  return Math.min(value, cap);
80133
80565
  }
80566
+ var TAIL_RECENT_ASSISTANT_REPLIES_MODE = "assistant-replies";
80567
+ function isAssistantRepliesMode(url2) {
80568
+ return url2.searchParams.get("mode") === TAIL_RECENT_ASSISTANT_REPLIES_MODE;
80569
+ }
80570
+ function tailEventMessageRole(event) {
80571
+ if (!event.raw || typeof event.raw !== "object" || Array.isArray(event.raw))
80572
+ return null;
80573
+ const payload = event.raw.payload;
80574
+ if (!payload || typeof payload !== "object" || Array.isArray(payload))
80575
+ return null;
80576
+ const role = payload.role;
80577
+ return typeof role === "string" ? role.trim().toLowerCase() : null;
80578
+ }
80579
+ function isApprovalReviewerDecision(summary) {
80580
+ const trimmed = summary.trim();
80581
+ if (!trimmed.startsWith("{"))
80582
+ return false;
80583
+ if (trimmed.startsWith('{"risk_level":') && trimmed.includes('"user_authorization":') && trimmed.includes('"outcome":') && trimmed.includes('"rationale":')) {
80584
+ return true;
80585
+ }
80586
+ try {
80587
+ const parsed = JSON.parse(trimmed);
80588
+ return typeof parsed.risk_level === "string" && typeof parsed.user_authorization === "string" && typeof parsed.outcome === "string" && typeof parsed.rationale === "string";
80589
+ } catch {
80590
+ return false;
80591
+ }
80592
+ }
80593
+ function isAssistantReply(event) {
80594
+ if (event.kind !== "assistant")
80595
+ return false;
80596
+ const summary = event.summary.trim();
80597
+ if (!summary || /^\[(?:assistant|message)\]$/iu.test(summary))
80598
+ return false;
80599
+ const role = tailEventMessageRole(event);
80600
+ if (role && role !== "assistant")
80601
+ return false;
80602
+ return !isApprovalReviewerDecision(summary);
80603
+ }
80604
+ function assistantReplySessionKey(event) {
80605
+ const source = event.source.trim().toLowerCase();
80606
+ const sessionId = event.sessionId.trim();
80607
+ return source && sessionId ? `${source}\x00${sessionId}` : `event\x00${event.id}`;
80608
+ }
80609
+ function latestAssistantReplies(events) {
80610
+ const latestBySession = new Map;
80611
+ for (const event of events) {
80612
+ if (!isAssistantReply(event))
80613
+ continue;
80614
+ const key = assistantReplySessionKey(event);
80615
+ const current = latestBySession.get(key);
80616
+ if (!current || event.ts > current.ts || event.ts === current.ts && event.id.localeCompare(current.id) > 0) {
80617
+ latestBySession.set(key, event);
80618
+ }
80619
+ }
80620
+ return [...latestBySession.values()];
80621
+ }
80134
80622
  function booleanQuery(url2, key) {
80135
80623
  return url2.searchParams.get(key) === "1" || url2.searchParams.get(key) === "true";
80136
80624
  }
@@ -80138,6 +80626,8 @@ function booleanQuery(url2, key) {
80138
80626
  class BrokerRepoTailService {
80139
80627
  options;
80140
80628
  repoWatchWarmInFlight = null;
80629
+ tailRecentCache = null;
80630
+ tailRecentInFlight = null;
80141
80631
  constructor(options) {
80142
80632
  this.options = options;
80143
80633
  }
@@ -80215,6 +80705,48 @@ class BrokerRepoTailService {
80215
80705
  return snapshot;
80216
80706
  }
80217
80707
  async readTailRecentPayloadWithTiming(url2) {
80708
+ const cacheTtlMs = this.options.tailRecentServeCacheTtlMs ?? 0;
80709
+ const cacheKey = `${parseTailLimit(url2)}:${url2.searchParams.get("transcripts") === "true" || url2.searchParams.get("transcripts") === "1"}:${isAssistantRepliesMode(url2) ? TAIL_RECENT_ASSISTANT_REPLIES_MODE : "all"}`;
80710
+ const now = this.now();
80711
+ if (cacheTtlMs > 0 && this.tailRecentCache?.key === cacheKey && this.tailRecentCache.expiresAtMs > now) {
80712
+ const cached2 = this.tailRecentCache;
80713
+ return {
80714
+ payload: {
80715
+ ...cached2.result.payload,
80716
+ events: [...cached2.result.payload.events]
80717
+ },
80718
+ timings: [
80719
+ ...cached2.result.timings,
80720
+ { name: "tail-serve-cache", dur: Math.max(0, now - (cached2.expiresAtMs - cacheTtlMs)) }
80721
+ ]
80722
+ };
80723
+ }
80724
+ const inFlight = this.tailRecentInFlight;
80725
+ if (cacheTtlMs > 0 && inFlight && inFlight.key === cacheKey)
80726
+ return inFlight.promise;
80727
+ const request = (async () => {
80728
+ const result = await this.computeTailRecentPayloadWithTiming(url2);
80729
+ if (cacheTtlMs > 0) {
80730
+ this.tailRecentCache = {
80731
+ key: cacheKey,
80732
+ result,
80733
+ expiresAtMs: this.now() + cacheTtlMs
80734
+ };
80735
+ }
80736
+ return result;
80737
+ })();
80738
+ if (cacheTtlMs > 0) {
80739
+ this.tailRecentInFlight = { key: cacheKey, promise: request };
80740
+ try {
80741
+ return await request;
80742
+ } finally {
80743
+ if (this.tailRecentInFlight?.promise === request)
80744
+ this.tailRecentInFlight = null;
80745
+ }
80746
+ }
80747
+ return request;
80748
+ }
80749
+ async computeTailRecentPayloadWithTiming(url2) {
80218
80750
  const timings = [];
80219
80751
  const measure = async (name, fn) => {
80220
80752
  const start = performance2.now();
@@ -80225,24 +80757,29 @@ class BrokerRepoTailService {
80225
80757
  }
80226
80758
  };
80227
80759
  const limit = parseTailLimit(url2);
80760
+ const assistantRepliesOnly = isAssistantRepliesMode(url2);
80761
+ const kinds = assistantRepliesOnly ? ["assistant"] : undefined;
80228
80762
  const includeTranscripts = url2.searchParams.get("transcripts") === "true" || url2.searchParams.get("transcripts") === "1";
80229
80763
  const eventsById = new Map;
80230
80764
  if (includeTranscripts) {
80231
80765
  const discovery = await measure("tail-discover", () => this.options.getTailDiscovery(false));
80232
80766
  const transcriptEvents = filterTailEventsForDisplay(await measure("tail-transcripts", () => this.options.readRecentTranscriptEvents(Math.max(limit, 800), {
80233
80767
  discovery,
80234
- perTranscriptLineLimit: Math.min(200, Math.max(50, limit))
80768
+ perTranscriptLineLimit: Math.min(200, Math.max(50, limit)),
80769
+ kinds,
80770
+ ...assistantRepliesOnly ? { perTranscriptKindLimit: 1 } : {}
80235
80771
  })));
80236
80772
  for (const event of transcriptEvents) {
80237
80773
  eventsById.set(event.id, event);
80238
80774
  }
80239
80775
  }
80240
80776
  const mergeStart = performance2.now();
80241
- const bufferedEvents = filterTailEventsForDisplay(await measure("tail-live", () => this.options.readRecentLiveEvents(limit)));
80777
+ const bufferedEvents = filterTailEventsForDisplay(await measure("tail-live", () => this.options.readRecentLiveEvents(limit, { kinds })));
80242
80778
  for (const event of bufferedEvents) {
80243
80779
  eventsById.set(event.id, event);
80244
80780
  }
80245
- const events = [...eventsById.values()].sort((left, right) => {
80781
+ const candidates = assistantRepliesOnly ? latestAssistantReplies(eventsById.values()) : [...eventsById.values()];
80782
+ const events = candidates.sort((left, right) => {
80246
80783
  if (left.ts === right.ts)
80247
80784
  return left.id.localeCompare(right.id);
80248
80785
  return left.ts - right.ts;
@@ -80258,12 +80795,12 @@ class BrokerRepoTailService {
80258
80795
  timings
80259
80796
  };
80260
80797
  }
80261
- async readTailRecentPayload(url2) {
80262
- return (await this.readTailRecentPayloadWithTiming(url2)).payload;
80263
- }
80264
80798
  now() {
80265
80799
  return (this.options.now ?? Date.now)();
80266
80800
  }
80801
+ async readTailRecentPayload(url2) {
80802
+ return (await this.readTailRecentPayloadWithTiming(url2)).payload;
80803
+ }
80267
80804
  }
80268
80805
 
80269
80806
  // packages/runtime/src/broker-rendezvous-service.ts
@@ -101776,6 +102313,10 @@ function hasColumn(database, tableName, columnName) {
101776
102313
  const rows = database.query(`SELECT name FROM pragma_table_info('${escapedTableName}')`).all();
101777
102314
  return rows.some((row) => row.name === columnName);
101778
102315
  }
102316
+ function hasTable(database, tableName) {
102317
+ const row = database.query("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?1").get(tableName);
102318
+ return Boolean(row);
102319
+ }
101779
102320
  var CONTROL_PLANE_SCHEMA_MIGRATIONS = [
101780
102321
  {
101781
102322
  id: "runtime-session-mapping-read-model",
@@ -101954,6 +102495,46 @@ WHERE latest.invocation_id = inv.id
101954
102495
  database.exec("ALTER TABLE trusted_peers ADD COLUMN tls_spki_fingerprint TEXT");
101955
102496
  }
101956
102497
  }
102498
+ },
102499
+ {
102500
+ id: "canonicalize-mesh-nodes-and-rehome",
102501
+ description: "Re-homes foreign key references on Bonjour collision-suffixed ghost nodes to canonical stable node IDs and prunes ghost nodes.",
102502
+ apply(database) {
102503
+ if (!hasTable(database, "nodes"))
102504
+ return;
102505
+ const nodeRows = database.query("SELECT * FROM nodes").all();
102506
+ for (const row of nodeRows) {
102507
+ const canonicalId = canonicalMeshNodeId(row.id);
102508
+ if (canonicalId && canonicalId !== row.id) {
102509
+ const existing = nodeRows.find((r) => r.id === canonicalId);
102510
+ if (!existing) {
102511
+ database.query(`INSERT INTO nodes (
102512
+ id, mesh_id, name, host_name, advertise_scope, broker_url, tailnet_name,
102513
+ capabilities_json, labels_json, metadata_json, last_seen_at, registered_at
102514
+ ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)
102515
+ ON CONFLICT(id) DO UPDATE SET
102516
+ last_seen_at = MAX(COALESCE(nodes.last_seen_at, 0), COALESCE(excluded.last_seen_at, 0)),
102517
+ broker_url = COALESCE(excluded.broker_url, nodes.broker_url),
102518
+ tailnet_name = COALESCE(excluded.tailnet_name, nodes.tailnet_name)`).run(canonicalId, row.mesh_id, stripBonjourCollisionSuffix(row.name) || row.name, stripBonjourCollisionSuffix(row.host_name ?? "") || (row.host_name ?? null), row.advertise_scope, row.broker_url ?? null, row.tailnet_name ?? null, row.capabilities_json ?? null, row.labels_json ?? null, row.metadata_json ?? null, row.last_seen_at ?? null, row.registered_at);
102519
+ }
102520
+ database.query("UPDATE agents SET home_node_id = ?1 WHERE home_node_id = ?2").run(canonicalId, row.id);
102521
+ database.query("UPDATE agents SET authority_node_id = ?1 WHERE authority_node_id = ?2").run(canonicalId, row.id);
102522
+ database.query("UPDATE agent_endpoints SET node_id = ?1 WHERE node_id = ?2").run(canonicalId, row.id);
102523
+ database.query("UPDATE runtime_sessions SET node_id = ?1 WHERE node_id = ?2").run(canonicalId, row.id);
102524
+ database.query("UPDATE runtime_session_aliases SET node_id = ?1 WHERE node_id = ?2").run(canonicalId, row.id);
102525
+ database.query("UPDATE conversations SET authority_node_id = ?1 WHERE authority_node_id = ?2").run(canonicalId, row.id);
102526
+ database.query("UPDATE conversation_read_cursors SET reader_node_id = ?1 WHERE reader_node_id = ?2").run(canonicalId, row.id);
102527
+ database.query("UPDATE messages SET origin_node_id = ?1 WHERE origin_node_id = ?2").run(canonicalId, row.id);
102528
+ database.query("UPDATE deliveries SET target_node_id = ?1 WHERE target_node_id = ?2").run(canonicalId, row.id);
102529
+ database.query("UPDATE invocations SET requester_node_id = ?1 WHERE requester_node_id = ?2").run(canonicalId, row.id);
102530
+ database.query("UPDATE invocations SET target_node_id = ?1 WHERE target_node_id = ?2").run(canonicalId, row.id);
102531
+ database.query("UPDATE thread_events SET authority_node_id = ?1 WHERE authority_node_id = ?2").run(canonicalId, row.id);
102532
+ database.query("UPDATE thread_cursors SET authority_node_id = ?1 WHERE authority_node_id = ?2").run(canonicalId, row.id);
102533
+ database.query("UPDATE trusted_peers SET node_id = ?1 WHERE node_id = ?2").run(canonicalId, row.id);
102534
+ database.query("DELETE FROM nodes WHERE id = ?1").run(row.id);
102535
+ }
102536
+ }
102537
+ }
101957
102538
  }
101958
102539
  ];
101959
102540
  function configureControlPlaneDatabase(database) {
@@ -102980,11 +103561,65 @@ class SQLiteControlPlaneStore {
102980
103561
  const now = options.now ?? currentTimestampMs();
102981
103562
  const maxStaleAgeMs = options.maxStaleAgeMs ?? 7 * 24 * 60 * 60 * 1000;
102982
103563
  const staleCutoff = now - maxStaleAgeMs;
103564
+ const nodeRows = this.db.query("SELECT * FROM nodes").all();
102983
103565
  const peerRows = this.db.query("SELECT * FROM trusted_peers").all();
102984
103566
  const rehomedMappings = [];
102985
- const rehomedNodeCount = 0;
103567
+ const rehomeMap = new Map;
103568
+ for (const row of nodeRows) {
103569
+ const canonicalId = canonicalMeshNodeId(row.id);
103570
+ if (canonicalId && canonicalId !== row.id) {
103571
+ rehomeMap.set(row.id, { to: canonicalId, candidateRow: row });
103572
+ }
103573
+ }
103574
+ let rehomedNodeCount = 0;
102986
103575
  let prunedNodeCount = 0;
102987
103576
  this.db.transaction(() => {
103577
+ for (const [staleId, { to: canonicalId, candidateRow }] of rehomeMap.entries()) {
103578
+ const existingCanonical = nodeRows.find((r) => r.id === canonicalId);
103579
+ if (!existingCanonical) {
103580
+ this.db.query(`INSERT INTO nodes (
103581
+ id, mesh_id, name, host_name, advertise_scope, broker_url, tailnet_name,
103582
+ capabilities_json, labels_json, metadata_json, last_seen_at, registered_at
103583
+ ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)
103584
+ ON CONFLICT(id) DO UPDATE SET
103585
+ last_seen_at = MAX(COALESCE(nodes.last_seen_at, 0), COALESCE(excluded.last_seen_at, 0)),
103586
+ broker_url = COALESCE(excluded.broker_url, nodes.broker_url),
103587
+ tailnet_name = COALESCE(excluded.tailnet_name, nodes.tailnet_name)`).run(canonicalId, candidateRow.mesh_id, stripBonjourCollisionSuffix(candidateRow.name) || candidateRow.name, stripBonjourCollisionSuffix(candidateRow.host_name ?? "") || (candidateRow.host_name ?? null), candidateRow.advertise_scope, candidateRow.broker_url ?? null, candidateRow.tailnet_name ?? null, candidateRow.capabilities_json ?? null, candidateRow.labels_json ?? null, candidateRow.metadata_json ?? null, candidateRow.last_seen_at ?? null, candidateRow.registered_at);
103588
+ } else {
103589
+ this.db.query(`UPDATE nodes SET
103590
+ last_seen_at = MAX(COALESCE(last_seen_at, 0), COALESCE(?1, 0)),
103591
+ broker_url = COALESCE(?2, broker_url)
103592
+ WHERE id = ?3`).run(candidateRow.last_seen_at ?? null, candidateRow.broker_url ?? null, canonicalId);
103593
+ }
103594
+ this.db.query("UPDATE agents SET home_node_id = ?1 WHERE home_node_id = ?2").run(canonicalId, staleId);
103595
+ this.db.query("UPDATE agents SET authority_node_id = ?1 WHERE authority_node_id = ?2").run(canonicalId, staleId);
103596
+ this.db.query("UPDATE agent_endpoints SET node_id = ?1 WHERE node_id = ?2").run(canonicalId, staleId);
103597
+ this.db.query("UPDATE runtime_sessions SET node_id = ?1 WHERE node_id = ?2").run(canonicalId, staleId);
103598
+ this.db.query("UPDATE runtime_session_aliases SET node_id = ?1 WHERE node_id = ?2").run(canonicalId, staleId);
103599
+ this.db.query("UPDATE conversations SET authority_node_id = ?1 WHERE authority_node_id = ?2").run(canonicalId, staleId);
103600
+ this.db.query("UPDATE conversation_read_cursors SET reader_node_id = ?1 WHERE reader_node_id = ?2").run(canonicalId, staleId);
103601
+ this.db.query("UPDATE messages SET origin_node_id = ?1 WHERE origin_node_id = ?2").run(canonicalId, staleId);
103602
+ this.db.query("UPDATE deliveries SET target_node_id = ?1 WHERE target_node_id = ?2").run(canonicalId, staleId);
103603
+ this.db.query("UPDATE invocations SET requester_node_id = ?1 WHERE requester_node_id = ?2").run(canonicalId, staleId);
103604
+ this.db.query("UPDATE invocations SET target_node_id = ?1 WHERE target_node_id = ?2").run(canonicalId, staleId);
103605
+ this.db.query("UPDATE thread_events SET authority_node_id = ?1 WHERE authority_node_id = ?2").run(canonicalId, staleId);
103606
+ this.db.query("UPDATE thread_cursors SET authority_node_id = ?1 WHERE authority_node_id = ?2").run(canonicalId, staleId);
103607
+ this.db.query("UPDATE trusted_peers SET node_id = ?1 WHERE node_id = ?2").run(canonicalId, staleId);
103608
+ const delRes = this.db.query("DELETE FROM nodes WHERE id = ?1").run(staleId);
103609
+ if ((delRes.changes ?? 0) > 0) {
103610
+ prunedNodeCount++;
103611
+ rehomedNodeCount++;
103612
+ rehomedMappings.push({ from: staleId, to: canonicalId });
103613
+ }
103614
+ }
103615
+ for (const peer of peerRows) {
103616
+ if (peer.node_id) {
103617
+ const canonical2 = canonicalMeshNodeId(peer.node_id);
103618
+ if (canonical2 && canonical2 !== peer.node_id) {
103619
+ this.db.query("UPDATE trusted_peers SET node_id = ?1 WHERE key_id = ?2").run(canonical2, peer.key_id);
103620
+ }
103621
+ }
103622
+ }
102988
103623
  const remainingNodes = this.db.query("SELECT * FROM nodes").all();
102989
103624
  for (const row of remainingNodes) {
102990
103625
  if (row.id === options.localNodeId)
@@ -105139,6 +105774,10 @@ class RecoverableSQLiteProjection {
105139
105774
  queue = Promise.resolve();
105140
105775
  closed = false;
105141
105776
  lastUnavailableReason = null;
105777
+ warming = false;
105778
+ warmBoundaryReady = null;
105779
+ startupRecoveryInitiated = false;
105780
+ deferredStartupEvents = [];
105142
105781
  constructor(dbPath, journal, options = {}) {
105143
105782
  this.dbPath = dbPath;
105144
105783
  this.journal = journal;
@@ -105154,21 +105793,57 @@ class RecoverableSQLiteProjection {
105154
105793
  if (this.store) {
105155
105794
  return { state: "ready", detail: null };
105156
105795
  }
105796
+ if (this.warming) {
105797
+ return {
105798
+ state: "warming",
105799
+ detail: "SQLite activity projection is rebuilding from the broker journal."
105800
+ };
105801
+ }
105157
105802
  return {
105158
105803
  state: "degraded",
105159
105804
  detail: this.lastUnavailableReason ?? (this.closed ? "SQLite projection is closed." : "SQLite projection is not ready.")
105160
105805
  };
105161
105806
  }
105162
105807
  warm() {
105808
+ if (this.options.disabled || this.closed || this.store || this.warming) {
105809
+ return this.warmBoundaryReady ?? Promise.resolve();
105810
+ }
105811
+ this.startupRecoveryInitiated = true;
105812
+ const deferredStartupEvents = this.deferredStartupEvents.splice(0);
105813
+ this.warming = true;
105814
+ let resolveBoundary = () => {};
105815
+ let rejectBoundary = () => {};
105816
+ let boundaryCaptured = false;
105817
+ this.warmBoundaryReady = new Promise((resolve16, reject) => {
105818
+ resolveBoundary = resolve16;
105819
+ rejectBoundary = reject;
105820
+ });
105163
105821
  this.enqueue(async () => {
105164
- await this.ensureStore();
105822
+ try {
105823
+ await this.ensureStore(() => {
105824
+ boundaryCaptured = true;
105825
+ resolveBoundary();
105826
+ });
105827
+ } finally {
105828
+ this.warming = false;
105829
+ if (!boundaryCaptured) {
105830
+ rejectBoundary(new Error(this.lastUnavailableReason ?? "SQLite projection replay boundary could not be established."));
105831
+ }
105832
+ }
105165
105833
  });
105834
+ for (const event of deferredStartupEvents) {
105835
+ this.enqueueEvent(event);
105836
+ }
105837
+ return this.warmBoundaryReady;
105166
105838
  }
105167
105839
  enqueueEntries(entriesInput) {
105168
105840
  const entries = normalizeEntries(entriesInput);
105169
105841
  if (entries.length === 0 || this.options.disabled || this.closed) {
105170
105842
  return;
105171
105843
  }
105844
+ if (!this.startupRecoveryInitiated) {
105845
+ return;
105846
+ }
105172
105847
  this.enqueue(async () => {
105173
105848
  const store = await this.ensureStore();
105174
105849
  if (!store) {
@@ -105192,6 +105867,10 @@ class RecoverableSQLiteProjection {
105192
105867
  if (this.options.disabled || this.closed) {
105193
105868
  return;
105194
105869
  }
105870
+ if (!this.startupRecoveryInitiated) {
105871
+ this.deferredStartupEvents.push(event);
105872
+ return;
105873
+ }
105195
105874
  this.enqueue(async () => {
105196
105875
  const store = await this.ensureStore();
105197
105876
  if (!store) {
@@ -105369,7 +106048,7 @@ class RecoverableSQLiteProjection {
105369
106048
  this.queue = next.then(() => {}, () => {});
105370
106049
  return next;
105371
106050
  }
105372
- async replayJournal(visitor) {
106051
+ async replayJournal(visitor, boundary) {
105373
106052
  const configuredBatchSize = this.options.replayYieldEvery ?? DEFAULT_REPLAY_YIELD_EVERY;
105374
106053
  const batchSize = Math.max(1, Math.floor(configuredBatchSize));
105375
106054
  let visited = 0;
@@ -105379,22 +106058,27 @@ class RecoverableSQLiteProjection {
105379
106058
  if (visited % batchSize === 0) {
105380
106059
  await new Promise((resolve16) => setImmediate(resolve16));
105381
106060
  }
105382
- });
106061
+ }, boundary);
105383
106062
  }
105384
- async ensureStore() {
106063
+ async ensureStore(onReplayBoundaryCaptured) {
105385
106064
  if (this.options.disabled || this.closed) {
105386
106065
  return null;
105387
106066
  }
106067
+ if (!this.startupRecoveryInitiated) {
106068
+ return null;
106069
+ }
105388
106070
  if (this.store) {
105389
106071
  return this.store;
105390
106072
  }
105391
106073
  try {
106074
+ const replayBoundary = await this.journal.captureReplayBoundary();
106075
+ onReplayBoundaryCaptured?.();
105392
106076
  const createStore = this.options.createStore ?? ((dbPath) => new SQLiteControlPlaneStore(dbPath));
105393
106077
  const store = createStore(this.dbPath);
105394
106078
  const parents = createReplayParentScan();
105395
106079
  await this.replayJournal((entry) => {
105396
106080
  collectReplayParents(parents, entry);
105397
- });
106081
+ }, replayBoundary);
105398
106082
  prepareReplayParents(store, parents);
105399
106083
  await this.replayJournal((entry) => {
105400
106084
  try {
@@ -105408,7 +106092,7 @@ class RecoverableSQLiteProjection {
105408
106092
  }
105409
106093
  reportSkippedEntry(entry, error48);
105410
106094
  }
105411
- });
106095
+ }, replayBoundary);
105412
106096
  this.store = store;
105413
106097
  this.lastUnavailableReason = null;
105414
106098
  return store;
@@ -106300,6 +106984,7 @@ function createBrokerCoreService(deps) {
106300
106984
  build: deps.build ?? loadOpenScoutRuntimeBuildIdentity(),
106301
106985
  services: deps.readChildServices?.(),
106302
106986
  ...deps.readProjectionStatus ? { projection: deps.readProjectionStatus() } : {},
106987
+ ...deps.readStartupStatus ? { startup: deps.readStartupStatus() } : {},
106303
106988
  counts: {
106304
106989
  nodes: Object.keys(snapshot.nodes).length,
106305
106990
  actors: Object.keys(snapshot.actors).length,
@@ -110713,6 +111398,9 @@ class BrokerLocalEndpointResolver {
110713
111398
  if (revived)
110714
111399
  return revived;
110715
111400
  } catch (error48) {
111401
+ if (isCodexThreadHeldExternallyError(error48)) {
111402
+ throw error48;
111403
+ }
110716
111404
  await this.options.persistEndpoint({
110717
111405
  ...endpoint,
110718
111406
  state: "offline",
@@ -110920,6 +111608,7 @@ function isWakeableSessionBackedEndpoint(endpoint) {
110920
111608
  }
110921
111609
 
110922
111610
  // packages/runtime/src/broker-local-invocation-service.ts
111611
+ var HELD_THREAD_RETRY_DELAY_MS = 30000;
110923
111612
  function executionResolutionWithObservedEndpoint(resolution, endpoint, fallbackObservedAt) {
110924
111613
  if (!resolution) {
110925
111614
  return null;
@@ -111008,6 +111697,23 @@ class BrokerLocalInvocationService {
111008
111697
  endpoint = await this.options.endpointResolver.prepareLocalEndpointForInvocation(endpoint);
111009
111698
  }
111010
111699
  } catch (error48) {
111700
+ if (isCodexThreadHeldExternallyError(error48)) {
111701
+ const checkedAt = this.now();
111702
+ await this.options.transitionInvocation(invocation.id, {
111703
+ state: "queued",
111704
+ summary: `${target2.displayName}'s Codex thread is open in another app. Message stored; will deliver when the thread is released.`,
111705
+ metadata: {
111706
+ dispatchOutcome: {
111707
+ status: "queued_until_online",
111708
+ reason: "thread_held_externally",
111709
+ checkedAt
111710
+ },
111711
+ heldThreadId: error48.threadId
111712
+ }
111713
+ });
111714
+ this.options.deferInvocationRetry?.(invocation.id, checkedAt + HELD_THREAD_RETRY_DELAY_MS);
111715
+ return;
111716
+ }
111011
111717
  const message = error48 instanceof Error ? error48.message : String(error48);
111012
111718
  const failedFlight = await this.options.transitionInvocation(invocation.id, {
111013
111719
  state: "failed",
@@ -111345,6 +112051,36 @@ class BrokerLocalInvocationService {
111345
112051
  }
111346
112052
  return;
111347
112053
  }
112054
+ if (isCodexThreadHeldExternallyError(error48)) {
112055
+ const checkedAt = this.now();
112056
+ if (!this.currentFlightIsTerminal(invocation.id)) {
112057
+ await this.options.transitionInvocation(invocation.id, {
112058
+ state: "queued",
112059
+ summary: `${target2.displayName}'s Codex thread is open in another app. Message stored; will deliver when the thread is released.`,
112060
+ error: undefined,
112061
+ completedAt: undefined,
112062
+ metadata: {
112063
+ dispatchOutcome: {
112064
+ status: "queued_until_online",
112065
+ reason: "thread_held_externally",
112066
+ checkedAt
112067
+ },
112068
+ heldThreadId: error48.threadId
112069
+ }
112070
+ });
112071
+ }
112072
+ this.options.deferInvocationRetry?.(invocation.id, checkedAt + HELD_THREAD_RETRY_DELAY_MS);
112073
+ await this.options.persistEndpoint({
112074
+ ...runningEndpoint,
112075
+ state: priorEndpointState,
112076
+ metadata: {
112077
+ ...runningEndpoint.metadata ?? {},
112078
+ lastNotice: message,
112079
+ threadHeldExternallyAt: checkedAt
112080
+ }
112081
+ });
112082
+ return;
112083
+ }
111348
112084
  const failedFlight = this.currentFlightIsTerminal(invocation.id) ? null : await this.options.transitionInvocation(invocation.id, {
111349
112085
  state: "failed",
111350
112086
  summary: `${target2.displayName} failed to respond.`,
@@ -111578,7 +112314,7 @@ function resolveProjectProvisionalAgentName(input) {
111578
112314
  }
111579
112315
 
111580
112316
  // packages/runtime/src/session-locator.ts
111581
- import { existsSync as existsSync45, readdirSync as readdirSync14, readFileSync as readFileSync26, statSync as statSync15 } from "fs";
112317
+ import { existsSync as existsSync45, readdirSync as readdirSync14, readFileSync as readFileSync26, statSync as statSync16 } from "fs";
111582
112318
  import { homedir as homedir38 } from "os";
111583
112319
  import { basename as basename23, join as join55, resolve as resolve21 } from "path";
111584
112320
  var CODEX_HARNESS = "codex";
@@ -111595,7 +112331,7 @@ function pathExists4(path7) {
111595
112331
  }
111596
112332
  function safeStatMtimeMs(path7) {
111597
112333
  try {
111598
- return statSync15(path7).mtimeMs;
112334
+ return statSync16(path7).mtimeMs;
111599
112335
  } catch {
111600
112336
  return 0;
111601
112337
  }
@@ -111615,7 +112351,7 @@ function walkFiles(root, predicate, into = [], depth = 0) {
111615
112351
  const full = join55(root, name2);
111616
112352
  let isDir = false;
111617
112353
  try {
111618
- isDir = statSync15(full).isDirectory();
112354
+ isDir = statSync16(full).isDirectory();
111619
112355
  } catch {
111620
112356
  continue;
111621
112357
  }
@@ -112168,7 +112904,7 @@ function throwIfAborted2(signal) {
112168
112904
  }
112169
112905
  function json2(response, status, payload) {
112170
112906
  response.writeHead(status, { "content-type": "application/json; charset=utf-8" });
112171
- response.end(JSON.stringify(payload, null, 2));
112907
+ response.end(JSON.stringify(payload));
112172
112908
  }
112173
112909
  function a2aJson(response, status, payload, headers = {}) {
112174
112910
  response.writeHead(status, {
@@ -112176,14 +112912,14 @@ function a2aJson(response, status, payload, headers = {}) {
112176
112912
  ...headers,
112177
112913
  "content-type": `${A2A_JSON_RPC_CONTENT_TYPE}; charset=utf-8`
112178
112914
  });
112179
- response.end(JSON.stringify(payload, null, 2));
112915
+ response.end(JSON.stringify(payload));
112180
112916
  }
112181
112917
  function jsonWithHeaders(response, status, payload, headers) {
112182
112918
  response.writeHead(status, {
112183
112919
  ...headers,
112184
112920
  "content-type": "application/json; charset=utf-8"
112185
112921
  });
112186
- response.end(JSON.stringify(payload, null, 2));
112922
+ response.end(JSON.stringify(payload));
112187
112923
  }
112188
112924
  var MAX_SERVER_TIMING_HEADER_LENGTH = 2048;
112189
112925
  var TRUNCATED_SERVER_TIMING_HEADER = 'server-timing-truncated;desc="oversize"';
@@ -114710,7 +115446,10 @@ function createBrokerHttpRouter(deps) {
114710
115446
  return;
114711
115447
  }
114712
115448
  if (method === "GET" && (url2.pathname === "/v1/snapshot" || url2.pathname === "/v1/mesh/snapshot")) {
114713
- json2(response, 200, await brokerService.readSnapshot({ since: parseSince(url2) }));
115449
+ json2(response, 200, await brokerService.readSnapshot({
115450
+ since: parseSince(url2),
115451
+ scope: url2.searchParams.get("scope") === "conversations" ? "conversations" : undefined
115452
+ }));
114714
115453
  return;
114715
115454
  }
114716
115455
  if (method === "GET" && url2.pathname === "/v1/capabilities/availability") {
@@ -116016,6 +116755,28 @@ async function discoverMeshNodes(options) {
116016
116755
  };
116017
116756
  }
116018
116757
 
116758
+ // packages/runtime/src/mesh-peer-filter.ts
116759
+ var MESH_PEER_STALE_MS = 24 * 60 * 60 * 1000;
116760
+ function isCurrentMeshPeerNode(node, options) {
116761
+ if (!node.brokerUrl?.trim())
116762
+ return false;
116763
+ if (node.id === options.localNodeId)
116764
+ return false;
116765
+ if (node.advertiseScope !== "mesh")
116766
+ return false;
116767
+ const meshId = options.meshId;
116768
+ if (meshId && node.meshId !== meshId)
116769
+ return false;
116770
+ const now = options.now ?? Date.now();
116771
+ const lastSeen = node.lastSeenAt ?? node.registeredAt ?? 0;
116772
+ if (lastSeen > 0 && now - lastSeen > MESH_PEER_STALE_MS)
116773
+ return false;
116774
+ return true;
116775
+ }
116776
+ function collectCurrentMeshPeerNodes(input) {
116777
+ return Object.values(input.nodes).filter((node) => isCurrentMeshPeerNode(node, input));
116778
+ }
116779
+
116019
116780
  // packages/runtime/src/broker-mesh-discovery-service.ts
116020
116781
  function isNodeLocalProductAgentId(agentId, productAgentIds) {
116021
116782
  return productAgentIds.has(agentId.trim().toLowerCase());
@@ -116074,9 +116835,11 @@ class BrokerMeshDiscoveryService {
116074
116835
  const peersToSync = new Map;
116075
116836
  for (const node of discovered)
116076
116837
  peersToSync.set(node.id, node);
116077
- for (const node of Object.values(this.deps.runtime.snapshot().nodes)) {
116078
- if (node.id === this.deps.nodeId || !node.brokerUrl)
116079
- continue;
116838
+ for (const node of collectCurrentMeshPeerNodes({
116839
+ nodes: this.deps.runtime.snapshot().nodes,
116840
+ localNodeId: this.deps.nodeId,
116841
+ meshId: this.deps.meshId
116842
+ })) {
116080
116843
  peersToSync.set(node.id, node);
116081
116844
  }
116082
116845
  for (const node of peersToSync.values()) {
@@ -117185,14 +117948,28 @@ class BrokerCommandService {
117185
117948
  class BrokerDispatchRecoveryService {
117186
117949
  deps;
117187
117950
  #recoveringInvocationIds = new Set;
117951
+ #deferredInvocations = new Map;
117188
117952
  constructor(deps) {
117189
117953
  this.deps = deps;
117190
117954
  }
117955
+ deferInvocation(invocationId, notBeforeTs) {
117956
+ this.#deferredInvocations.set(invocationId, notBeforeTs);
117957
+ }
117958
+ #isDeferred(invocationId, now) {
117959
+ const notBefore = this.#deferredInvocations.get(invocationId);
117960
+ if (notBefore === undefined)
117961
+ return false;
117962
+ if (now >= notBefore) {
117963
+ this.#deferredInvocations.delete(invocationId);
117964
+ return false;
117965
+ }
117966
+ return true;
117967
+ }
117191
117968
  async recoverQueuedFlights(input) {
117192
117969
  const now = this.deps.now?.() ?? Date.now();
117193
- const jobs = this.deps.dispatchJobs().filter((job) => isInvocationDispatchJobDue(job, now, { includeRunning: true })).filter((job) => !input.agentId || job.targetAgentId === input.agentId).sort((left, right) => left.createdAt - right.createdAt);
117970
+ const jobs = this.deps.dispatchJobs().filter((job) => isInvocationDispatchJobDue(job, now, { includeRunning: true })).filter((job) => !input.agentId || job.targetAgentId === input.agentId).filter((job) => !this.#isDeferred(job.invocationId, now)).sort((left, right) => left.createdAt - right.createdAt);
117194
117971
  const jobInvocationIds = new Set(jobs.map((job) => job.invocationId));
117195
- const queued = Object.values(this.deps.runtimeSnapshot().flights).filter((flight) => flight.state === "queued" || flight.state === "waking").filter((flight) => !input.agentId || flight.targetAgentId === input.agentId).filter((flight) => !jobInvocationIds.has(flight.invocationId)).sort((left, right) => flightSortTime(left) - flightSortTime(right));
117972
+ const queued = Object.values(this.deps.runtimeSnapshot().flights).filter((flight) => flight.state === "queued" || flight.state === "waking").filter((flight) => !input.agentId || flight.targetAgentId === input.agentId).filter((flight) => !jobInvocationIds.has(flight.invocationId)).filter((flight) => !this.#isDeferred(flight.invocationId, now)).sort((left, right) => flightSortTime(left) - flightSortTime(right));
117196
117973
  const result = {
117197
117974
  considered: jobs.length + queued.length,
117198
117975
  dispatched: 0,
@@ -117259,10 +118036,14 @@ class BrokerHomeService {
117259
118036
  }
117260
118037
  async read() {
117261
118038
  const snapshot = this.#deps.runtimeSnapshot();
118039
+ const projectionStatus = this.#deps.projectionStatus?.() ?? { state: "ready" };
118040
+ const projectionReady = projectionStatus.state === "ready";
117262
118041
  return {
117263
118042
  updatedAt: this.#now(),
117264
118043
  agents: this.#agents(snapshot),
117265
- activity: this.#activity(snapshot, await this.#deps.listActivityItems({ limit: 96 }))
118044
+ activity: projectionReady ? this.#activity(snapshot, await this.#deps.listActivityItems({ limit: 96 })) : this.#runtimeActivity(snapshot),
118045
+ activitySource: projectionReady ? "sqlite_projection" : "runtime_snapshot",
118046
+ activityState: projectionStatus.state
117266
118047
  };
117267
118048
  }
117268
118049
  #agents(snapshot) {
@@ -117302,6 +118083,22 @@ class BrokerHomeService {
117302
118083
  };
117303
118084
  });
117304
118085
  }
118086
+ #runtimeActivity(snapshot) {
118087
+ return Object.values(snapshot.messages).sort((left, right) => right.createdAt - left.createdAt || right.id.localeCompare(left.id)).slice(0, 24).map((message) => {
118088
+ const actorName = this.#deps.actorDisplayName(snapshot, message.actorId);
118089
+ return {
118090
+ id: message.id,
118091
+ kind: message.class === "system" || message.class === "status" || message.class === "log" ? "system" : "message",
118092
+ actorId: message.actorId,
118093
+ actorName,
118094
+ title: actorName,
118095
+ detail: message.body || null,
118096
+ conversationId: message.conversationId,
118097
+ channel: brokerConversationChannel(snapshot, message.conversationId),
118098
+ timestamp: message.createdAt
118099
+ };
118100
+ });
118101
+ }
117305
118102
  #now() {
117306
118103
  return this.#deps.now?.() ?? Date.now();
117307
118104
  }
@@ -118488,7 +119285,9 @@ var relayAgentSweepIntervalMs = Number.parseInt(process.env.OPENSCOUT_RELAY_AGEN
118488
119285
  var relayAgentIdleTtlMs = Number.parseInt(process.env.OPENSCOUT_RELAY_AGENT_IDLE_TTL_MS ?? String(DEFAULT_RELAY_AGENT_SESSION_IDLE_TTL_MS), 10);
118489
119286
  var runtimeHeartbeatIntervalMs = 30000;
118490
119287
  var repoWatchServeCacheTtlMs = Number.parseInt(process.env.OPENSCOUT_REPO_WATCH_CACHE_TTL_MS ?? "1200000", 10);
119288
+ var tailRecentServeCacheTtlMs = Number.parseInt(process.env.OPENSCOUT_TAIL_RECENT_SERVE_CACHE_TTL_MS ?? "4000", 10);
118491
119289
  var repoWatchRehydrateAfterMs = Number.parseInt(process.env.OPENSCOUT_REPO_WATCH_REHYDRATE_AFTER_MS ?? "30000", 10);
119290
+ var startupBoundaryTestDelayMs = Number.parseInt(process.env.OPENSCOUT_TEST_STARTUP_BOUNDARY_DELAY_MS ?? "0", 10);
118492
119291
  var meshGateMode = resolveMeshGateMode(process.env);
118493
119292
  ensureOpenScoutCleanSlateSync();
118494
119293
  var existingBroker = await probeExistingBroker();
@@ -118504,7 +119303,7 @@ nodeId = resolveStableLocalNodeId({
118504
119303
  supportDirectory
118505
119304
  });
118506
119305
  var journal = new FileBackedBrokerJournal(journalPath);
118507
- await journal.load();
119306
+ var journalLoadReport = await journal.load();
118508
119307
  var initialSnapshot = journal.snapshot();
118509
119308
  assertNoReservedStoredAgentNames(initialSnapshot.agents, { localNodeId: nodeId });
118510
119309
  var sqliteDisabled = process.env.OPENSCOUT_DISABLE_SQLITE === "1";
@@ -118514,6 +119313,8 @@ if (!sqliteDisabled) {
118514
119313
  await mkdir14(dirname33(dbPath2), { recursive: true });
118515
119314
  }
118516
119315
  var projection = new RecoverableSQLiteProjection(dbPath2, journal, { disabled: sqliteDisabled });
119316
+ var projectionWarmStarted = false;
119317
+ var bootstrapProjectionOptions = () => projectionWarmStarted ? undefined : { enqueueProjection: false };
118517
119318
  var routeAliasDatabase = sqliteDisabled ? null : openControlPlaneSqliteDatabase(dbPath2, { create: true });
118518
119319
  if (routeAliasDatabase) {
118519
119320
  configureControlPlaneDatabase(routeAliasDatabase);
@@ -119050,7 +119851,7 @@ async function migrateUnqualifiedRelayAgentKeys() {
119050
119851
  async function readRelayAgentRegistrySignature() {
119051
119852
  try {
119052
119853
  const registryPath = resolveOpenScoutSupportPaths().relayAgentsRegistryPath;
119053
- const info = await stat7(registryPath);
119854
+ const info = await stat8(registryPath);
119054
119855
  const contents = await readFile15(registryPath);
119055
119856
  const hash2 = createHash16("sha256").update(contents).digest("base64url");
119056
119857
  return `${info.mtimeMs}:${info.size}:${hash2}`;
@@ -119330,6 +120131,7 @@ var localInvocationService = new BrokerLocalInvocationService({
119330
120131
  createId: createRuntimeId2,
119331
120132
  transitionInvocation,
119332
120133
  persistEndpoint,
120134
+ deferInvocationRetry: (invocationId, notBeforeTs) => dispatchRecoveryService.deferInvocation(invocationId, notBeforeTs),
119333
120135
  postInvocationStatusMessage,
119334
120136
  postConversationMessage,
119335
120137
  existingBrokerReplyForInvocation,
@@ -119696,9 +120498,11 @@ var deliveryAcceptanceService = new BrokerDeliveryAcceptanceService({
119696
120498
  queueOperatorSignal: (input) => operatorAttentionService.queueOperatorSignal(input),
119697
120499
  warn: (message, detail) => console.warn(message, detail)
119698
120500
  });
120501
+ var startupTrafficGate = new BrokerStartupTrafficGate;
119699
120502
  var homeService = new BrokerHomeService({
119700
120503
  runtimeSnapshot: () => runtime.snapshot(),
119701
120504
  listActivityItems: (options) => projection.listActivityItems(options),
120505
+ projectionStatus: () => projection.statusSnapshot(),
119702
120506
  actorDisplayName: brokerActorDisplayName2,
119703
120507
  operatorActorId
119704
120508
  });
@@ -119714,6 +120518,7 @@ var brokerService = createBrokerCoreService({
119714
120518
  isReconciledStaleFlightActivityItem,
119715
120519
  readChildServices: () => webControl.readChildServiceSnapshots(),
119716
120520
  readProjectionStatus: () => projection.statusSnapshot(),
120521
+ readStartupStatus: () => startupTrafficGate.snapshot(),
119717
120522
  readHome: () => homeService.read(),
119718
120523
  readCapabilities: readBrokerCapabilityMatrixSnapshot,
119719
120524
  readRuntimeCatalog: readBrokerRuntimeCatalogSnapshot,
@@ -119732,9 +120537,9 @@ var brokerRepoTailService = new BrokerRepoTailService({
119732
120537
  readRecentTranscriptEvents,
119733
120538
  repoWatchServeCacheTtlMs,
119734
120539
  repoWatchRehydrateAfterMs,
120540
+ tailRecentServeCacheTtlMs,
119735
120541
  warn: (message) => console.warn(message)
119736
120542
  });
119737
- registerActiveScoutBrokerService(brokerService);
119738
120543
  var rendezvousService = new BrokerRendezvousService;
119739
120544
  var routeRequest = createBrokerHttpRouter({
119740
120545
  host,
@@ -119878,12 +120683,7 @@ function openRolesControlPlaneDb() {
119878
120683
  }
119879
120684
  function createBrokerHttpServer() {
119880
120685
  return createServer((request, response) => {
119881
- meshIngressGate.gateHttpRequest(request, response, (gatedRequest) => routeRequest(gatedRequest, response).catch((error48) => {
119882
- json2(response, 500, {
119883
- error: "internal_error",
119884
- detail: error48 instanceof Error ? error48.message : String(error48)
119885
- });
119886
- })).catch((error48) => {
120686
+ meshIngressGate.gateHttpRequest(request, response, (gatedRequest) => routeBrokerHttpRequest(gatedRequest, response)).catch((error48) => {
119887
120687
  json2(response, 500, {
119888
120688
  error: "internal_error",
119889
120689
  detail: error48 instanceof Error ? error48.message : String(error48)
@@ -119891,6 +120691,22 @@ function createBrokerHttpServer() {
119891
120691
  });
119892
120692
  });
119893
120693
  }
120694
+ async function routeBrokerHttpRequest(request, response) {
120695
+ if (!startupTrafficGate.admits(request.method, request.url ?? "/")) {
120696
+ json2(response, 503, {
120697
+ error: "broker_restoring",
120698
+ detail: "Recovery reads are available; this route will resume after the startup projection boundary is established.",
120699
+ retryable: true
120700
+ });
120701
+ return;
120702
+ }
120703
+ await routeRequest(request, response).catch((error48) => {
120704
+ json2(response, 500, {
120705
+ error: "internal_error",
120706
+ detail: error48 instanceof Error ? error48.message : String(error48)
120707
+ });
120708
+ });
120709
+ }
119894
120710
  var server = createBrokerHttpServer();
119895
120711
  var socketServer = createBrokerHttpServer();
119896
120712
  server.on("close", () => {
@@ -119923,12 +120739,7 @@ var secretRedaction = await bootstrapSecretRedaction({ patchConsole: true });
119923
120739
  console.log(`[openscout-runtime] secret redaction armed (${secretRedaction.registered} value(s)${secretRedaction.schemaPath ? `, schema ${secretRedaction.schemaPath}` : ", no .env.schema found"})`);
119924
120740
  try {
119925
120741
  let handleBrokerHttp = function(request, response) {
119926
- meshIngressGate.gateHttpRequest(request, response, (gatedRequest) => routeRequest(gatedRequest, response).catch((error48) => {
119927
- json2(response, 500, {
119928
- error: "internal_error",
119929
- detail: error48 instanceof Error ? error48.message : String(error48)
119930
- });
119931
- })).catch((error48) => {
120742
+ meshIngressGate.gateHttpRequest(request, response, (gatedRequest) => routeBrokerHttpRequest(gatedRequest, response)).catch((error48) => {
119932
120743
  json2(response, 500, {
119933
120744
  error: "internal_error",
119934
120745
  detail: error48 instanceof Error ? error48.message : String(error48)
@@ -119939,8 +120750,7 @@ try {
119939
120750
  console.log(`[openscout-runtime] secret redaction armed (${secretRedaction2.registered} value(s)${secretRedaction2.schemaPath ? `, schema ${secretRedaction2.schemaPath}` : ", no .env.schema found"})`);
119940
120751
  await listenTcp(server, { host: isLoopbackHost(host) || host === "0.0.0.0" || host === "::" ? "127.0.0.1" : host, port });
119941
120752
  await listenUnixSocket(socketServer, brokerSocketPath);
119942
- projection.warm();
119943
- upsertNodeDurably(localNode).then(() => upsertActorDurably(systemActor)).catch((error48) => {
120753
+ const bootstrapIdentityWrite = upsertNodeDurably(localNode, bootstrapProjectionOptions()).then(() => upsertActorDurably(systemActor, bootstrapProjectionOptions())).catch((error48) => {
119944
120754
  console.error("[openscout-runtime] bootstrap identity persistence failed:", error48);
119945
120755
  });
119946
120756
  meshBindController = createMeshBindController({
@@ -119956,7 +120766,7 @@ try {
119956
120766
  brokerUrl = state.brokerUrl;
119957
120767
  const nextNode = localNodeWithBindState(currentLocalNode(), state);
119958
120768
  Object.assign(localNode, nextNode);
119959
- await upsertNodeDurably(nextNode).catch((error48) => {
120769
+ await upsertNodeDurably(nextNode, bootstrapProjectionOptions()).catch((error48) => {
119960
120770
  console.warn("[openscout-runtime] mesh bind: failed to update node registry:", error48);
119961
120771
  });
119962
120772
  await writeHostInfo().catch((error48) => {
@@ -119970,14 +120780,13 @@ try {
119970
120780
  advertiseScope = state.scope;
119971
120781
  brokerUrl = state.brokerUrl;
119972
120782
  Object.assign(localNode, localNodeWithBindState(localNode, state));
119973
- await upsertNodeDurably(localNode).catch(() => {
120783
+ await upsertNodeDurably(localNode, bootstrapProjectionOptions()).catch(() => {
119974
120784
  return;
119975
120785
  });
119976
120786
  }
119977
120787
  await writeHostInfo().catch((error48) => {
119978
120788
  console.warn("[openscout-runtime] failed to write .host-info:", error48);
119979
120789
  });
119980
- peerDelivery.start();
119981
120790
  const meshRendezvousConfig = resolveMeshRendezvousPublishConfig();
119982
120791
  if (meshRendezvousConfig) {
119983
120792
  meshRendezvousPublisher = startMeshRendezvousPublisher(currentRendezvousNode, {
@@ -119985,6 +120794,15 @@ try {
119985
120794
  logger: console
119986
120795
  });
119987
120796
  }
120797
+ if (Number.isFinite(startupBoundaryTestDelayMs) && startupBoundaryTestDelayMs > 0) {
120798
+ await sleep3(startupBoundaryTestDelayMs);
120799
+ }
120800
+ await bootstrapIdentityWrite;
120801
+ projectionWarmStarted = true;
120802
+ await projection.warm();
120803
+ startupTrafficGate.admitMutations();
120804
+ registerActiveScoutBrokerService(brokerService);
120805
+ peerDelivery.start();
119988
120806
  console.log(`[openscout-runtime] broker listening on 127.0.0.1:${port} (scope: ${advertiseScope}, url: ${brokerUrl})`);
119989
120807
  console.log(`[openscout-runtime] broker local socket ${brokerSocketPath}`);
119990
120808
  const bindState = meshBindController.getState();
@@ -119996,6 +120814,7 @@ try {
119996
120814
  console.log(`[openscout-runtime] node ${nodeId} in mesh ${meshId}`);
119997
120815
  console.log(`[openscout-runtime] mesh trust: keyId ${nodeIdentityKeyId} fingerprint ${nodeIdentityFingerprint} (gate: ${effectiveGateMode()})`);
119998
120816
  console.log(`[openscout-runtime] journal ${journalPath}`);
120817
+ console.log(`[openscout-runtime] journal load ${journalLoadReport.totalMs}ms (scan ${journalLoadReport.scanMs}ms, compaction ${journalLoadReport.compactionMs}ms, ${journalLoadReport.validEntries} entries, ${journalLoadReport.sourceBytes} -> ${journalLoadReport.compactedBytes} bytes)`);
119999
120818
  console.log(`[openscout-runtime] sqlite ${sqliteDisabled ? "disabled" : dbPath2}`);
120000
120819
  } catch (error48) {
120001
120820
  unregisterActiveScoutBrokerService(brokerService);
@@ -120091,6 +120910,11 @@ if (Number.isFinite(relayAgentSweepIntervalMs) && relayAgentSweepIntervalMs > 0)
120091
120910
  setInterval(() => {
120092
120911
  sweepAndCompactMeshNodes();
120093
120912
  }, 900000).unref();
120913
+ setInterval(() => {
120914
+ dispatchRecoveryService.recoverQueuedFlights({ reason: "queued_retry_sweep" }).catch((error48) => {
120915
+ console.error("[openscout-runtime] queued dispatch retry sweep failed:", error48);
120916
+ });
120917
+ }, 60000).unref();
120094
120918
  if (routeAliasService) {
120095
120919
  setInterval(() => {
120096
120920
  routeAliasService.sweepExpired();