@openscout/scout 0.2.95 → 0.2.96

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 (360) hide show
  1. package/bin/scout +26 -10
  2. package/bin/scoutd +0 -0
  3. package/dist/build-manifest.json +3 -3
  4. package/dist/client/assets/{ActivityScreen--eANwuxa.js → ActivityScreen-BnoaUkVZ.js} +1 -1
  5. package/dist/client/assets/{AddProjectForm-CcD6qvV8.js → AddProjectForm-IqOtJfRs.js} +1 -1
  6. package/dist/client/assets/{AgentAvatar-CYhf6twS.js → AgentAvatar-6-KBVKUu.js} +1 -1
  7. package/dist/client/assets/{AgentConfigurationScreen-BTI24HQX.js → AgentConfigurationScreen-CuZJy07q.js} +1 -1
  8. package/dist/client/assets/{AgentDefinitionsWorkspace-srmN6-vj.js → AgentDefinitionsWorkspace-Iyl4BesU.js} +1 -1
  9. package/dist/client/assets/{AgentDetailCard-UqPNpcvB.js → AgentDetailCard-C9rn3Fj5.js} +1 -1
  10. package/dist/client/assets/{AgentFloorView-XXNgI5Cj.js → AgentFloorView-YT-Jjccf.js} +1 -1
  11. package/dist/client/assets/{AgentInfoScreen-CimdOnZ9.js → AgentInfoScreen-Dr99gQEZ.js} +1 -1
  12. package/dist/client/assets/{AgentLaneCard-Z-aOBR3W.js → AgentLaneCard-DI2iW9zO.js} +1 -1
  13. package/dist/client/assets/{AgentLaneChrome-CyhA1reW.js → AgentLaneChrome-D8bARHMx.js} +1 -1
  14. package/dist/client/assets/{AgentLaneDetailSheet-BNzjMjIH.js → AgentLaneDetailSheet-52un7dKC.js} +1 -1
  15. package/dist/client/assets/{AgentLaneSummaryResize-Box8-_rS.js → AgentLaneSummaryResize-CEBjmPTa.js} +1 -1
  16. package/dist/client/assets/AgentLanesEmbedScreen-Dgcm7zd_.js +1 -0
  17. package/dist/client/assets/AgentLanesPreflight-q20mTjms.js +1 -0
  18. package/dist/client/assets/AgentLanesView-CetZZDyF.js +2 -0
  19. package/dist/client/assets/{AgentLiveActions-BwuzOE8h.js → AgentLiveActions-DrEJDJef.js} +1 -1
  20. package/dist/client/assets/AgentMasterScreen-DJPnstoD.js +1 -0
  21. package/dist/client/assets/{AgentSessions-CsZwoukw.js → AgentSessions-DCPCG4xb.js} +1 -1
  22. package/dist/client/assets/{AgentsConsole-KCao4XmX.js → AgentsConsole-CsYOoFJi.js} +1 -1
  23. package/dist/client/assets/{AgentsScreen-CtPAmwRX.js → AgentsScreen-k8LvBuU_.js} +1 -1
  24. package/dist/client/assets/AgentsSubnav-C4xpQhsv.js +1 -0
  25. package/dist/client/assets/{AstronautSuit-Ckx7lu7G.js → AstronautSuit-DbjQtfD_.js} +1 -1
  26. package/dist/client/assets/{AtopView-DYlpgEHf.js → AtopView-Daq_ob3z.js} +1 -1
  27. package/dist/client/assets/{BackToPicker-4JaeRvDm.js → BackToPicker-CXZjBRAe.js} +1 -1
  28. package/dist/client/assets/{BriefingDetailScreen-D6-xqrpo.js → BriefingDetailScreen-CUCXO-KH.js} +1 -1
  29. package/dist/client/assets/{BriefingsScreen-DKxSDEmk.js → BriefingsScreen-B5oMTGKv.js} +1 -1
  30. package/dist/client/assets/{BrokerMetadataPanel-BbREmsbK.js → BrokerMetadataPanel-BsiU8lTD.js} +1 -1
  31. package/dist/client/assets/{BrokerScreen-fbPIouMw.js → BrokerScreen-BPbOHhCS.js} +1 -1
  32. package/dist/client/assets/{CastPicker-BcA2vDDV.js → CastPicker-_5E5hNUe.js} +1 -1
  33. package/dist/client/assets/ChatCollapsedStrip-D-eXhzPf.js +1 -0
  34. package/dist/client/assets/{CodeDiffPane-Cn8Y9hAt.js → CodeDiffPane-n7W4iGUG.js} +1 -1
  35. package/dist/client/assets/{CodeProjectPicker-nPFktrco.js → CodeProjectPicker-CMsbSTDq.js} +1 -1
  36. package/dist/client/assets/{CodeScreen-BlAxtxE5.js → CodeScreen-CeuO3EhR.js} +1 -1
  37. package/dist/client/assets/{ConversationComposer-2HjbGPL9.js → ConversationComposer-CXPKx86g.js} +1 -1
  38. package/dist/client/assets/{ConversationFeedRows-C6wUqJrx.js → ConversationFeedRows-WrH-YI3L.js} +1 -1
  39. package/dist/client/assets/{ConversationHeader-C8vfXaTF.js → ConversationHeader-BQWzGzLK.js} +1 -1
  40. package/dist/client/assets/{ConversationPanels-CNCIbpqU.js → ConversationPanels-Dujvnmup.js} +2 -2
  41. package/dist/client/assets/ConversationScreen-CR9pWB65.js +2 -0
  42. package/dist/client/assets/{ConversationStatus-DZuyKsWN.js → ConversationStatus-DVzSb2Hv.js} +1 -1
  43. package/dist/client/assets/{CrewAvatar-CTIuxp4G.js → CrewAvatar-BwXjyg8N.js} +1 -1
  44. package/dist/client/assets/CrewWorkspaces-CkQDhyie.css +1 -0
  45. package/dist/client/assets/CrewWorkspaces-NKujRzwh.js +1 -0
  46. package/dist/client/assets/{DataTable-6IDhanr5.js → DataTable-Bp8tU9AK.js} +1 -1
  47. package/dist/client/assets/{DispatchAftermath-DC1u9itO.js → DispatchAftermath-B-6rmXzL.js} +1 -1
  48. package/dist/client/assets/{DocumentFocusViewer-DZVhS7as.js → DocumentFocusViewer-Do3wQ_3Z.js} +1 -1
  49. package/dist/client/assets/{EmbeddableSurfacesLab-BKUFJMCV.js → EmbeddableSurfacesLab-C1orRyP9.js} +1 -1
  50. package/dist/client/assets/{EmptyState-CeBl0iGd.js → EmptyState-CJzXj1l5.js} +1 -1
  51. package/dist/client/assets/{FileViewerPane-DQlpNt2S.js → FileViewerPane-Df6VzXjA.js} +1 -1
  52. package/dist/client/assets/FlightObserveScreen-6mGnmWQA.js +1 -0
  53. package/dist/client/assets/{FollowScreen-BXHOp3gb.js → FollowScreen-DvnxYLVh.js} +1 -1
  54. package/dist/client/assets/{HarnessMark-D5CA5uSp.js → HarnessMark-B979GCSB.js} +1 -1
  55. package/dist/client/assets/{HarnessesScreen-DhFXq1qz.js → HarnessesScreen-CHTuv8p6.js} +1 -1
  56. package/dist/client/assets/{HerdrSession-BRhs5LIR.js → HerdrSession-B3McuYgi.js} +1 -1
  57. package/dist/client/assets/{HomeHero-DMABJuze.js → HomeHero-CdUVPjkG.js} +1 -1
  58. package/dist/client/assets/{HostAdvisorView-RAociATV.js → HostAdvisorView-Bok5Sk5c.js} +1 -1
  59. package/dist/client/assets/{KnowledgeSearchInspector-CZPyVNSw.js → KnowledgeSearchInspector-B7XSoJsu.js} +1 -1
  60. package/dist/client/assets/{KnowledgeSearchScreen-mGTKIg00.js → KnowledgeSearchScreen-D3o3IODW.js} +1 -1
  61. package/dist/client/assets/{LaneToolHoverCard-D_DMlBeT.js → LaneToolHoverCard-HByf2ndx.js} +1 -1
  62. package/dist/client/assets/{LaneTraceDetailSheet-BEHg3LmH.js → LaneTraceDetailSheet-BUgHz-sd.js} +1 -1
  63. package/dist/client/assets/{LaneTraceEventFocus-DVimcizS.js → LaneTraceEventFocus-DM-hoPxG.js} +1 -1
  64. package/dist/client/assets/{MeshCanvas-BOuZx4AM.js → MeshCanvas-DCLJRsBy.js} +1 -1
  65. package/dist/client/assets/{MeshCanvasMinimap-wL-1N94e.js → MeshCanvasMinimap-cEFS9eW7.js} +1 -1
  66. package/dist/client/assets/{MeshScreen-DMY9Bmh5.js → MeshScreen-BcxPkhm6.js} +1 -1
  67. package/dist/client/assets/{MeshTopologyView-DiDcX5f4.js → MeshTopologyView-CCRPd8PU.js} +2 -2
  68. package/dist/client/assets/MessagesScreen-Bb5l13MO.js +1 -0
  69. package/dist/client/assets/{MissionContextRail-DrNKXG5u.js → MissionContextRail-DF0_kiU7.js} +1 -1
  70. package/dist/client/assets/{MissionControlView-ByBlHVN8.js → MissionControlView-E3V7bENU.js} +1 -1
  71. package/dist/client/assets/{MissionFocusOverlay-D1i6R6Zt.js → MissionFocusOverlay-h15sQFvP.js} +1 -1
  72. package/dist/client/assets/{MissionLeftAgentRow-DN9NcCML.js → MissionLeftAgentRow-KPdk9rSa.js} +1 -1
  73. package/dist/client/assets/{MissionLogPane-DSeIv3Xo.js → MissionLogPane-BbdDKjUl.js} +1 -1
  74. package/dist/client/assets/{NewAgentModal-V7yK6J6j.js → NewAgentModal-DfHxad34.js} +1 -1
  75. package/dist/client/assets/NewChatComposer-_Stj0fZy.js +19 -0
  76. package/dist/client/assets/{NewChatOrigin-DdpzE4kz.js → NewChatOrigin-B1u7ki70.js} +1 -1
  77. package/dist/client/assets/{ObserveEmbedScreen-l_Q3ts2q.js → ObserveEmbedScreen-Co0xTii6.js} +1 -1
  78. package/dist/client/assets/{ObserveTextFlow-BSEtYTxU.js → ObserveTextFlow-ZQWwrK3i.js} +2 -2
  79. package/dist/client/assets/{ObservedTopologyPanel-CdGUXxGR.js → ObservedTopologyPanel-BJUhDSuQ.js} +1 -1
  80. package/dist/client/assets/{OpenScoutAppShell-DN8dOSK4.js → OpenScoutAppShell-CUd2yOLu.js} +25 -25
  81. package/dist/client/assets/{OpsAgentsView-ntGr4pz4.js → OpsAgentsView-DI5wu1si.js} +1 -1
  82. package/dist/client/assets/OpsScreen-D8fQafCl.js +1 -0
  83. package/dist/client/assets/OpsSubnav-1K4Jaf__.js +1 -0
  84. package/dist/client/assets/ProjectAgentProfile-Bdjd_dAx.js +1 -0
  85. package/dist/client/assets/{ProjectAgentProfileBar-BQET-qrY.js → ProjectAgentProfileBar-k2QHHHsQ.js} +1 -1
  86. package/dist/client/assets/{ProjectAgentProfileHero-Ck8mThtx.js → ProjectAgentProfileHero-Bpxk1ui2.js} +1 -1
  87. package/dist/client/assets/ProjectsInbox-C_bMHLCc.js +2 -0
  88. package/dist/client/assets/ProjectsRail-J-aH_pxT.js +1 -0
  89. package/dist/client/assets/ProjectsScreen-cVUkGbPz.js +1 -0
  90. package/dist/client/assets/ProjectsThreadAside-_ourdM-Q.js +1 -0
  91. package/dist/client/assets/{Provider-B2xuo3rf.js → Provider-CtXJeLrP.js} +1 -1
  92. package/dist/client/assets/{RailRow-B-GycCBx.js → RailRow-CEH2MFBw.js} +1 -1
  93. package/dist/client/assets/{RawSessionsTable-AQThi6sm.js → RawSessionsTable-CDyrom-F.js} +1 -1
  94. package/dist/client/assets/RealtimeVoiceScreen-DBl3DN1H.js +1 -0
  95. package/dist/client/assets/{RepoDiffEmbedScreen-DXWoRF_c.js → RepoDiffEmbedScreen-kY2pHjIs.js} +1 -1
  96. package/dist/client/assets/{RepoDiffPageScreen-D_274ExO.js → RepoDiffPageScreen-C6LhoKrn.js} +1 -1
  97. package/dist/client/assets/{RepoDiffViewer-DbedmHDX.js → RepoDiffViewer-BhcIIQQg.js} +1 -1
  98. package/dist/client/assets/{RepoDiffViewerLazy-C0--fPtk.js → RepoDiffViewerLazy-Csy_j9LD.js} +2 -2
  99. package/dist/client/assets/{ReposScreen-D39_YG4H.js → ReposScreen-B_cB0zu7.js} +1 -1
  100. package/dist/client/assets/ScoutDeckSurface-CSy_fjcG.js +1 -0
  101. package/dist/client/assets/{ScoutSurface-UsRy0t-I.js → ScoutSurface-CQVcSrin.js} +1 -1
  102. package/dist/client/assets/{ScoutbotFxLab-Fmdfboxs.js → ScoutbotFxLab-DqGiLYNy.js} +1 -1
  103. package/dist/client/assets/{SecondaryNav-o2RL9H8H.js → SecondaryNav-BR4VRdgh.js} +1 -1
  104. package/dist/client/assets/SessionEmbedScreen-BTlZ9gAg.js +1 -0
  105. package/dist/client/assets/{SessionObserve-Dsd0j05N.js → SessionObserve-dQDN23pP.js} +1 -1
  106. package/dist/client/assets/{SessionObserveEvidence-DopQYDkD.js → SessionObserveEvidence-BRBGKAgd.js} +1 -1
  107. package/dist/client/assets/SessionRefScreen-COVQMbtE.js +1 -0
  108. package/dist/client/assets/SessionsScreen--5OJ3p3v.js +1 -0
  109. package/dist/client/assets/{SettingsDrawer-_AwuopMS.js → SettingsDrawer-RGVK_bmE.js} +1 -1
  110. package/dist/client/assets/{SettingsScreen-Cw4DDfJP.js → SettingsScreen-CCxzy5IU.js} +1 -1
  111. package/dist/client/assets/{ShikiPane-BfHc_3pM.js → ShikiPane-DYI9Hkge.js} +1 -1
  112. package/dist/client/assets/{SlidePanel-C-q7XwTa.js → SlidePanel-B9ugxWgA.js} +1 -1
  113. package/dist/client/assets/{SpriteAvatar-Bs68ZENy.js → SpriteAvatar-z5hHesx9.js} +1 -1
  114. package/dist/client/assets/{StatusPill-ZZQwxB1a.js → StatusPill-BFvMjmZV.js} +1 -1
  115. package/dist/client/assets/{TailView-Q4FVMsUH.js → TailView-0uEIj2JH.js} +1 -1
  116. package/dist/client/assets/{Terminal-D7zqHwHV.js → Terminal-DouZeNxc.js} +1 -1
  117. package/dist/client/assets/{TerminalEmbedScreen-CXIJ7qv6.js → TerminalEmbedScreen-dMNUbzXr.js} +1 -1
  118. package/dist/client/assets/{TerminalHeaderMount-BnBLOPbb.js → TerminalHeaderMount-BL07cd0q.js} +1 -1
  119. package/dist/client/assets/{TextDocumentSurface-CKQP-cBT.js → TextDocumentSurface-BflAwXeZ.js} +1 -1
  120. package/dist/client/assets/{TmuxPeek-V9dGESfO.js → TmuxPeek-BTnjOQi0.js} +1 -1
  121. package/dist/client/assets/{VoicePermissionsPanel-k7sbLXx2.js → VoicePermissionsPanel-CgQ6GGS-.js} +1 -1
  122. package/dist/client/assets/{WorkDetailScreen-60p9litn.js → WorkDetailScreen-CaLG-zDs.js} +1 -1
  123. package/dist/client/assets/{WorkFilesViewer-BjJS7GyM.js → WorkFilesViewer-B9Sil_No.js} +1 -1
  124. package/dist/client/assets/{activity-Bj3Hnbj3.js → activity-DcrMApUY.js} +1 -1
  125. package/dist/client/assets/{addon-fit-BL-NTWRU.js → addon-fit-DMVrz5Sv.js} +1 -1
  126. package/dist/client/assets/{addon-webgl-CIMgmNjg.js → addon-webgl-BYvpZUyu.js} +1 -1
  127. package/dist/client/assets/{agent-autocomplete-DXlvdc4b.js → agent-autocomplete-B-5QTeas.js} +1 -1
  128. package/dist/client/assets/{agent-essentials-BOMHR0_U.js → agent-essentials-D7KRGYvF.js} +1 -1
  129. package/dist/client/assets/{agent-lane-card-model-CTLxf3R4.js → agent-lane-card-model-CNZMPkhc.js} +1 -1
  130. package/dist/client/assets/{agent-lanes-model-AfrjRNK5.js → agent-lanes-model-DXqjs0OK.js} +2 -2
  131. package/dist/client/assets/agent-master-I1W-5d-x.css +1 -0
  132. package/dist/client/assets/agent-master-model-DqjrVI2h.js +1 -0
  133. package/dist/client/assets/{agent-specialization-BIPIBW8u.js → agent-specialization-BujJVUTD.js} +1 -1
  134. package/dist/client/assets/{arc.es-IR5r6sj_.js → arc.es-NHqHWohb.js} +1 -1
  135. package/dist/client/assets/{arrow-down-BydciYFZ.js → arrow-down-CKtSUjmW.js} +1 -1
  136. package/dist/client/assets/{arrow-left-CghA0kTw.js → arrow-left-Czpf-AE4.js} +1 -1
  137. package/dist/client/assets/{arrow-right-iJFv3jNh.js → arrow-right-BuzMnLYP.js} +1 -1
  138. package/dist/client/assets/{arrow-up-right-CCfZXPqD.js → arrow-up-right-C6Wl-1uw.js} +1 -1
  139. package/dist/client/assets/{bot-B5sub1-i.js → bot-rd0awxD3.js} +1 -1
  140. package/dist/client/assets/{check-C18YQC90.js → check-ofKUE8yH.js} +1 -1
  141. package/dist/client/assets/{chevron-down-Mp9mu_yd.js → chevron-down-wciXnOQz.js} +1 -1
  142. package/dist/client/assets/{chevron-right-CzH-TaSF.js → chevron-right-D-HdlPg8.js} +1 -1
  143. package/dist/client/assets/{chunk-HRAB3GC3-swV8PA2k.js → chunk-HRAB3GC3-Tyv9rzx7.js} +1 -1
  144. package/dist/client/assets/{chunk-JTPDIGGW-BKXqcLKw.js → chunk-JTPDIGGW-BC2Mandc.js} +3 -3
  145. package/dist/client/assets/{chunk-T65CQEWV-vYbNJ8E6.js → chunk-T65CQEWV-C1AWTYZZ.js} +1 -1
  146. package/dist/client/assets/{chunk-YOZR3KYS-U65yUmqt.js → chunk-YOZR3KYS-DwHPHa6f.js} +1 -1
  147. package/dist/client/assets/{clock-B4PTFi5m.js → clock-B88r8OrZ.js} +1 -1
  148. package/dist/client/assets/{code-xml-Jtxsp5d1.js → code-xml-D7pOQM9l.js} +1 -1
  149. package/dist/client/assets/{compass-0_54-vz3.js → compass-Dt1AMXz2.js} +1 -1
  150. package/dist/client/assets/content-9K38QchR.js +1 -0
  151. package/dist/client/assets/content-BRgnyXWh.js +1 -0
  152. package/dist/client/assets/{content-CHghn-rT.js → content-BWPNyXJ0.js} +1 -1
  153. package/dist/client/assets/content-BdkI07v3.js +1 -0
  154. package/dist/client/assets/content-C4oWa8SB.js +1 -0
  155. package/dist/client/assets/content-C9ijJxyl.js +1 -0
  156. package/dist/client/assets/content-CFZ4rghn.js +1 -0
  157. package/dist/client/assets/content-CIqu_Ci_.js +1 -0
  158. package/dist/client/assets/content-CnJF9DGO.js +1 -0
  159. package/dist/client/assets/content-CriW8Y8u.js +1 -0
  160. package/dist/client/assets/content-DDCyPPk_.js +1 -0
  161. package/dist/client/assets/content-DtcZeh5m.js +1 -0
  162. package/dist/client/assets/content-U9tsdtle.js +1 -0
  163. package/dist/client/assets/content-hFLK3CON.js +1 -0
  164. package/dist/client/assets/{content-DMbawvqU.js → content-nkx0swDe.js} +1 -1
  165. package/dist/client/assets/content-p00KQrtD.js +1 -0
  166. package/dist/client/assets/{conversation-icons-BV10B2Me.js → conversation-icons-tp9BX6X2.js} +1 -1
  167. package/dist/client/assets/{conversation-model-CwF6Y9gx.js → conversation-model-Dc02NsGp.js} +1 -1
  168. package/dist/client/assets/conversation-motion-features-D9-RmBSq.js +1 -0
  169. package/dist/client/assets/{copy-Dtpx4FOE.js → copy-CWWAJ75H.js} +1 -1
  170. package/dist/client/assets/{cpu-BjVis9mc.js → cpu-DrqejfkB.js} +1 -1
  171. package/dist/client/assets/{createLucideIcon-DXpqZP7I.js → createLucideIcon-DezKXSG2.js} +1 -1
  172. package/dist/client/assets/{ctx-panel-D_HJ3nhb.css → ctx-panel-F05jXK4Q.css} +1 -1
  173. package/dist/client/assets/discover-C2CZO4Tk.js +2 -0
  174. package/dist/client/assets/embed-entry-BSMUykuG.js +2 -0
  175. package/dist/client/assets/{external-link-Ckiyzjwo.js → external-link-Dp_a2vRZ.js} +1 -1
  176. package/dist/client/assets/{eye-CpfyvdLq.js → eye-BRyD0jno.js} +1 -1
  177. package/dist/client/assets/{file-code-corner-7mo7EviR.js → file-code-corner-muIVH_xO.js} +1 -1
  178. package/dist/client/assets/{file-text-KijGBnME.js → file-text-CqJgwxmv.js} +1 -1
  179. package/dist/client/assets/{gauge-y-Xg8Mrv.js → gauge-hU--hKVP.js} +1 -1
  180. package/dist/client/assets/{gestures-Bq9XnSqY.js → gestures-DN4hEeqv.js} +1 -1
  181. package/dist/client/assets/{git-branch-BQ_x8KZL.js → git-branch-CK5v8F2v.js} +1 -1
  182. package/dist/client/assets/{home-moving-signal-DtRpiNa0.js → home-moving-signal-BjDtEJUP.js} +1 -1
  183. package/dist/client/assets/{home-now-card-DFb4GOgM.js → home-now-card-nF8OotI-.js} +1 -1
  184. package/dist/client/assets/{home-now-card-nano-D--m9jpq.js → home-now-card-nano-C-r_bBg5.js} +1 -1
  185. package/dist/client/assets/{hooks-9d1SoaQA.js → hooks-D46bABUP.js} +1 -1
  186. package/dist/client/assets/index-CPrU5q04.js +1 -0
  187. package/dist/client/assets/{index-CZ-05hKz.js → index-DvLtl7rV.js} +5 -5
  188. package/dist/client/assets/index-kL1WLbeS.js +1 -0
  189. package/dist/client/assets/index-zvhpRHao.js +1 -0
  190. package/dist/client/assets/{inspector-panel-C-EhEDYy.js → inspector-panel-Dkc7rLvY.js} +1 -1
  191. package/dist/client/assets/{keyboard-nav-DFhAJkW3.js → keyboard-nav-BLYDhL3Z.js} +1 -1
  192. package/dist/client/assets/{lane-roster-store-gUBsydNf.js → lane-roster-store-DOdI1O13.js} +1 -1
  193. package/dist/client/assets/{layers-CGou-LwV.js → layers-CSsg3JVP.js} +1 -1
  194. package/dist/client/assets/{layout-grid-BrZt31QH.js → layout-grid-DOChPJdZ.js} +1 -1
  195. package/dist/client/assets/left-B-SdEJSJ.js +1 -0
  196. package/dist/client/assets/{left-B_o51JV6.js → left-B3wSE6ql.js} +1 -1
  197. package/dist/client/assets/{left-CwHZCGO3.js → left-BNRFiRsb.js} +1 -1
  198. package/dist/client/assets/{left-DA0amyfu.js → left-BggzhgXN.js} +1 -1
  199. package/dist/client/assets/left-CARCvvxS.js +2 -0
  200. package/dist/client/assets/left-CpokZYHt.js +1 -0
  201. package/dist/client/assets/{left-CwLs0okF.js → left-YT7mIGuH.js} +1 -1
  202. package/dist/client/assets/{left-advisor-DU3s01gk.js → left-advisor-CCY0vkcO.js} +1 -1
  203. package/dist/client/assets/left-agents-trhO5sL8.js +1 -0
  204. package/dist/client/assets/{left-default-uvuvDmt0.js → left-default-CG33elBs.js} +1 -1
  205. package/dist/client/assets/{left-lanes-DnNLgec8.js → left-lanes-CitMgeTp.js} +1 -1
  206. package/dist/client/assets/{left-mission-DN3-NLPC.js → left-mission-Zl2m_5eU.js} +1 -1
  207. package/dist/client/assets/{library-DIo5NiGP.js → library-DkALuCh5.js} +1 -1
  208. package/dist/client/assets/{loader-circle-BiohlpM3.js → loader-circle-pM56HNhR.js} +1 -1
  209. package/dist/client/assets/{local-agents-wUIaBcEr.js → local-agents-C8xAhbO5.js} +1 -1
  210. package/dist/client/assets/{mentions-CcPFMbmZ.js → mentions-DG6OQrsc.js} +1 -1
  211. package/dist/client/assets/{mesh-buckets-ByyFXdKT.js → mesh-buckets-6y3ZIibI.js} +1 -1
  212. package/dist/client/assets/{mesh-ops-CvGyjK84.js → mesh-ops-BZ1h5RQs.js} +1 -1
  213. package/dist/client/assets/{mesh-roster-n2nDpEmA.js → mesh-roster-Bc7T4b7z.js} +1 -1
  214. package/dist/client/assets/{mesh-view-store-BpxGm71b.js → mesh-view-store-ChUOASK8.js} +1 -1
  215. package/dist/client/assets/{message-circle-B2ddzBrX.js → message-circle-mZCv8tvB.js} +1 -1
  216. package/dist/client/assets/{message-markup-RkfmDfME.js → message-markup-C2LQDm_k.js} +1 -1
  217. package/dist/client/assets/{message-square-D9YYWE0x.js → message-square-C7t_qtuj.js} +1 -1
  218. package/dist/client/assets/{message-visibility-DwxgcgYK.js → message-visibility-CGOmSSKs.js} +1 -1
  219. package/dist/client/assets/{mission-control-store-Bf4b54MV.js → mission-control-store-nDLdUZPA.js} +1 -1
  220. package/dist/client/assets/{observe-CJRIvOCn.js → observe-BpEm1INu.js} +1 -1
  221. package/dist/client/assets/{page-status-BptpTdQ-.js → page-status-E5jnk48p.js} +1 -1
  222. package/dist/client/assets/{paperclip-B1UNGl5d.js → paperclip-C64lkcbM.js} +1 -1
  223. package/dist/client/assets/{persistent-state-YI-WHSCF.js → persistent-state-EHXw8WNy.js} +1 -1
  224. package/dist/client/assets/{plus-CuU_X0-8.js → plus-Co-dqKul.js} +1 -1
  225. package/dist/client/assets/{profile-rY8jO38P.js → profile-APxDsN2P.js} +1 -1
  226. package/dist/client/assets/projects-inbox-Cg4X2lUQ.js +1 -0
  227. package/dist/client/assets/projects-inbox-DRBl2N85.css +1 -0
  228. package/dist/client/assets/{proxy-DnLpZIi9.js → proxy-BiW5suC7.js} +1 -1
  229. package/dist/client/assets/{radio-Dm1ItnA4.js → radio-BOxBQX-T.js} +1 -1
  230. package/dist/client/assets/{refresh-cw-BRn9Oxxl.js → refresh-cw-DMxGzDwn.js} +1 -1
  231. package/dist/client/assets/resolve-panes-DeVJbS9c.js +1 -0
  232. package/dist/client/assets/resolve-sidebar-context-BQe5J6xF.js +1 -0
  233. package/dist/client/assets/{right-BJltPRnd.js → right-Bmfd3pjP.js} +1 -1
  234. package/dist/client/assets/{right-Beh3nCUB.js → right-BqI-nr9G.js} +1 -1
  235. package/dist/client/assets/{right-D3aTKf1F.js → right-BuCgE0fZ.js} +1 -1
  236. package/dist/client/assets/{right-Shpw_xDy.js → right-BwlW6E57.js} +1 -1
  237. package/dist/client/assets/{right-CPP7GyOm.js → right-C0ybUw0j.js} +1 -1
  238. package/dist/client/assets/{right-BbyYdzHn.js → right-CdkcrmeD.js} +1 -1
  239. package/dist/client/assets/{right-CJnB_Bg7.js → right-CimaAvQN.js} +1 -1
  240. package/dist/client/assets/{right-C1yumXNx.js → right-CkCCPbCX.js} +1 -1
  241. package/dist/client/assets/{right-DI1B79nR.js → right-D3eSiy41.js} +1 -1
  242. package/dist/client/assets/{right-DtsRNX5b.js → right-Dz_xD0Vj.js} +1 -1
  243. package/dist/client/assets/{rocket-DOwXHKWA.js → rocket-BQm5_CvR.js} +1 -1
  244. package/dist/client/assets/router-B9vQkNJL.js +1 -0
  245. package/dist/client/assets/{scope-views-A4_vP97W.js → scope-views-1IYJdl41.js} +1 -1
  246. package/dist/client/assets/{scout-voice-BhPzrc6P.js → scout-voice-BVUqGhth.js} +1 -1
  247. package/dist/client/assets/{scoutbot-markdown-jh7tzFB1.js → scoutbot-markdown-BQ_Ee2Ic.js} +1 -1
  248. package/dist/client/assets/{scroll-text-DO0GQzvN.js → scroll-text-Dze_dXtQ.js} +1 -1
  249. package/dist/client/assets/{search-D1tJSAWe.js → search-CDko0PKE.js} +1 -1
  250. package/dist/client/assets/{secondaryNavConfig-B9IF8wXl.js → secondaryNavConfig-BoQ_zYR9.js} +1 -1
  251. package/dist/client/assets/{selection-bridge-i2S9zpf8.js → selection-bridge-Din6yV3h.js} +1 -1
  252. package/dist/client/assets/{send-horizontal-CgLppsIC.js → send-horizontal-CSjIm6xg.js} +1 -1
  253. package/dist/client/assets/{server-Dymv5Emh.js → server-Bzj7lPIx.js} +1 -1
  254. package/dist/client/assets/{session-catalog-DNaOEzoQ.js → session-catalog-DsaZJXZt.js} +1 -1
  255. package/dist/client/assets/session-ref-lookup-state-SATH_jAP.js +1 -0
  256. package/dist/client/assets/{session-table-PTQVoTyc.js → session-table-BQfR7u6r.js} +1 -1
  257. package/dist/client/assets/{settings-2fC_G9nX.js → settings-Dyvpkb1D.js} +1 -1
  258. package/dist/client/assets/{sliders-horizontal-BPSMHhbm.js → sliders-horizontal-C8njVwfg.js} +1 -1
  259. package/dist/client/assets/{sparkles-Dy8p5xN8.js → sparkles-CETYrxGA.js} +1 -1
  260. package/dist/client/assets/{sse-CiOSzE5n.js → sse-CD9MMUxl.js} +1 -1
  261. package/dist/client/assets/{tail-events-BMQmSx1n.js → tail-events-Ps8KpKah.js} +1 -1
  262. package/dist/client/assets/{terminal-yN9xN-h9.js → terminal-9GRS_Qdc.js} +1 -1
  263. package/dist/client/assets/{terminal-relay-9lhzEp2V.js → terminal-relay-GYMIvKs1.js} +1 -1
  264. package/dist/client/assets/{terminal-takeover-DANQfTcy.js → terminal-takeover-_Jyys4me.js} +1 -1
  265. package/dist/client/assets/{text-CnZ0e1-V.js → text-BP3oyl8-.js} +1 -1
  266. package/dist/client/assets/{text-rLpBg4_z.css → text-BYAFNLNq.css} +1 -1
  267. package/dist/client/assets/{use-conversation-list-D9BNLfnW.js → use-conversation-list-C9ABzjXI.js} +1 -1
  268. package/dist/client/assets/use-fleet-active-asks-DAspZQjE.js +1 -0
  269. package/dist/client/assets/{use-mesh-ops-items-BIvIHlqe.js → use-mesh-ops-items-Dh54ymEp.js} +1 -1
  270. package/dist/client/assets/{use-reduced-motion-CKkhq9c5.js → use-reduced-motion-x8pJMVrG.js} +1 -1
  271. package/dist/client/assets/{use-scout-dev-flags-B2KCzPxn.js → use-scout-dev-flags-DhCbiDK3.js} +1 -1
  272. package/dist/client/assets/{useAgentHoverCard-CHBsxcbp.js → useAgentHoverCard-DoBwV0LX.js} +1 -1
  273. package/dist/client/assets/useContentSecondaryNav-pZe2Zfk1.js +1 -0
  274. package/dist/client/assets/{usePierreRuntime-DUuXH5yp.js → usePierreRuntime-ejq9dCWV.js} +1 -1
  275. package/dist/client/assets/{wrench-YcXMlsh2.js → wrench-DjkoAOQt.js} +1 -1
  276. package/dist/client/assets/{x-e3h2hDsp.js → x-CAbNespN.js} +1 -1
  277. package/dist/client/assets/{xterm-Byp1Hep_.js → xterm-Cf-ngcGP.js} +1 -1
  278. package/dist/client/assets/{zap-nMcjPoWB.js → zap-Cq8eWkcF.js} +1 -1
  279. package/dist/client/index.html +1 -1
  280. package/dist/drizzle/0009_old_korg.sql +72 -0
  281. package/dist/drizzle/0010_sparkling_colonel_america.sql +2 -0
  282. package/dist/drizzle/0011_funny_onslaught.sql +4 -0
  283. package/dist/drizzle/0012_high_blazing_skull.sql +16 -0
  284. package/dist/drizzle/0013_perfect_juggernaut.sql +1 -0
  285. package/dist/drizzle/0014_legal_meggan.sql +6 -0
  286. package/dist/drizzle/0015_lame_marvel_boy.sql +12 -0
  287. package/dist/drizzle/0016_early_goliath.sql +6 -0
  288. package/dist/drizzle/meta/0009_snapshot.json +6262 -0
  289. package/dist/drizzle/meta/0010_snapshot.json +6286 -0
  290. package/dist/drizzle/meta/0011_snapshot.json +6337 -0
  291. package/dist/drizzle/meta/0012_snapshot.json +6458 -0
  292. package/dist/drizzle/meta/0013_snapshot.json +6465 -0
  293. package/dist/drizzle/meta/0014_snapshot.json +6503 -0
  294. package/dist/drizzle/meta/0015_snapshot.json +6596 -0
  295. package/dist/drizzle/meta/0016_snapshot.json +6611 -0
  296. package/dist/drizzle/meta/_journal.json +56 -0
  297. package/dist/main.mjs +1306 -360
  298. package/dist/node/main.mjs +314 -12
  299. package/dist/pairing-runtime-controller.mjs +608 -108
  300. package/dist/runtime/base-daemon.mjs +30 -3
  301. package/dist/runtime/broker-daemon.mjs +4771 -529
  302. package/dist/runtime/broker-process-manager.mjs +23 -2
  303. package/dist/runtime/mesh-discover.mjs +23 -2
  304. package/dist/scout-control-plane-web.mjs +1914 -478
  305. package/package.json +2 -2
  306. package/dist/client/assets/AgentLanesEmbedScreen-BmLnN4on.js +0 -1
  307. package/dist/client/assets/AgentLanesPreflight-5B6sXvRB.js +0 -1
  308. package/dist/client/assets/AgentLanesView-DHyzVBk6.js +0 -2
  309. package/dist/client/assets/AgentsSubnav-CDMjKeYC.js +0 -1
  310. package/dist/client/assets/ChatCollapsedStrip-Ycm0ecaX.js +0 -1
  311. package/dist/client/assets/ConversationScreen-BNULZAp2.js +0 -2
  312. package/dist/client/assets/CrewWorkspaces-CJhBKVoZ.css +0 -1
  313. package/dist/client/assets/CrewWorkspaces-CkPYIA46.js +0 -1
  314. package/dist/client/assets/FlightObserveScreen-CDWGSKZg.js +0 -1
  315. package/dist/client/assets/MessagesScreen-Eulveud3.js +0 -1
  316. package/dist/client/assets/NewChatComposer-hlWT-nbR.js +0 -19
  317. package/dist/client/assets/OpsScreen-Ppen_Lmj.js +0 -1
  318. package/dist/client/assets/OpsSubnav-GAKsoSor.js +0 -1
  319. package/dist/client/assets/ProjectAgentProfile-BLlp2e6t.js +0 -1
  320. package/dist/client/assets/ProjectsInbox-Dlt8OQ8O.js +0 -2
  321. package/dist/client/assets/ProjectsRail-DCfNMmnW.js +0 -1
  322. package/dist/client/assets/ProjectsScreen-BP-hmI1m.js +0 -1
  323. package/dist/client/assets/ProjectsThreadAside-CWpMjGIH.js +0 -1
  324. package/dist/client/assets/RealtimeVoiceScreen-D7zZHK_t.js +0 -1
  325. package/dist/client/assets/ScoutDeckSurface-CKT3qdqY.js +0 -1
  326. package/dist/client/assets/SessionEmbedScreen-RD5XOx7R.js +0 -1
  327. package/dist/client/assets/SessionRefScreen-B_cTv47v.js +0 -1
  328. package/dist/client/assets/SessionsScreen-Bq0Z77On.js +0 -1
  329. package/dist/client/assets/archive-BjcGiAy8.js +0 -1
  330. package/dist/client/assets/content-6RvWTrtk.js +0 -1
  331. package/dist/client/assets/content-BCgwMUqz.js +0 -1
  332. package/dist/client/assets/content-Bf2VLhx0.js +0 -1
  333. package/dist/client/assets/content-BrU_38-m.js +0 -1
  334. package/dist/client/assets/content-BvvJN8rN.js +0 -1
  335. package/dist/client/assets/content-CAeEqYPw.js +0 -1
  336. package/dist/client/assets/content-CI_Z9DXk.js +0 -1
  337. package/dist/client/assets/content-CbyKONhW.js +0 -1
  338. package/dist/client/assets/content-Czogvp43.js +0 -1
  339. package/dist/client/assets/content-DFk0zNzX.js +0 -1
  340. package/dist/client/assets/content-DHe4DgkA.js +0 -1
  341. package/dist/client/assets/content-DTz7cKjo.js +0 -1
  342. package/dist/client/assets/content-E3kudY-W.js +0 -1
  343. package/dist/client/assets/content-LpO0aO_U.js +0 -1
  344. package/dist/client/assets/conversation-motion-features-BKkCRaWR.js +0 -1
  345. package/dist/client/assets/discover-CHbrEItO.js +0 -2
  346. package/dist/client/assets/embed-entry-vil28MyU.js +0 -2
  347. package/dist/client/assets/index-BVlMw8x_.js +0 -1
  348. package/dist/client/assets/index-Cn0GR-q1.js +0 -1
  349. package/dist/client/assets/index-DosI4AG9.js +0 -1
  350. package/dist/client/assets/left-BpgWnaah.js +0 -1
  351. package/dist/client/assets/left-Cx0kv6pe.js +0 -1
  352. package/dist/client/assets/left-agents-qL5PpUY-.js +0 -1
  353. package/dist/client/assets/left-z-6CkuBe.js +0 -2
  354. package/dist/client/assets/projects-inbox-BBs1hG13.css +0 -1
  355. package/dist/client/assets/projects-inbox-D-zAb9Gp.js +0 -1
  356. package/dist/client/assets/resolve-panes-DO6LkwhQ.js +0 -1
  357. package/dist/client/assets/resolve-sidebar-context-CIF288wY.js +0 -1
  358. package/dist/client/assets/router-DJj2WbDg.js +0 -1
  359. package/dist/client/assets/use-fleet-active-asks-BeAdcl09.js +0 -1
  360. package/dist/client/assets/useContentSecondaryNav-D0mUhxTF.js +0 -1
package/dist/main.mjs CHANGED
@@ -903,6 +903,11 @@ function buildScoutReturnAddress(input) {
903
903
  return next;
904
904
  }
905
905
 
906
+ // ../protocol/src/conversation-projection.ts
907
+ function scoutConversationFeedId(conversationId) {
908
+ return `conv:${conversationId}`;
909
+ }
910
+
906
911
  // ../protocol/src/channel-identity.ts
907
912
  function mintChannelId(randomUuid) {
908
913
  return `${CHAT_ID_PREFIX}${randomUuid().toLowerCase().replace(/-/g, "")}`;
@@ -1589,12 +1594,16 @@ var init_host_integrations = () => {};
1589
1594
  // ../protocol/src/native-interactions.ts
1590
1595
  var init_native_interactions = () => {};
1591
1596
 
1597
+ // ../protocol/src/session-handle.ts
1598
+ var SCOUT_SESSION_HANDLE_PREFIX = "sess.";
1599
+ var init_session_handle = () => {};
1600
+
1592
1601
  // ../protocol/src/runtime-catalog.generated.ts
1593
1602
  var SCOUT_RUNTIME_CATALOG_DATA;
1594
1603
  var init_runtime_catalog_generated = __esm(() => {
1595
1604
  SCOUT_RUNTIME_CATALOG_DATA = {
1596
1605
  schemaVersion: "openscout.runtime-catalog.v1",
1597
- revision: "2026-08-18.1",
1606
+ revision: "2026-09-01.1",
1598
1607
  harnesses: [
1599
1608
  {
1600
1609
  id: "claude",
@@ -1618,6 +1627,13 @@ var init_runtime_catalog_generated = __esm(() => {
1618
1627
  family: "Opus",
1619
1628
  version: "5"
1620
1629
  },
1630
+ {
1631
+ id: "claude-fable-5",
1632
+ label: "Fable 5",
1633
+ enabled: true,
1634
+ family: "Fable",
1635
+ version: "5"
1636
+ },
1621
1637
  {
1622
1638
  id: "claude-sonnet-4-6",
1623
1639
  label: "Sonnet 4.6",
@@ -2543,6 +2559,7 @@ var init_broker_routes = __esm(() => {
2543
2559
  home: "/v1/home",
2544
2560
  node: "/v1/node",
2545
2561
  snapshot: "/v1/snapshot",
2562
+ conversationProjection: "/v1/conversation-projection",
2546
2563
  capabilities: "/v1/capabilities",
2547
2564
  runtimeCatalog: "/v1/runtime-catalog",
2548
2565
  topologySnapshot: "/v1/topology/snapshot",
@@ -2614,6 +2631,7 @@ var init_src = __esm(() => {
2614
2631
  init_budget();
2615
2632
  init_host_integrations();
2616
2633
  init_native_interactions();
2634
+ init_session_handle();
2617
2635
  init_runtime_profiles();
2618
2636
  init_runtime_execution();
2619
2637
  init_runtime_catalog();
@@ -9590,8 +9608,18 @@ async function maybeReadJsonFromActiveScoutBrokerService(baseUrl, path) {
9590
9608
  return handled(await service.readNode());
9591
9609
  }
9592
9610
  if (url.pathname === "/v1/snapshot") {
9611
+ const requestedScope = url.searchParams.get("scope");
9593
9612
  return handled(await service.readSnapshot({
9594
- since: parsePositiveInt(url.searchParams.get("since")) ?? null
9613
+ since: parsePositiveInt(url.searchParams.get("since")) ?? null,
9614
+ scope: requestedScope === "conversations" || requestedScope === "agents" ? requestedScope : undefined
9615
+ }));
9616
+ }
9617
+ if (url.pathname === "/v1/conversation-projection") {
9618
+ if (!service.readConversationProjection) {
9619
+ return unhandled();
9620
+ }
9621
+ return handled(await service.readConversationProjection({
9622
+ limit: parseLimit(url.searchParams.get("limit"))
9595
9623
  }));
9596
9624
  }
9597
9625
  if (url.pathname === "/v1/capabilities") {
@@ -12270,11 +12298,32 @@ function resolveBundledRuntimeDirFromModuleDir(moduleDir) {
12270
12298
  resolve6(moduleDir, "..", "..")
12271
12299
  ];
12272
12300
  for (const candidate of candidates) {
12273
- if (isInstalledRuntimePackageDir(candidate))
12274
- return candidate;
12301
+ if (!isInstalledRuntimePackageDir(candidate))
12302
+ continue;
12303
+ const sourceWorkspaceRuntime = resolveSourceWorkspaceRuntimeDir(candidate);
12304
+ if (sourceWorkspaceRuntime)
12305
+ return sourceWorkspaceRuntime;
12306
+ return candidate;
12275
12307
  }
12276
12308
  return null;
12277
12309
  }
12310
+ function resolveSourceWorkspaceRuntimeDir(bundledPackageDir) {
12311
+ const packagesDir = dirname9(bundledPackageDir);
12312
+ if (resolve6(packagesDir, "cli") !== resolve6(bundledPackageDir))
12313
+ return null;
12314
+ const runtimeDir = join11(packagesDir, "runtime");
12315
+ if (!existsSync9(join11(runtimeDir, "src")))
12316
+ return null;
12317
+ if (!isInstalledRuntimePackageDir(runtimeDir))
12318
+ return null;
12319
+ try {
12320
+ const cliPackage = JSON.parse(readFileSync6(join11(bundledPackageDir, "package.json"), "utf8"));
12321
+ const runtimePackage = JSON.parse(readFileSync6(join11(runtimeDir, "package.json"), "utf8"));
12322
+ return cliPackage.name === "@openscout/scout" && runtimePackage.name === "@openscout/runtime" ? runtimeDir : null;
12323
+ } catch {
12324
+ return null;
12325
+ }
12326
+ }
12278
12327
  function findWorkspaceRuntimeDir(startDir) {
12279
12328
  let current = resolve6(startDir);
12280
12329
  while (true) {
@@ -33490,26 +33539,6 @@ var init_local_agents = __esm(() => {
33490
33539
  TMUX_DEFAULT_ROWS = parsePositiveInteger2(process.env.OPENSCOUT_LOCAL_AGENT_TMUX_ROWS, 48);
33491
33540
  });
33492
33541
 
33493
- // ../../apps/desktop/src/core/broker/paths.ts
33494
- var openAiAudioSpeechUrl = "https://api.openai.com/v1/audio/speech";
33495
- var init_paths = __esm(() => {
33496
- init_src();
33497
- });
33498
-
33499
- // ../../apps/desktop/src/core/broker/ask-metadata.ts
33500
- function buildScoutAskMetadata(input) {
33501
- return {
33502
- source: input.source,
33503
- ...input.workRecordId ? {
33504
- collaborationRecordId: input.workRecordId,
33505
- workId: input.workRecordId
33506
- } : {},
33507
- ...input.senderContext ? { senderContext: input.senderContext } : {},
33508
- ...input.workspace ? { askWorkspace: input.workspace } : {},
33509
- ...input.labels ? { labels: input.labels } : {}
33510
- };
33511
- }
33512
-
33513
33542
  // ../runtime/src/registry.ts
33514
33543
  function createRuntimeRegistrySnapshot(value = {}) {
33515
33544
  return {
@@ -33532,6 +33561,26 @@ var init_registry3 = __esm(() => {
33532
33561
  TERMINAL_COLLABORATION_STATES = new Set(["done", "cancelled", "closed", "declined"]);
33533
33562
  });
33534
33563
 
33564
+ // ../../apps/desktop/src/core/broker/paths.ts
33565
+ var openAiAudioSpeechUrl = "https://api.openai.com/v1/audio/speech";
33566
+ var init_paths = __esm(() => {
33567
+ init_src();
33568
+ });
33569
+
33570
+ // ../../apps/desktop/src/core/broker/ask-metadata.ts
33571
+ function buildScoutAskMetadata(input) {
33572
+ return {
33573
+ source: input.source,
33574
+ ...input.workRecordId ? {
33575
+ collaborationRecordId: input.workRecordId,
33576
+ workId: input.workRecordId
33577
+ } : {},
33578
+ ...input.senderContext ? { senderContext: input.senderContext } : {},
33579
+ ...input.workspace ? { askWorkspace: input.workspace } : {},
33580
+ ...input.labels ? { labels: input.labels } : {}
33581
+ };
33582
+ }
33583
+
33535
33584
  // ../runtime/src/planner.ts
33536
33585
  function createDeliveryId(messageId, targetId, reason, transport) {
33537
33586
  return `del-${messageId}-${targetId}-${reason}-${transport}`;
@@ -37881,7 +37930,7 @@ var init_sqlite_core = __esm(() => {
37881
37930
  });
37882
37931
 
37883
37932
  // ../runtime/src/drizzle-schema.ts
37884
- var epochMsNow, nodesTable, trustedPeersTable, peerNoncesTable, actorsTable, agentsTable, agentEndpointsTable, runtimeSessionsTable, runtimeSessionAliasesTable, routeAliasBindingsTable, routeAliasRevisionsTable, conversationsTable, conversationMembersTable, messagesTable, messageMentionsTable, messageAttachmentsTable, conversationReadCursorsTable, invocationsTable, flightsTable, bindingsTable, deliveriesTable, deliveryAttemptsTable, durableActionsTable, durableAttemptsTable, durableCheckpointsTable, durableSignalsTable, collaborationRecordsTable, collaborationEventsTable, contextBlocksTable, contextPacksTable, eventsTable, threadEventsTable, threadCursorsTable, scoutDispatchesTable, activityItemsTable, budgetUsageEventsTable, budgetQuotaWindowSnapshotsTable, mobilePushRegistrationsTable, briefingsTable, roleAssignmentsTable, missionLogEntriesTable, controlPlaneDrizzleSchema;
37933
+ var epochMsNow, nodesTable, trustedPeersTable, peerNoncesTable, actorsTable, agentsTable, agentEndpointsTable, runtimeSessionsTable, runtimeSessionAliasesTable, routeAliasBindingsTable, routeAliasRevisionsTable, conversationsTable, conversationMembersTable, messagesTable, messageMentionsTable, messageAttachmentsTable, conversationReadCursorsTable, brokerJournalProjectionCheckpointsTable, conversationProjectionMetaTable, conversationProjectionItemsTable, conversationProjectionMessageFactsTable, conversationProjectionMessageStatsTable, conversationProjectionSourcesTable, conversationProjectionEventsTable, invocationsTable, flightsTable, bindingsTable, deliveriesTable, deliveryAttemptsTable, durableActionsTable, durableAttemptsTable, durableCheckpointsTable, durableSignalsTable, collaborationRecordsTable, collaborationEventsTable, contextBlocksTable, contextPacksTable, eventsTable, threadEventsTable, threadCursorsTable, scoutDispatchesTable, activityItemsTable, budgetUsageEventsTable, budgetQuotaWindowSnapshotsTable, mobilePushRegistrationsTable, briefingsTable, roleAssignmentsTable, missionLogEntriesTable, controlPlaneDrizzleSchema;
37885
37934
  var init_drizzle_schema = __esm(() => {
37886
37935
  init_drizzle_orm();
37887
37936
  init_sqlite_core();
@@ -37953,7 +38002,10 @@ var init_drizzle_schema = __esm(() => {
37953
38002
  advertiseScope: text("advertise_scope").notNull(),
37954
38003
  ownerId: text("owner_id"),
37955
38004
  metadataJson: text("metadata_json")
37956
- });
38005
+ }, (table3) => [
38006
+ index("idx_agents_home_node_id").on(table3.homeNodeId),
38007
+ index("idx_agents_authority_node_id").on(table3.authorityNodeId)
38008
+ ]);
37957
38009
  agentEndpointsTable = sqliteTable("agent_endpoints", {
37958
38010
  id: text("id").primaryKey(),
37959
38011
  agentId: text("agent_id").notNull().references(() => agentsTable.id, { onDelete: "cascade" }),
@@ -37969,7 +38021,14 @@ var init_drizzle_schema = __esm(() => {
37969
38021
  metadataJson: text("metadata_json"),
37970
38022
  updatedAt: integer("updated_at").notNull().default(epochMsNow)
37971
38023
  }, (table3) => [
37972
- index("idx_agent_endpoints_agent_updated_at").on(table3.agentId, desc(table3.updatedAt))
38024
+ index("idx_agent_endpoints_agent_updated_at").on(table3.agentId, desc(table3.updatedAt)),
38025
+ index("idx_agent_endpoints_roster_recency").on(desc(sql`CASE
38026
+ WHEN ${table3.updatedAt} IS NULL THEN NULL
38027
+ WHEN CAST(${table3.updatedAt} AS REAL) < 1000000000000
38028
+ THEN CAST(CAST(${table3.updatedAt} AS REAL) * 1000 AS INTEGER)
38029
+ ELSE CAST(${table3.updatedAt} AS INTEGER)
38030
+ END`), table3.agentId),
38031
+ index("idx_agent_endpoints_node_id").on(table3.nodeId)
37973
38032
  ]);
37974
38033
  runtimeSessionsTable = sqliteTable("runtime_sessions", {
37975
38034
  id: text("id").primaryKey(),
@@ -37993,6 +38052,7 @@ var init_drizzle_schema = __esm(() => {
37993
38052
  }, (table3) => [
37994
38053
  index("idx_runtime_sessions_agent_last_seen").on(table3.agentId, desc(table3.lastSeenAt)),
37995
38054
  index("idx_runtime_sessions_endpoint_last_seen").on(table3.endpointId, desc(table3.lastSeenAt)),
38055
+ index("idx_runtime_sessions_node_id").on(table3.nodeId),
37996
38056
  index("idx_runtime_sessions_external").on(table3.externalSessionId),
37997
38057
  index("idx_runtime_sessions_expires").on(table3.expiresAt).where(sql`expires_at IS NOT NULL`)
37998
38058
  ]);
@@ -38012,6 +38072,8 @@ var init_drizzle_schema = __esm(() => {
38012
38072
  primaryKey({ columns: [table3.alias, table3.sessionId] }),
38013
38073
  index("idx_runtime_session_aliases_alias").on(table3.alias, desc(table3.lastSeenAt)),
38014
38074
  index("idx_runtime_session_aliases_session").on(table3.sessionId),
38075
+ index("idx_runtime_session_aliases_endpoint").on(table3.endpointId),
38076
+ index("idx_runtime_session_aliases_node_id").on(table3.nodeId),
38015
38077
  index("idx_runtime_session_aliases_expires").on(table3.expiresAt).where(sql`expires_at IS NOT NULL`)
38016
38078
  ]);
38017
38079
  routeAliasBindingsTable = sqliteTable("route_alias_bindings", {
@@ -38091,7 +38153,8 @@ var init_drizzle_schema = __esm(() => {
38091
38153
  actorId: text("actor_id").notNull().references(() => actorsTable.id, { onDelete: "cascade" }),
38092
38154
  role: text("role")
38093
38155
  }, (table3) => [
38094
- primaryKey({ columns: [table3.conversationId, table3.actorId] })
38156
+ primaryKey({ columns: [table3.conversationId, table3.actorId] }),
38157
+ index("idx_conversation_members_actor").on(table3.actorId, table3.conversationId)
38095
38158
  ]);
38096
38159
  messagesTable = sqliteTable("messages", {
38097
38160
  id: text("id").primaryKey(),
@@ -38111,7 +38174,8 @@ var init_drizzle_schema = __esm(() => {
38111
38174
  }, (table3) => [
38112
38175
  index("idx_messages_conversation_created_at").on(table3.conversationId, table3.createdAt),
38113
38176
  index("idx_messages_created_at").on(desc(table3.createdAt)),
38114
- index("idx_messages_actor_created_at").on(table3.actorId, desc(table3.createdAt))
38177
+ index("idx_messages_actor_created_at").on(table3.actorId, desc(table3.createdAt)),
38178
+ index("idx_messages_origin_node_id").on(table3.originNodeId)
38115
38179
  ]);
38116
38180
  messageMentionsTable = sqliteTable("message_mentions", {
38117
38181
  messageId: text("message_id").notNull().references(() => messagesTable.id, { onDelete: "cascade" }),
@@ -38140,7 +38204,102 @@ var init_drizzle_schema = __esm(() => {
38140
38204
  metadataJson: text("metadata_json")
38141
38205
  }, (table3) => [
38142
38206
  primaryKey({ columns: [table3.conversationId, table3.actorId] }),
38143
- index("idx_read_cursors_conversation_updated_at").on(table3.conversationId, desc(table3.updatedAt))
38207
+ index("idx_read_cursors_conversation_updated_at").on(table3.conversationId, desc(table3.updatedAt)),
38208
+ index("idx_read_cursors_reader_node_id").on(table3.readerNodeId)
38209
+ ]);
38210
+ brokerJournalProjectionCheckpointsTable = sqliteTable("broker_journal_projection_checkpoints", {
38211
+ projectionId: text("projection_id").primaryKey(),
38212
+ projectionVersion: integer("projection_version").notNull(),
38213
+ barrierId: text("barrier_id").notNull(),
38214
+ updatedAt: integer("updated_at").notNull()
38215
+ });
38216
+ conversationProjectionMetaTable = sqliteTable("conversation_projection_meta", {
38217
+ singleton: integer("singleton").primaryKey(),
38218
+ projectionId: text("projection_id").notNull(),
38219
+ projectionVersion: integer("projection_version").notNull(),
38220
+ headSeq: integer("head_seq").notNull(),
38221
+ minReplayableSeq: integer("min_replayable_seq").notNull(),
38222
+ updatedAt: integer("updated_at").notNull()
38223
+ }, (table3) => [
38224
+ check("conversation_projection_meta_singleton_check", sql`${table3.singleton} = 1`)
38225
+ ]);
38226
+ conversationProjectionItemsTable = sqliteTable("conversation_projection_items", {
38227
+ feedId: text("feed_id").primaryKey(),
38228
+ entityKind: text("entity_kind").notNull(),
38229
+ kind: text("kind").notNull(),
38230
+ conversationId: text("conversation_id"),
38231
+ runtimeSessionId: text("runtime_session_id"),
38232
+ source: text("source"),
38233
+ sourceSessionId: text("source_session_id"),
38234
+ title: text("title"),
38235
+ alias: text("alias"),
38236
+ naturalKey: text("natural_key"),
38237
+ projectRoot: text("project_root"),
38238
+ harness: text("harness"),
38239
+ model: text("model"),
38240
+ effort: text("effort"),
38241
+ agentId: text("agent_id"),
38242
+ agentName: text("agent_name"),
38243
+ currentBranch: text("current_branch"),
38244
+ authorityNodeId: text("authority_node_id"),
38245
+ authorityNodeName: text("authority_node_name"),
38246
+ parentConversationId: text("parent_conversation_id"),
38247
+ anchorMessageId: text("anchor_message_id"),
38248
+ activityState: text("activity_state").notNull(),
38249
+ lastMessageId: text("last_message_id"),
38250
+ lastMessageAt: integer("last_message_at"),
38251
+ lastActivityAt: integer("last_activity_at").notNull(),
38252
+ messageCount: integer("message_count").notNull().default(0),
38253
+ unreadCount: integer("unread_count").notNull().default(0),
38254
+ participantCount: integer("participant_count").notNull().default(0),
38255
+ preview: text("preview"),
38256
+ lastEngagedAt: integer("last_engaged_at"),
38257
+ sourceFreshAt: integer("source_fresh_at"),
38258
+ visibilityState: text("visibility_state").notNull().default("visible"),
38259
+ updatedSeq: integer("updated_seq").notNull(),
38260
+ updatedAt: integer("updated_at").notNull()
38261
+ }, (table3) => [
38262
+ check("conversation_projection_items_entity_kind_check", sql`${table3.entityKind} IN ('scout_conversation', 'observed_session')`),
38263
+ check("conversation_projection_items_visibility_check", sql`${table3.visibilityState} IN ('visible', 'hidden')`),
38264
+ index("idx_conversation_projection_recent").on(table3.visibilityState, desc(table3.lastActivityAt), table3.feedId),
38265
+ index("idx_conversation_projection_project_recent").on(table3.projectRoot, table3.visibilityState, desc(table3.lastActivityAt)),
38266
+ index("idx_conversation_projection_engaged").on(table3.visibilityState, desc(table3.lastEngagedAt), desc(table3.lastActivityAt), table3.feedId),
38267
+ index("idx_conversation_projection_source_fresh").on(table3.visibilityState, desc(table3.sourceFreshAt)),
38268
+ index("idx_conversation_projection_runtime_session").on(table3.entityKind, table3.runtimeSessionId),
38269
+ index("idx_conversation_projection_source_session").on(table3.entityKind, table3.sourceSessionId),
38270
+ uniqueIndex("idx_conversation_projection_conversation").on(table3.conversationId).where(sql`conversation_id IS NOT NULL`)
38271
+ ]);
38272
+ conversationProjectionMessageFactsTable = sqliteTable("conversation_projection_message_facts", {
38273
+ messageId: text("message_id").primaryKey().references(() => messagesTable.id, { onDelete: "cascade" }),
38274
+ conversationId: text("conversation_id").notNull().references(() => conversationsTable.id, { onDelete: "cascade" }),
38275
+ createdAt: integer("created_at").notNull()
38276
+ }, (table3) => [
38277
+ index("idx_conversation_projection_message_facts_conversation").on(table3.conversationId, table3.createdAt, table3.messageId)
38278
+ ]);
38279
+ conversationProjectionMessageStatsTable = sqliteTable("conversation_projection_message_stats", {
38280
+ conversationId: text("conversation_id").primaryKey().references(() => conversationsTable.id, { onDelete: "cascade" }),
38281
+ messageCount: integer("message_count").notNull().default(0),
38282
+ latestMessageId: text("latest_message_id"),
38283
+ latestMessageAt: integer("latest_message_at")
38284
+ });
38285
+ conversationProjectionSourcesTable = sqliteTable("conversation_projection_sources", {
38286
+ source: text("source").notNull(),
38287
+ sourceSessionId: text("source_session_id").notNull(),
38288
+ feedId: text("feed_id").notNull().references(() => conversationProjectionItemsTable.feedId, { onDelete: "cascade" }),
38289
+ firstSeenAt: integer("first_seen_at").notNull(),
38290
+ lastSeenAt: integer("last_seen_at").notNull()
38291
+ }, (table3) => [
38292
+ primaryKey({ columns: [table3.source, table3.sourceSessionId] }),
38293
+ index("idx_conversation_projection_sources_feed").on(table3.feedId)
38294
+ ]);
38295
+ conversationProjectionEventsTable = sqliteTable("conversation_projection_events", {
38296
+ seq: integer("seq").primaryKey({ autoIncrement: true }),
38297
+ projectionId: text("projection_id").notNull(),
38298
+ ts: integer("ts").notNull(),
38299
+ payloadJson: text("payload_json").notNull()
38300
+ }, (table3) => [
38301
+ index("idx_conversation_projection_events_projection_seq").on(table3.projectionId, table3.seq),
38302
+ index("idx_conversation_projection_events_ts").on(table3.ts)
38144
38303
  ]);
38145
38304
  invocationsTable = sqliteTable("invocations", {
38146
38305
  id: text("id").primaryKey(),
@@ -38172,7 +38331,10 @@ var init_drizzle_schema = __esm(() => {
38172
38331
  executionResolutionJson: text("execution_resolution_json")
38173
38332
  }, (table3) => [
38174
38333
  index("idx_invocations_target_created_at").on(table3.targetAgentId, table3.createdAt),
38175
- index("idx_invocations_requester_created_at").on(table3.requesterId, desc(table3.createdAt))
38334
+ index("idx_invocations_requester_created_at").on(table3.requesterId, desc(table3.createdAt)),
38335
+ index("idx_invocations_conversation_created_at").on(table3.conversationId, desc(table3.createdAt)),
38336
+ index("idx_invocations_requester_node_id").on(table3.requesterNodeId),
38337
+ index("idx_invocations_target_node_id").on(table3.targetNodeId)
38176
38338
  ]);
38177
38339
  flightsTable = sqliteTable("flights", {
38178
38340
  id: text("id").primaryKey(),
@@ -38218,7 +38380,8 @@ var init_drizzle_schema = __esm(() => {
38218
38380
  createdAt: integer("created_at").notNull().default(epochMsNow)
38219
38381
  }, (table3) => [
38220
38382
  index("idx_deliveries_status_transport").on(table3.status, table3.transport),
38221
- index("idx_deliveries_created_at").on(desc(table3.createdAt))
38383
+ index("idx_deliveries_created_at").on(desc(table3.createdAt)),
38384
+ index("idx_deliveries_target_node_id").on(table3.targetNodeId)
38222
38385
  ]);
38223
38386
  deliveryAttemptsTable = sqliteTable("delivery_attempts", {
38224
38387
  id: text("id").primaryKey(),
@@ -38388,7 +38551,8 @@ var init_drizzle_schema = __esm(() => {
38388
38551
  }, (table3) => [
38389
38552
  unique2().on(table3.conversationId, table3.seq),
38390
38553
  index("idx_thread_events_conversation_seq").on(table3.conversationId, desc(table3.seq)),
38391
- index("idx_thread_events_conversation_ts").on(table3.conversationId, desc(table3.ts))
38554
+ index("idx_thread_events_conversation_ts").on(table3.conversationId, desc(table3.ts)),
38555
+ index("idx_thread_events_authority_node_id").on(table3.authorityNodeId)
38392
38556
  ]);
38393
38557
  threadCursorsTable = sqliteTable("thread_cursors", {
38394
38558
  conversationId: text("conversation_id").notNull().references(() => conversationsTable.id, { onDelete: "cascade" }),
@@ -38396,7 +38560,8 @@ var init_drizzle_schema = __esm(() => {
38396
38560
  lastAppliedSeq: integer("last_applied_seq").notNull(),
38397
38561
  updatedAt: integer("updated_at").notNull()
38398
38562
  }, (table3) => [
38399
- primaryKey({ columns: [table3.conversationId, table3.authorityNodeId] })
38563
+ primaryKey({ columns: [table3.conversationId, table3.authorityNodeId] }),
38564
+ index("idx_thread_cursors_authority_node_id").on(table3.authorityNodeId)
38400
38565
  ]);
38401
38566
  scoutDispatchesTable = sqliteTable("scout_dispatches", {
38402
38567
  id: text("id").primaryKey(),
@@ -38598,6 +38763,13 @@ var init_drizzle_schema = __esm(() => {
38598
38763
  messageMentions: messageMentionsTable,
38599
38764
  messageAttachments: messageAttachmentsTable,
38600
38765
  conversationReadCursors: conversationReadCursorsTable,
38766
+ brokerJournalProjectionCheckpoints: brokerJournalProjectionCheckpointsTable,
38767
+ conversationProjectionMeta: conversationProjectionMetaTable,
38768
+ conversationProjectionItems: conversationProjectionItemsTable,
38769
+ conversationProjectionMessageFacts: conversationProjectionMessageFactsTable,
38770
+ conversationProjectionMessageStats: conversationProjectionMessageStatsTable,
38771
+ conversationProjectionSources: conversationProjectionSourcesTable,
38772
+ conversationProjectionEvents: conversationProjectionEventsTable,
38601
38773
  invocations: invocationsTable,
38602
38774
  flights: flightsTable,
38603
38775
  bindings: bindingsTable,
@@ -38667,6 +38839,8 @@ CREATE INDEX IF NOT EXISTS idx_runtime_sessions_agent_last_seen
38667
38839
  ON runtime_sessions (agent_id, last_seen_at DESC);
38668
38840
  CREATE INDEX IF NOT EXISTS idx_runtime_sessions_endpoint_last_seen
38669
38841
  ON runtime_sessions (endpoint_id, last_seen_at DESC);
38842
+ CREATE INDEX IF NOT EXISTS idx_runtime_sessions_node_id
38843
+ ON runtime_sessions (node_id);
38670
38844
  CREATE INDEX IF NOT EXISTS idx_runtime_sessions_external
38671
38845
  ON runtime_sessions (external_session_id);
38672
38846
  CREATE INDEX IF NOT EXISTS idx_runtime_sessions_expires
@@ -38676,6 +38850,10 @@ CREATE INDEX IF NOT EXISTS idx_runtime_session_aliases_alias
38676
38850
  ON runtime_session_aliases (alias, last_seen_at DESC);
38677
38851
  CREATE INDEX IF NOT EXISTS idx_runtime_session_aliases_session
38678
38852
  ON runtime_session_aliases (session_id);
38853
+ CREATE INDEX IF NOT EXISTS idx_runtime_session_aliases_endpoint
38854
+ ON runtime_session_aliases (endpoint_id);
38855
+ CREATE INDEX IF NOT EXISTS idx_runtime_session_aliases_node_id
38856
+ ON runtime_session_aliases (node_id);
38679
38857
  CREATE INDEX IF NOT EXISTS idx_runtime_session_aliases_expires
38680
38858
  ON runtime_session_aliases (expires_at)
38681
38859
  WHERE expires_at IS NOT NULL;
@@ -38938,6 +39116,93 @@ CREATE TABLE IF NOT EXISTS conversation_read_cursors (
38938
39116
  PRIMARY KEY (conversation_id, actor_id)
38939
39117
  );
38940
39118
 
39119
+ CREATE TABLE IF NOT EXISTS broker_journal_projection_checkpoints (
39120
+ projection_id TEXT PRIMARY KEY,
39121
+ projection_version INTEGER NOT NULL,
39122
+ barrier_id TEXT NOT NULL,
39123
+ updated_at INTEGER NOT NULL
39124
+ );
39125
+
39126
+ CREATE TABLE IF NOT EXISTS conversation_projection_meta (
39127
+ singleton INTEGER PRIMARY KEY,
39128
+ projection_id TEXT NOT NULL,
39129
+ projection_version INTEGER NOT NULL,
39130
+ head_seq INTEGER NOT NULL,
39131
+ min_replayable_seq INTEGER NOT NULL,
39132
+ updated_at INTEGER NOT NULL,
39133
+ CONSTRAINT conversation_projection_meta_singleton_check CHECK (singleton = 1)
39134
+ );
39135
+
39136
+ CREATE TABLE IF NOT EXISTS conversation_projection_items (
39137
+ feed_id TEXT PRIMARY KEY,
39138
+ entity_kind TEXT NOT NULL,
39139
+ kind TEXT NOT NULL,
39140
+ conversation_id TEXT,
39141
+ runtime_session_id TEXT,
39142
+ source TEXT,
39143
+ source_session_id TEXT,
39144
+ title TEXT,
39145
+ alias TEXT,
39146
+ natural_key TEXT,
39147
+ project_root TEXT,
39148
+ harness TEXT,
39149
+ model TEXT,
39150
+ effort TEXT,
39151
+ agent_id TEXT,
39152
+ agent_name TEXT,
39153
+ current_branch TEXT,
39154
+ authority_node_id TEXT,
39155
+ authority_node_name TEXT,
39156
+ parent_conversation_id TEXT,
39157
+ anchor_message_id TEXT,
39158
+ activity_state TEXT NOT NULL,
39159
+ last_message_id TEXT,
39160
+ last_message_at INTEGER,
39161
+ last_activity_at INTEGER NOT NULL,
39162
+ message_count INTEGER NOT NULL DEFAULT 0,
39163
+ unread_count INTEGER NOT NULL DEFAULT 0,
39164
+ participant_count INTEGER NOT NULL DEFAULT 0,
39165
+ preview TEXT,
39166
+ last_engaged_at INTEGER,
39167
+ source_fresh_at INTEGER,
39168
+ visibility_state TEXT NOT NULL DEFAULT 'visible',
39169
+ updated_seq INTEGER NOT NULL,
39170
+ updated_at INTEGER NOT NULL,
39171
+ CONSTRAINT conversation_projection_items_entity_kind_check
39172
+ CHECK (entity_kind IN ('scout_conversation', 'observed_session')),
39173
+ CONSTRAINT conversation_projection_items_visibility_check
39174
+ CHECK (visibility_state IN ('visible', 'hidden'))
39175
+ );
39176
+
39177
+ CREATE TABLE IF NOT EXISTS conversation_projection_message_facts (
39178
+ message_id TEXT PRIMARY KEY REFERENCES messages(id) ON DELETE CASCADE,
39179
+ conversation_id TEXT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
39180
+ created_at INTEGER NOT NULL
39181
+ );
39182
+
39183
+ CREATE TABLE IF NOT EXISTS conversation_projection_message_stats (
39184
+ conversation_id TEXT PRIMARY KEY REFERENCES conversations(id) ON DELETE CASCADE,
39185
+ message_count INTEGER NOT NULL DEFAULT 0,
39186
+ latest_message_id TEXT,
39187
+ latest_message_at INTEGER
39188
+ );
39189
+
39190
+ CREATE TABLE IF NOT EXISTS conversation_projection_sources (
39191
+ source TEXT NOT NULL,
39192
+ source_session_id TEXT NOT NULL,
39193
+ feed_id TEXT NOT NULL REFERENCES conversation_projection_items(feed_id) ON DELETE CASCADE,
39194
+ first_seen_at INTEGER NOT NULL,
39195
+ last_seen_at INTEGER NOT NULL,
39196
+ PRIMARY KEY (source, source_session_id)
39197
+ );
39198
+
39199
+ CREATE TABLE IF NOT EXISTS conversation_projection_events (
39200
+ seq INTEGER PRIMARY KEY AUTOINCREMENT,
39201
+ projection_id TEXT NOT NULL,
39202
+ ts INTEGER NOT NULL,
39203
+ payload_json TEXT NOT NULL
39204
+ );
39205
+
38941
39206
  CREATE TABLE IF NOT EXISTS invocations (
38942
39207
  id TEXT PRIMARY KEY,
38943
39208
  requester_id TEXT NOT NULL REFERENCES actors(id) ON DELETE RESTRICT,
@@ -39345,18 +39610,74 @@ CREATE INDEX IF NOT EXISTS idx_peer_nonces_seen_at
39345
39610
  ON peer_nonces (seen_at);
39346
39611
  CREATE INDEX IF NOT EXISTS idx_agent_endpoints_agent_updated_at
39347
39612
  ON agent_endpoints (agent_id, updated_at DESC);
39613
+ CREATE INDEX IF NOT EXISTS idx_agent_endpoints_roster_recency
39614
+ ON agent_endpoints (
39615
+ CASE
39616
+ WHEN updated_at IS NULL THEN NULL
39617
+ WHEN CAST(updated_at AS REAL) < 1000000000000
39618
+ THEN CAST(CAST(updated_at AS REAL) * 1000 AS INTEGER)
39619
+ ELSE CAST(updated_at AS INTEGER)
39620
+ END DESC,
39621
+ agent_id
39622
+ );
39623
+ CREATE INDEX IF NOT EXISTS idx_agents_home_node_id
39624
+ ON agents (home_node_id);
39625
+ CREATE INDEX IF NOT EXISTS idx_agents_authority_node_id
39626
+ ON agents (authority_node_id);
39627
+ CREATE INDEX IF NOT EXISTS idx_agent_endpoints_node_id
39628
+ ON agent_endpoints (node_id);
39629
+ CREATE INDEX IF NOT EXISTS idx_conversation_members_actor
39630
+ ON conversation_members (actor_id, conversation_id);
39348
39631
  CREATE INDEX IF NOT EXISTS idx_messages_conversation_created_at
39349
39632
  ON messages (conversation_id, created_at);
39350
39633
  CREATE INDEX IF NOT EXISTS idx_messages_created_at
39351
39634
  ON messages (created_at DESC);
39352
39635
  CREATE INDEX IF NOT EXISTS idx_messages_actor_created_at
39353
39636
  ON messages (actor_id, created_at DESC);
39637
+ CREATE INDEX IF NOT EXISTS idx_messages_origin_node_id
39638
+ ON messages (origin_node_id);
39354
39639
  CREATE INDEX IF NOT EXISTS idx_read_cursors_conversation_updated_at
39355
39640
  ON conversation_read_cursors (conversation_id, updated_at DESC);
39641
+ CREATE INDEX IF NOT EXISTS idx_read_cursors_reader_node_id
39642
+ ON conversation_read_cursors (reader_node_id);
39643
+ CREATE INDEX IF NOT EXISTS idx_conversation_projection_recent
39644
+ ON conversation_projection_items (visibility_state, last_activity_at DESC, feed_id);
39645
+ CREATE INDEX IF NOT EXISTS idx_conversation_projection_project_recent
39646
+ ON conversation_projection_items (project_root, visibility_state, last_activity_at DESC);
39647
+ CREATE INDEX IF NOT EXISTS idx_conversation_projection_message_facts_conversation
39648
+ ON conversation_projection_message_facts (conversation_id, created_at, message_id);
39649
+ CREATE INDEX IF NOT EXISTS idx_conversation_projection_engaged
39650
+ ON conversation_projection_items (
39651
+ visibility_state,
39652
+ last_engaged_at DESC,
39653
+ last_activity_at DESC,
39654
+ feed_id
39655
+ );
39656
+ CREATE INDEX IF NOT EXISTS idx_conversation_projection_source_fresh
39657
+ ON conversation_projection_items (visibility_state, source_fresh_at DESC);
39658
+ CREATE INDEX IF NOT EXISTS idx_conversation_projection_runtime_session
39659
+ ON conversation_projection_items (entity_kind, runtime_session_id);
39660
+ CREATE INDEX IF NOT EXISTS idx_conversation_projection_source_session
39661
+ ON conversation_projection_items (entity_kind, source_session_id);
39662
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_conversation_projection_conversation
39663
+ ON conversation_projection_items (conversation_id)
39664
+ WHERE conversation_id IS NOT NULL;
39665
+ CREATE INDEX IF NOT EXISTS idx_conversation_projection_sources_feed
39666
+ ON conversation_projection_sources (feed_id);
39667
+ CREATE INDEX IF NOT EXISTS idx_conversation_projection_events_projection_seq
39668
+ ON conversation_projection_events (projection_id, seq);
39669
+ CREATE INDEX IF NOT EXISTS idx_conversation_projection_events_ts
39670
+ ON conversation_projection_events (ts);
39356
39671
  CREATE INDEX IF NOT EXISTS idx_invocations_target_created_at
39357
39672
  ON invocations (target_agent_id, created_at);
39358
39673
  CREATE INDEX IF NOT EXISTS idx_invocations_requester_created_at
39359
39674
  ON invocations (requester_id, created_at DESC);
39675
+ CREATE INDEX IF NOT EXISTS idx_invocations_conversation_created_at
39676
+ ON invocations (conversation_id, created_at DESC);
39677
+ CREATE INDEX IF NOT EXISTS idx_invocations_requester_node_id
39678
+ ON invocations (requester_node_id);
39679
+ CREATE INDEX IF NOT EXISTS idx_invocations_target_node_id
39680
+ ON invocations (target_node_id);
39360
39681
  CREATE INDEX IF NOT EXISTS idx_flights_target_state
39361
39682
  ON flights (target_agent_id, state);
39362
39683
  CREATE INDEX IF NOT EXISTS idx_flights_invocation_id
@@ -39365,6 +39686,8 @@ CREATE INDEX IF NOT EXISTS idx_deliveries_status_transport
39365
39686
  ON deliveries (status, transport);
39366
39687
  CREATE INDEX IF NOT EXISTS idx_deliveries_created_at
39367
39688
  ON deliveries (created_at DESC);
39689
+ CREATE INDEX IF NOT EXISTS idx_deliveries_target_node_id
39690
+ ON deliveries (target_node_id);
39368
39691
  CREATE INDEX IF NOT EXISTS idx_delivery_attempts_created_at
39369
39692
  ON delivery_attempts (created_at DESC);
39370
39693
  CREATE UNIQUE INDEX IF NOT EXISTS idx_durable_actions_idempotency_key
@@ -39411,6 +39734,10 @@ CREATE INDEX IF NOT EXISTS idx_thread_events_conversation_seq
39411
39734
  ON thread_events (conversation_id, seq DESC);
39412
39735
  CREATE INDEX IF NOT EXISTS idx_thread_events_conversation_ts
39413
39736
  ON thread_events (conversation_id, ts DESC);
39737
+ CREATE INDEX IF NOT EXISTS idx_thread_events_authority_node_id
39738
+ ON thread_events (authority_node_id);
39739
+ CREATE INDEX IF NOT EXISTS idx_thread_cursors_authority_node_id
39740
+ ON thread_cursors (authority_node_id);
39414
39741
  CREATE INDEX IF NOT EXISTS idx_activity_items_agent_ts
39415
39742
  ON activity_items (agent_id, ts DESC);
39416
39743
  CREATE INDEX IF NOT EXISTS idx_activity_items_actor_ts
@@ -40638,7 +40965,23 @@ CREATE INDEX IF NOT EXISTS idx_activity_items_ts
40638
40965
  ON activity_items(ts DESC);
40639
40966
  CREATE INDEX IF NOT EXISTS idx_conversations_created_at
40640
40967
  ON conversations(created_at DESC);
40968
+ CREATE INDEX IF NOT EXISTS idx_agent_endpoints_roster_recency
40969
+ ON agent_endpoints (
40970
+ CASE
40971
+ WHEN updated_at IS NULL THEN NULL
40972
+ WHEN CAST(updated_at AS REAL) < 1000000000000
40973
+ THEN CAST(CAST(updated_at AS REAL) * 1000 AS INTEGER)
40974
+ ELSE CAST(updated_at AS INTEGER)
40975
+ END DESC,
40976
+ agent_id
40977
+ );
40978
+ `);
40979
+ if (hasColumn(database, "conversations", "authority_node_id")) {
40980
+ database.exec(`
40981
+ CREATE INDEX IF NOT EXISTS idx_conversations_authority_node_id
40982
+ ON conversations(authority_node_id);
40641
40983
  `);
40984
+ }
40642
40985
  }
40643
40986
  },
40644
40987
  {
@@ -41014,8 +41357,39 @@ var init_budget_observations2 = __esm(() => {
41014
41357
  QUOTA_HISTORY_BUCKET_MS = 60 * 60 * 1000;
41015
41358
  });
41016
41359
 
41017
- // ../runtime/src/sqlite-store.ts
41360
+ // ../runtime/src/runtime-session-handle.ts
41018
41361
  import { createHash as createHash4 } from "crypto";
41362
+ function metadataStringValue(metadata, key) {
41363
+ const value = metadata?.[key];
41364
+ return typeof value === "string" && value.trim() ? value.trim() : null;
41365
+ }
41366
+ function firstStringValue(...values) {
41367
+ return values.find((value) => Boolean(value?.trim()))?.trim() ?? null;
41368
+ }
41369
+ function runtimeSessionPrimaryAlias(endpoint) {
41370
+ const metadata = endpoint.metadata;
41371
+ if (metadata?.cardless === true) {
41372
+ return firstStringValue(metadataStringValue(metadata, "handle"), metadataStringValue(metadata, "externalSessionId"), metadataStringValue(metadata, "threadId"), endpoint.sessionId, endpoint.agentId);
41373
+ }
41374
+ return firstStringValue(metadataStringValue(metadata, "externalSessionId"), metadataStringValue(metadata, "threadId"), metadataStringValue(metadata, "nativeSessionId"), metadataStringValue(metadata, "pairingSessionId"), metadataStringValue(metadata, "sessionId"), endpoint.sessionId, metadataStringValue(metadata, "runtimeSessionId"), metadataStringValue(metadata, "runtimeInstanceId"), metadataStringValue(metadata, "tmuxSession"));
41375
+ }
41376
+ function runtimeSessionHandleForEndpoint(endpoint, primaryAlias = runtimeSessionPrimaryAlias(endpoint)) {
41377
+ if (!primaryAlias)
41378
+ return null;
41379
+ const resolutionKey = [
41380
+ endpoint.nodeId,
41381
+ endpoint.harness,
41382
+ primaryAlias
41383
+ ].join("\x00");
41384
+ const token = createHash4("sha256").update(resolutionKey).digest("hex").slice(0, 20);
41385
+ return `${SCOUT_SESSION_HANDLE_PREFIX}${token}`;
41386
+ }
41387
+ var init_runtime_session_handle = __esm(() => {
41388
+ init_src();
41389
+ });
41390
+
41391
+ // ../runtime/src/sqlite-store.ts
41392
+ import { createHash as createHash5 } from "crypto";
41019
41393
  import { mkdirSync as mkdirSync7 } from "fs";
41020
41394
  import { dirname as dirname18 } from "path";
41021
41395
  function parseJson(value, fallback2) {
@@ -41027,6 +41401,16 @@ function parseJson(value, fallback2) {
41027
41401
  return fallback2;
41028
41402
  }
41029
41403
  }
41404
+ function isTransientSqliteBusyError(error) {
41405
+ if (typeof error === "object" && error !== null) {
41406
+ const code = error.code;
41407
+ if (code === "SQLITE_BUSY" || code === "SQLITE_LOCKED") {
41408
+ return true;
41409
+ }
41410
+ }
41411
+ const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
41412
+ return message.includes("database is locked") || message.includes("database is busy") || message.includes("sqlite_busy");
41413
+ }
41030
41414
  function stringify3(value) {
41031
41415
  return value === undefined ? null : JSON.stringify(value);
41032
41416
  }
@@ -41037,9 +41421,9 @@ function normalizeTimestampMs(value) {
41037
41421
  return epochMs(value);
41038
41422
  }
41039
41423
  function stableHash2(value, length = 20) {
41040
- return createHash4("sha256").update(value).digest("hex").slice(0, length);
41424
+ return createHash5("sha256").update(value).digest("hex").slice(0, length);
41041
41425
  }
41042
- function metadataStringValue(metadata, key) {
41426
+ function metadataStringValue2(metadata, key) {
41043
41427
  const value = metadata?.[key];
41044
41428
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
41045
41429
  }
@@ -41056,7 +41440,7 @@ function metadataTimestampValue(metadata, key) {
41056
41440
  }
41057
41441
  return null;
41058
41442
  }
41059
- function firstStringValue(...values) {
41443
+ function firstStringValue2(...values) {
41060
41444
  for (const value of values) {
41061
41445
  const trimmed = value?.trim();
41062
41446
  if (trimmed) {
@@ -41274,16 +41658,9 @@ function runtimeSessionAliasFromRow(row) {
41274
41658
  function runtimeSessionMetadata(endpoint) {
41275
41659
  return endpoint.metadata ?? {};
41276
41660
  }
41277
- function endpointRuntimeSessionPrimaryAlias(endpoint) {
41278
- const metadata = runtimeSessionMetadata(endpoint);
41279
- if (metadata.cardless === true) {
41280
- return firstStringValue(metadataStringValue(metadata, "handle"), metadataStringValue(metadata, "externalSessionId"), metadataStringValue(metadata, "threadId"), endpoint.sessionId, endpoint.agentId);
41281
- }
41282
- return firstStringValue(metadataStringValue(metadata, "externalSessionId"), metadataStringValue(metadata, "threadId"), metadataStringValue(metadata, "nativeSessionId"), metadataStringValue(metadata, "pairingSessionId"), metadataStringValue(metadata, "sessionId"), endpoint.sessionId, metadataStringValue(metadata, "runtimeSessionId"), metadataStringValue(metadata, "runtimeInstanceId"), metadataStringValue(metadata, "tmuxSession"));
41283
- }
41284
41661
  function endpointRuntimeSessionExternalId(endpoint) {
41285
41662
  const metadata = runtimeSessionMetadata(endpoint);
41286
- return firstStringValue(metadataStringValue(metadata, "externalSessionId"), metadataStringValue(metadata, "threadId"), metadataStringValue(metadata, "nativeSessionId"), metadataStringValue(metadata, "pairingSessionId"));
41663
+ return firstStringValue2(metadataStringValue2(metadata, "externalSessionId"), metadataStringValue2(metadata, "threadId"), metadataStringValue2(metadata, "nativeSessionId"), metadataStringValue2(metadata, "pairingSessionId"));
41287
41664
  }
41288
41665
  function endpointRuntimeSessionStartedAt(endpoint, fallback2) {
41289
41666
  const metadata = runtimeSessionMetadata(endpoint);
@@ -41299,16 +41676,6 @@ function endpointRuntimeSessionIsTerminal(endpoint) {
41299
41676
  function endpointRuntimeSessionState(endpoint) {
41300
41677
  return endpoint.metadata?.staleLocalRegistration === true ? "superseded" : endpoint.state;
41301
41678
  }
41302
- function endpointRuntimeSessionId(endpoint, primaryAlias) {
41303
- const key = [
41304
- endpoint.nodeId,
41305
- endpoint.agentId,
41306
- endpoint.harness,
41307
- endpoint.transport,
41308
- primaryAlias
41309
- ].join("\x00");
41310
- return `sess.${stableHash2(key)}`;
41311
- }
41312
41679
  function endpointRuntimeSessionAliases(endpoint, scoutSessionId) {
41313
41680
  const metadata = runtimeSessionMetadata(endpoint);
41314
41681
  const aliases = [
@@ -41319,12 +41686,12 @@ function endpointRuntimeSessionAliases(endpoint, scoutSessionId) {
41319
41686
  aliases.push({ alias: endpoint.sessionId.trim(), aliasKind: "endpoint_session" });
41320
41687
  }
41321
41688
  for (const entry of RUNTIME_SESSION_ALIAS_METADATA_KEYS) {
41322
- const value = metadataStringValue(metadata, entry.key);
41689
+ const value = metadataStringValue2(metadata, entry.key);
41323
41690
  if (value) {
41324
41691
  aliases.push({ alias: value, aliasKind: entry.kind });
41325
41692
  }
41326
41693
  }
41327
- const provisionalHandle = metadataStringValue(metadata, "handle");
41694
+ const provisionalHandle = metadataStringValue2(metadata, "handle");
41328
41695
  if (provisionalHandle) {
41329
41696
  aliases.push({ alias: provisionalHandle, aliasKind: "provisional" });
41330
41697
  }
@@ -41443,6 +41810,7 @@ class SQLiteControlPlaneStore {
41443
41810
  pendingEvents = [];
41444
41811
  flushPendingEventsTimer = null;
41445
41812
  conversationsApi = null;
41813
+ closed = false;
41446
41814
  constructor(dbPath) {
41447
41815
  mkdirSync7(dirname18(dbPath), { recursive: true });
41448
41816
  this.db = openControlPlaneSqliteDatabase(dbPath, { create: true });
@@ -41461,6 +41829,9 @@ class SQLiteControlPlaneStore {
41461
41829
  }
41462
41830
  });
41463
41831
  }
41832
+ get isClosed() {
41833
+ return this.closed;
41834
+ }
41464
41835
  listRuntimeSessions(options = {}) {
41465
41836
  const predicates = [];
41466
41837
  const params = [];
@@ -41717,6 +42088,10 @@ class SQLiteControlPlaneStore {
41717
42088
  };
41718
42089
  }
41719
42090
  close() {
42091
+ if (this.closed) {
42092
+ return;
42093
+ }
42094
+ this.closed = true;
41720
42095
  this.flushPendingEvents();
41721
42096
  if (this.flushPendingEventsTimer) {
41722
42097
  clearTimeout(this.flushPendingEventsTimer);
@@ -41731,16 +42106,29 @@ class SQLiteControlPlaneStore {
41731
42106
  }
41732
42107
  const nextBatch = this.pendingEvents;
41733
42108
  this.pendingEvents = [];
41734
- this.persistEventsBatch(nextBatch);
42109
+ try {
42110
+ this.persistEventsBatch(nextBatch);
42111
+ } catch (error) {
42112
+ this.pendingEvents = [...nextBatch, ...this.pendingEvents];
42113
+ throw error;
42114
+ }
41735
42115
  }
41736
- schedulePendingEventFlush() {
42116
+ schedulePendingEventFlush(delayMs = 0) {
41737
42117
  if (this.flushPendingEventsTimer) {
41738
42118
  return;
41739
42119
  }
41740
42120
  this.flushPendingEventsTimer = setTimeout(() => {
41741
42121
  this.flushPendingEventsTimer = null;
41742
- this.flushPendingEvents();
41743
- }, 0);
42122
+ try {
42123
+ this.flushPendingEvents();
42124
+ } catch (error) {
42125
+ if (isTransientSqliteBusyError(error)) {
42126
+ this.schedulePendingEventFlush(PENDING_EVENT_BUSY_RETRY_MS);
42127
+ return;
42128
+ }
42129
+ throw error;
42130
+ }
42131
+ }, delayMs);
41744
42132
  this.flushPendingEventsTimer.unref?.();
41745
42133
  }
41746
42134
  loadSnapshot() {
@@ -41886,7 +42274,7 @@ class SQLiteControlPlaneStore {
41886
42274
  audience: parseJson(row.audience_json, undefined),
41887
42275
  visibility: row.visibility,
41888
42276
  policy: row.policy,
41889
- createdAt: row.created_at,
42277
+ createdAt: normalizeTimestampMs(row.created_at) ?? row.created_at,
41890
42278
  metadata: parseJson(row.metadata_json, undefined)
41891
42279
  };
41892
42280
  }
@@ -41992,6 +42380,51 @@ class SQLiteControlPlaneStore {
41992
42380
  activeFlights: this.listConversationThreadFlights(conversation)
41993
42381
  };
41994
42382
  }
42383
+ getConversationThreadLaunchSnapshot(options) {
42384
+ const conversation = this.getConversation(options.conversationId, this.readDb);
42385
+ if (!conversation) {
42386
+ return null;
42387
+ }
42388
+ const requestedLimit = Math.floor(options.limit ?? 64);
42389
+ const limit = Number.isFinite(requestedLimit) ? Math.max(1, Math.min(64, requestedLimit)) : 64;
42390
+ const rows = queryAll(this.readDb, `SELECT
42391
+ m.id,
42392
+ m.actor_id,
42393
+ a.display_name AS actor_name,
42394
+ m.body,
42395
+ m.class,
42396
+ m.created_at
42397
+ FROM messages m
42398
+ LEFT JOIN actors a ON a.id = m.actor_id
42399
+ WHERE m.conversation_id = ?1
42400
+ ORDER BY CASE
42401
+ WHEN m.created_at > 0 AND m.created_at < ${EPOCH_MILLISECONDS_FLOOR}
42402
+ THEN m.created_at * 1000
42403
+ ELSE m.created_at
42404
+ END DESC, m.id DESC
42405
+ LIMIT ?2`, options.conversationId, limit + 1);
42406
+ const hasEarlier = rows.length > limit;
42407
+ const page = rows.slice(0, limit).reverse();
42408
+ return {
42409
+ projectionId: options.projectionId,
42410
+ projectionVersion: options.projectionVersion,
42411
+ sequence: options.sequence,
42412
+ feedId: scoutConversationFeedId(options.conversationId),
42413
+ entityKind: "scout_conversation",
42414
+ conversationId: options.conversationId,
42415
+ cursor: page[0]?.id ?? null,
42416
+ hasEarlier,
42417
+ generatedAt: options.generatedAt ?? currentTimestampMs(),
42418
+ messages: page.map((row) => ({
42419
+ id: row.id,
42420
+ actorId: row.actor_id,
42421
+ actorName: row.actor_name,
42422
+ body: row.body,
42423
+ class: row.class,
42424
+ createdAt: row.created_at
42425
+ }))
42426
+ };
42427
+ }
41995
42428
  upsertThreadCursor(conversationId, authorityNodeId, lastAppliedSeq, updatedAt) {
41996
42429
  this.db.query(`INSERT INTO thread_cursors (
41997
42430
  conversation_id, authority_node_id, last_applied_seq, updated_at
@@ -42202,12 +42635,16 @@ class SQLiteControlPlaneStore {
42202
42635
  WHERE endpoint_id = ?3`).run(expiresAt, observedAt2, endpointId);
42203
42636
  }
42204
42637
  projectRuntimeSessionForEndpoint(endpoint, observedAt2) {
42205
- const primaryAlias = endpointRuntimeSessionPrimaryAlias(endpoint);
42638
+ const primaryAlias = runtimeSessionPrimaryAlias(endpoint);
42206
42639
  if (!primaryAlias) {
42207
42640
  this.markRuntimeSessionsForEndpointEnded(endpoint.id, null, observedAt2);
42208
42641
  return;
42209
42642
  }
42210
- const sessionId = endpointRuntimeSessionId(endpoint, primaryAlias);
42643
+ const sessionId = runtimeSessionHandleForEndpoint(endpoint, primaryAlias);
42644
+ if (!sessionId) {
42645
+ this.markRuntimeSessionsForEndpointEnded(endpoint.id, null, observedAt2);
42646
+ return;
42647
+ }
42211
42648
  const lastSeenAt = endpointRuntimeSessionLastSeenAt(endpoint, observedAt2);
42212
42649
  const startedAt = endpointRuntimeSessionStartedAt(endpoint, lastSeenAt);
42213
42650
  const terminal = endpointRuntimeSessionIsTerminal(endpoint);
@@ -42557,10 +42994,23 @@ class SQLiteControlPlaneStore {
42557
42994
  targetAgentId: identity.target_agent_id
42558
42995
  };
42559
42996
  }
42560
- this.db.query(`INSERT OR REPLACE INTO flights (
42997
+ this.db.query(`INSERT INTO flights (
42561
42998
  id, invocation_id, requester_id, target_agent_id, state, summary, output, error,
42562
42999
  labels_json, metadata_json, started_at, completed_at
42563
- ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)`).run(recorded.id, recorded.invocationId, recorded.requesterId, recorded.targetAgentId, recorded.state, recorded.summary ?? null, recorded.output ?? null, recorded.error ?? null, stringify3(recorded.labels), stringify3(recorded.metadata), recorded.startedAt ?? null, recorded.completedAt ?? null);
43000
+ ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)
43001
+ ON CONFLICT(id) DO UPDATE SET
43002
+ rowid = (SELECT COALESCE(MAX(rowid), 0) + 1 FROM flights),
43003
+ invocation_id = excluded.invocation_id,
43004
+ requester_id = excluded.requester_id,
43005
+ target_agent_id = excluded.target_agent_id,
43006
+ state = excluded.state,
43007
+ summary = excluded.summary,
43008
+ output = excluded.output,
43009
+ error = excluded.error,
43010
+ labels_json = excluded.labels_json,
43011
+ metadata_json = excluded.metadata_json,
43012
+ started_at = excluded.started_at,
43013
+ completed_at = excluded.completed_at`).run(recorded.id, recorded.invocationId, recorded.requesterId, recorded.targetAgentId, recorded.state, recorded.summary ?? null, recorded.output ?? null, recorded.error ?? null, stringify3(recorded.labels), stringify3(recorded.metadata), recorded.startedAt ?? null, recorded.completedAt ?? null);
42564
43014
  this.db.query(`UPDATE invocations SET
42565
43015
  flight_id = ?2, state = ?3, summary = ?4, output = ?5, error = ?6,
42566
43016
  started_at = ?7, completed_at = ?8, flight_metadata_json = ?9
@@ -42740,42 +43190,48 @@ class SQLiteControlPlaneStore {
42740
43190
  }));
42741
43191
  }
42742
43192
  recordDeliveries(deliveries2) {
42743
- for (const delivery of deliveries2) {
42744
- this.drizzleDb.insert(deliveriesTable).values({
42745
- id: delivery.id,
42746
- messageId: delivery.messageId ?? null,
42747
- invocationId: delivery.invocationId ?? null,
42748
- targetId: delivery.targetId,
42749
- targetNodeId: delivery.targetNodeId ?? null,
42750
- targetKind: delivery.targetKind,
42751
- transport: delivery.transport,
42752
- reason: delivery.reason,
42753
- policy: delivery.policy,
42754
- status: delivery.status,
42755
- bindingId: delivery.bindingId ?? null,
42756
- leaseOwner: delivery.leaseOwner ?? null,
42757
- leaseExpiresAt: delivery.leaseExpiresAt ?? null,
42758
- metadataJson: stringify3(delivery.metadata),
42759
- createdAt: this.deliveryCreatedAt(delivery)
42760
- }).onConflictDoUpdate({
42761
- target: deliveriesTable.id,
42762
- set: {
42763
- messageId: delivery.messageId ?? null,
42764
- invocationId: delivery.invocationId ?? null,
42765
- targetId: delivery.targetId,
42766
- targetNodeId: delivery.targetNodeId ?? null,
42767
- targetKind: delivery.targetKind,
42768
- transport: delivery.transport,
42769
- reason: delivery.reason,
42770
- policy: delivery.policy,
42771
- status: delivery.status,
42772
- bindingId: delivery.bindingId ?? null,
42773
- leaseOwner: delivery.leaseOwner ?? null,
42774
- leaseExpiresAt: delivery.leaseExpiresAt ?? null,
42775
- metadataJson: stringify3(delivery.metadata)
42776
- }
42777
- }).run();
42778
- }
43193
+ if (deliveries2.length === 0)
43194
+ return;
43195
+ const statement = this.db.query(`INSERT INTO deliveries (
43196
+ id, message_id, invocation_id, target_id, target_node_id, target_kind,
43197
+ transport, reason, policy, status, binding_id, lease_owner, lease_expires_at,
43198
+ metadata_json, created_at
43199
+ ) VALUES (
43200
+ ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15
43201
+ )
43202
+ ON CONFLICT(id) DO UPDATE SET
43203
+ message_id = excluded.message_id,
43204
+ invocation_id = excluded.invocation_id,
43205
+ target_id = excluded.target_id,
43206
+ target_node_id = excluded.target_node_id,
43207
+ target_kind = excluded.target_kind,
43208
+ transport = excluded.transport,
43209
+ reason = excluded.reason,
43210
+ policy = excluded.policy,
43211
+ status = excluded.status,
43212
+ binding_id = excluded.binding_id,
43213
+ lease_owner = excluded.lease_owner,
43214
+ lease_expires_at = excluded.lease_expires_at,
43215
+ metadata_json = excluded.metadata_json`);
43216
+ this.db.transaction((batch) => {
43217
+ const createdAtBySource = new Map;
43218
+ for (const delivery of batch) {
43219
+ const sourceKey = delivery.messageId || delivery.invocationId ? `${delivery.messageId ?? ""}\x00${delivery.invocationId ?? ""}` : null;
43220
+ let createdAt;
43221
+ if (sourceKey === null) {
43222
+ createdAt = this.deliveryCreatedAt(delivery);
43223
+ } else {
43224
+ const cached = createdAtBySource.get(sourceKey);
43225
+ if (cached !== undefined) {
43226
+ createdAt = cached;
43227
+ } else {
43228
+ createdAt = this.deliveryCreatedAt(delivery);
43229
+ createdAtBySource.set(sourceKey, createdAt);
43230
+ }
43231
+ }
43232
+ statement.run(delivery.id, delivery.messageId ?? null, delivery.invocationId ?? null, delivery.targetId, delivery.targetNodeId ?? null, delivery.targetKind, delivery.transport, delivery.reason, delivery.policy, delivery.status, delivery.bindingId ?? null, delivery.leaseOwner ?? null, delivery.leaseExpiresAt ?? null, stringify3(delivery.metadata), createdAt);
43233
+ }
43234
+ })(deliveries2);
42779
43235
  }
42780
43236
  deliveryCreatedAt(delivery) {
42781
43237
  const messageCreatedAt = delivery.messageId ? queryGet(this.db, "SELECT created_at FROM messages WHERE id = ?1 LIMIT 1", delivery.messageId)?.created_at : null;
@@ -43280,6 +43736,17 @@ class SQLiteControlPlaneStore {
43280
43736
  get writerDb() {
43281
43737
  return this.db;
43282
43738
  }
43739
+ runReplayTransaction(operation) {
43740
+ this.db.transaction(() => {
43741
+ const previousReadDb = this.readDb;
43742
+ this.readDb = this.db;
43743
+ try {
43744
+ operation();
43745
+ } finally {
43746
+ this.readDb = previousReadDb;
43747
+ }
43748
+ })();
43749
+ }
43283
43750
  get readerDb() {
43284
43751
  return this.readDb;
43285
43752
  }
@@ -43563,7 +44030,7 @@ class SQLiteControlPlaneStore {
43563
44030
  this.schedulePendingEventFlush();
43564
44031
  }
43565
44032
  }
43566
- var RUNTIME_SESSION_RETENTION_MS, RUNTIME_SESSION_ALIAS_METADATA_KEYS;
44033
+ var PENDING_EVENT_BUSY_RETRY_MS = 25, RUNTIME_SESSION_RETENTION_MS, RUNTIME_SESSION_ALIAS_METADATA_KEYS;
43567
44034
  var init_sqlite_store = __esm(() => {
43568
44035
  init_drizzle_orm();
43569
44036
  init_node_identity();
@@ -43575,6 +44042,7 @@ var init_sqlite_store = __esm(() => {
43575
44042
  init_api();
43576
44043
  init_drizzle_schema();
43577
44044
  init_budget_observations2();
44045
+ init_runtime_session_handle();
43578
44046
  RUNTIME_SESSION_RETENTION_MS = 30 * 24 * 60 * 60 * 1000;
43579
44047
  RUNTIME_SESSION_ALIAS_METADATA_KEYS = [
43580
44048
  { key: "sessionId", kind: "metadata_session" },
@@ -43589,7 +44057,7 @@ var init_sqlite_store = __esm(() => {
43589
44057
  });
43590
44058
 
43591
44059
  // ../runtime/src/mesh-peer-auth.ts
43592
- import { createHash as createHash5, randomBytes as randomBytes2 } from "crypto";
44060
+ import { createHash as createHash6, randomBytes as randomBytes2 } from "crypto";
43593
44061
  function assertNoNewlines(component, name) {
43594
44062
  if (component.includes(`
43595
44063
  `) || component.includes("\r")) {
@@ -43615,7 +44083,7 @@ function peerRequestSigningPayload(input) {
43615
44083
  `);
43616
44084
  }
43617
44085
  function sha256Hex(body) {
43618
- return createHash5("sha256").update(body).digest("hex");
44086
+ return createHash6("sha256").update(body).digest("hex");
43619
44087
  }
43620
44088
  function signPeerRequest(identity, input) {
43621
44089
  const ts = input.ts ?? Date.now();
@@ -58671,14 +59139,14 @@ var init_x509_es = __esm(() => {
58671
59139
 
58672
59140
  // ../runtime/src/node-tls-identity.ts
58673
59141
  import {
58674
- createHash as createHash6,
59142
+ createHash as createHash7,
58675
59143
  createPrivateKey as createPrivateKey2,
58676
59144
  createPublicKey as createPublicKey2,
58677
59145
  generateKeyPairSync as generateKeyPairSync2,
58678
59146
  randomBytes as randomBytes3
58679
59147
  } from "crypto";
58680
59148
  function tlsSpkiFingerprintFromDer(spkiDer) {
58681
- return createHash6("sha256").update(spkiDer).digest("hex");
59149
+ return createHash7("sha256").update(spkiDer).digest("hex");
58682
59150
  }
58683
59151
  function tlsSpkiFingerprintFromCertificateDer(certificateDer) {
58684
59152
  const certificate2 = new X509Certificate(asBufferSource(certificateDer));
@@ -59302,10 +59770,12 @@ var init_mesh_dial_order = __esm(() => {
59302
59770
  });
59303
59771
 
59304
59772
  // ../runtime/src/mesh-forwarding.ts
59773
+ var MAX_PEER_AGENT_SNAPSHOT_BYTES;
59305
59774
  var init_mesh_forwarding = __esm(() => {
59306
59775
  init_iroh_bridge();
59307
59776
  init_mesh_peer_client();
59308
59777
  init_mesh_dial_order();
59778
+ MAX_PEER_AGENT_SNAPSHOT_BYTES = 2 * 1024 * 1024;
59309
59779
  });
59310
59780
 
59311
59781
  // ../runtime/src/mesh-rendezvous.ts
@@ -60639,9 +61109,9 @@ var init_eff_short_wordlist = __esm(() => {
60639
61109
  });
60640
61110
 
60641
61111
  // ../runtime/src/mesh-sas.ts
60642
- import { createHash as createHash7, createHmac } from "crypto";
61112
+ import { createHash as createHash8, createHmac } from "crypto";
60643
61113
  function createEnrollmentCommitment(nonce, cardSignature) {
60644
- return createHash7("sha256").update(Buffer.concat([nonce, Buffer.from(cardSignature, "utf8")])).digest("base64");
61114
+ return createHash8("sha256").update(Buffer.concat([nonce, Buffer.from(cardSignature, "utf8")])).digest("base64");
60645
61115
  }
60646
61116
  function verifyEnrollmentCommitment(commitment, nonce, cardSignature) {
60647
61117
  const expected = createEnrollmentCommitment(nonce, cardSignature);
@@ -62068,6 +62538,7 @@ var TERMINAL_ENDPOINT_STATES;
62068
62538
  var init_broker_endpoint_selection = __esm(() => {
62069
62539
  init_a2a_http_endpoint();
62070
62540
  init_local_agent_transports();
62541
+ init_runtime_session_handle();
62071
62542
  TERMINAL_ENDPOINT_STATES = new Set([
62072
62543
  "failed",
62073
62544
  "superseded",
@@ -64470,11 +64941,11 @@ var init_paths2 = __esm(() => {
64470
64941
 
64471
64942
  // ../runtime/src/knowledge/store.ts
64472
64943
  import { existsSync as existsSync31, mkdirSync as mkdirSync10, statSync as statSync8 } from "fs";
64473
- import { createHash as createHash8, randomUUID as randomUUID4 } from "crypto";
64944
+ import { createHash as createHash9, randomUUID as randomUUID4 } from "crypto";
64474
64945
  import { dirname as dirname21 } from "path";
64475
64946
  import { Database as Database3 } from "bun:sqlite";
64476
64947
  function ftsRowidForChunk(chunkId) {
64477
- return createHash8("sha256").update(chunkId).digest().readBigInt64BE(0);
64948
+ return createHash9("sha256").update(chunkId).digest().readBigInt64BE(0);
64478
64949
  }
64479
64950
  function stringify4(value) {
64480
64951
  return JSON.stringify(value ?? null);
@@ -64513,7 +64984,7 @@ function normalizeFtsQueryOr(value) {
64513
64984
  return terms.map(quoteFtsTerm).join(" OR ");
64514
64985
  }
64515
64986
  function textHash(value) {
64516
- return `sha256:${createHash8("sha256").update(value).digest("hex")}`;
64987
+ return `sha256:${createHash9("sha256").update(value).digest("hex")}`;
64517
64988
  }
64518
64989
  function deterministicKnowledgeChunkId(input) {
64519
64990
  return textHash([
@@ -65268,7 +65739,7 @@ var init_store = __esm(() => {
65268
65739
  });
65269
65740
 
65270
65741
  // ../runtime/src/knowledge/session-indexer.ts
65271
- import { createHash as createHash9 } from "crypto";
65742
+ import { createHash as createHash10 } from "crypto";
65272
65743
  import {
65273
65744
  createReadStream as createReadStream2,
65274
65745
  existsSync as existsSync32,
@@ -65382,7 +65853,7 @@ function discoverRecentSessionFiles(cutoffMs, limit, harnessFilter) {
65382
65853
  async function parseJsonl(file) {
65383
65854
  const maybeYield = createYieldBudget();
65384
65855
  const records = [];
65385
- const hash = createHash9("sha256");
65856
+ const hash = createHash10("sha256");
65386
65857
  let carry = "";
65387
65858
  let offset = 0;
65388
65859
  let index2 = 0;
@@ -65713,10 +66184,10 @@ function trimOneLine(value, max) {
65713
66184
  return flat.length <= max ? flat : `${flat.slice(0, Math.max(0, max - 3))}...`;
65714
66185
  }
65715
66186
  function hashText(value) {
65716
- return `sha256:${createHash9("sha256").update(value).digest("hex")}`;
66187
+ return `sha256:${createHash10("sha256").update(value).digest("hex")}`;
65717
66188
  }
65718
66189
  function stableId(value, length = 16) {
65719
- return createHash9("sha256").update(value).digest("hex").slice(0, length);
66190
+ return createHash10("sha256").update(value).digest("hex").slice(0, length);
65720
66191
  }
65721
66192
  function portablePath(filePath) {
65722
66193
  const home = homedir27();
@@ -66568,7 +67039,7 @@ var init_sender = __esm(() => {
66568
67039
  // ../../apps/desktop/src/core/broker/service.ts
66569
67040
  import { mkdir as mkdir11, readFile as readFile15, unlink, writeFile as writeFile10 } from "fs/promises";
66570
67041
  import { basename as basename12, join as join39, resolve as resolve17 } from "path";
66571
- import { createHash as createHash10, randomUUID as randomUUID5 } from "crypto";
67042
+ import { createHash as createHash11, randomUUID as randomUUID5 } from "crypto";
66572
67043
  function relayHubDirectory() {
66573
67044
  return resolveOpenScoutSupportPaths().relayHubDirectory;
66574
67045
  }
@@ -66660,7 +67131,7 @@ function deliveryRequestId(clientMessageId, createdAt) {
66660
67131
  if (!normalized) {
66661
67132
  return `deliver-${createdAt.toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
66662
67133
  }
66663
- const digest = createHash10("sha256").update(normalized).digest("hex").slice(0, 32);
67134
+ const digest = createHash11("sha256").update(normalized).digest("hex").slice(0, 32);
66664
67135
  return `deliver-client-${digest}`;
66665
67136
  }
66666
67137
  function metadataStringList(metadata, key) {
@@ -68040,10 +68511,6 @@ async function ensureBrokerDirectConversationBetween(baseUrl, snapshot, nodeId,
68040
68511
  };
68041
68512
  }
68042
68513
  async function sendScoutMessage(input) {
68043
- const broker2 = await loadScoutBrokerContext();
68044
- if (!broker2) {
68045
- return { usedBroker: false, invokedTargets: [], unresolvedTargets: [] };
68046
- }
68047
68514
  const currentDirectory = input.currentDirectory ?? process.cwd();
68048
68515
  const source = input.source?.trim() || "scout-cli";
68049
68516
  const wake = input.wake ?? false;
@@ -68056,15 +68523,19 @@ async function sendScoutMessage(input) {
68056
68523
  source,
68057
68524
  sourceIntent: "tell_wake"
68058
68525
  } : undefined;
68059
- const senderId = await resolveConversationActorId(broker2.baseUrl, broker2.snapshot, broker2.node.id, input.senderId, currentDirectory);
68060
68526
  const requestedTargetLabel = input.targetLabel?.trim();
68061
68527
  const requestedTargetRef = input.targetRef?.trim();
68062
68528
  if (requestedTargetLabel || requestedTargetRef) {
68529
+ const health = await readScoutBrokerHealth();
68530
+ if (!health.reachable || !health.ok || !health.nodeId) {
68531
+ return { usedBroker: false, invokedTargets: [], unresolvedTargets: [] };
68532
+ }
68533
+ const senderId2 = await resolveConversationActorId(health.baseUrl, createRuntimeRegistrySnapshot(), health.nodeId, input.senderId, currentDirectory);
68063
68534
  const { target: target2, renderedTarget, isBindingRef } = routeTargetForTargetLabel(requestedTargetLabel ?? "", requestedTargetRef, input.aliasScope);
68064
- const delivery = await brokerPostDeliver(broker2.baseUrl, {
68535
+ const delivery = await brokerPostDeliver(health.baseUrl, {
68065
68536
  caller: {
68066
- actorId: senderId,
68067
- nodeId: broker2.node.id,
68537
+ actorId: senderId2,
68538
+ nodeId: health.nodeId,
68068
68539
  currentDirectory,
68069
68540
  metadata: { source }
68070
68541
  },
@@ -68107,6 +68578,11 @@ async function sendScoutMessage(input) {
68107
68578
  routeKind: delivery.routeKind
68108
68579
  };
68109
68580
  }
68581
+ const broker2 = await loadScoutBrokerContext();
68582
+ if (!broker2) {
68583
+ return { usedBroker: false, invokedTargets: [], unresolvedTargets: [] };
68584
+ }
68585
+ const senderId = await resolveConversationActorId(broker2.baseUrl, broker2.snapshot, broker2.node.id, input.senderId, currentDirectory);
68110
68586
  const mentionResolution = await resolveMentionTargets(broker2.snapshot, input.body, currentDirectory);
68111
68587
  const selectors = extractAgentSelectors(input.body);
68112
68588
  if (selectors.length === 1 && mentionResolution.resolved.length + mentionResolution.unresolved.length + mentionResolution.ambiguous.length === 1) {
@@ -69582,6 +70058,7 @@ var init_service3 = __esm(() => {
69582
70058
  init_broker_api();
69583
70059
  init_broker_process_manager();
69584
70060
  init_local_agents();
70061
+ init_registry3();
69585
70062
  init_support_paths();
69586
70063
  init_user_config();
69587
70064
  init_paths();
@@ -70509,6 +70986,12 @@ function describeStopStep(step) {
70509
70986
  return `sweep supervised stragglers (${step.pids.length} candidate${step.pids.length === 1 ? "" : "s"})`;
70510
70987
  }
70511
70988
  }
70989
+ function ownedSweepSurvivorPids(step, tree) {
70990
+ const candidates = new Set(step.pids);
70991
+ const stillOwned = layerProcesses(tree, step.layers);
70992
+ const reparentedFromThisCheckout = detachedExpectedProcesses(tree).filter((entry) => step.layers.includes(entry.layer));
70993
+ return [...stillOwned, ...reparentedFromThisCheckout].map((entry) => entry.pid).filter((pid) => candidates.has(pid));
70994
+ }
70512
70995
  function processAlive(pid) {
70513
70996
  try {
70514
70997
  process.kill(pid, 0);
@@ -70578,6 +71061,9 @@ function bootstrapLaunchdJob(plistPath, uid) {
70578
71061
  const ok = (result.status ?? 1) === 0 || /already bootstrapped|Operation already in progress/i.test(detail);
70579
71062
  return { ok, detail };
70580
71063
  }
71064
+ function scoutdStartArguments(options = {}) {
71065
+ return options.waitForHealth === false ? ["start", "--no-wait"] : ["start"];
71066
+ }
70581
71067
  function chooseLaunchdStartMethod(input) {
70582
71068
  if (input.scoutdPath)
70583
71069
  return "scoutd";
@@ -70597,7 +71083,7 @@ function startLaunchdJob(label, uid, home, options = {}) {
70597
71083
  case "kickstart":
70598
71084
  return { ...kickstartLaunchdJob(label, uid, { restart: options.restart }), method };
70599
71085
  case "scoutd": {
70600
- const result = spawnSync4(scoutdPath, ["start"], { encoding: "utf8" });
71086
+ const result = spawnSync4(scoutdPath, scoutdStartArguments(options), { encoding: "utf8" });
70601
71087
  const detail = `${result.stdout ?? ""}${result.stderr ?? ""}`.trim();
70602
71088
  return { ok: (result.status ?? 1) === 0, detail, method };
70603
71089
  }
@@ -70692,6 +71178,7 @@ var init_app_lifecycle = __esm(() => {
70692
71178
  // ../../apps/desktop/src/cli/commands/app.ts
70693
71179
  var exports_app = {};
70694
71180
  __export(exports_app, {
71181
+ startTreeReady: () => startTreeReady,
70695
71182
  selectInstalledAppBundle: () => selectInstalledAppBundle,
70696
71183
  runAppCommand: () => runAppCommand,
70697
71184
  renderAppCommandHelp: () => renderAppCommandHelp,
@@ -70828,6 +71315,13 @@ async function waitFor(paths2, predicate, timeoutMs) {
70828
71315
  }
70829
71316
  return tree;
70830
71317
  }
71318
+ function startTreeReady(tree, scope) {
71319
+ const appsReady = tree.layers.app.length > 0 && tree.layers.menu.length > 0;
71320
+ if (!appsReady || scope === "apps") {
71321
+ return appsReady;
71322
+ }
71323
+ return SUPERVISED_LAYERS.every((layer) => tree.layers[layer].length > 0);
71324
+ }
70831
71325
  async function stopSuite(paths2, steps, scope) {
70832
71326
  const tree = readTree(paths2);
70833
71327
  const uid = process.getuid?.() ?? 0;
@@ -70838,7 +71332,12 @@ async function stopSuite(paths2, steps, scope) {
70838
71332
  steps.push(result.ok ? label : `${label} \u2014 failed: ${result.detail || "unknown error"}`);
70839
71333
  continue;
70840
71334
  }
70841
- const { escalated, survivors } = await terminateProcesses(step.pids);
71335
+ let pids = step.pids;
71336
+ if (step.kind === "sweep") {
71337
+ const drainedTree = await waitFor(paths2, (candidate) => ownedSweepSurvivorPids(step, candidate).length === 0, SUPERVISED_DRAIN_TIMEOUT_MS);
71338
+ pids = ownedSweepSurvivorPids(step, drainedTree);
71339
+ }
71340
+ const { escalated, survivors } = await terminateProcesses(pids);
70842
71341
  const notes = [];
70843
71342
  if (escalated.length > 0)
70844
71343
  notes.push(`escalated to SIGKILL: ${escalated.join(", ")}`);
@@ -70851,22 +71350,27 @@ async function stopSuite(paths2, steps, scope) {
70851
71350
  }
70852
71351
  async function startSuite(paths2, steps, scope, options = {}) {
70853
71352
  const uid = process.getuid?.() ?? 0;
71353
+ let supervisedReadiness = null;
70854
71354
  if (scope === "apps") {
70855
71355
  steps.push("skip launchd (--apps-only)");
70856
71356
  } else {
70857
71357
  const label = resolveLaunchdLabel();
70858
71358
  const launched = startLaunchdJob(label, uid, homedir28(), {
70859
71359
  restart: options.restart,
70860
- serviceRoot: paths2.serviceRoot
71360
+ serviceRoot: paths2.serviceRoot,
71361
+ waitForHealth: false
70861
71362
  });
70862
71363
  steps.push(launched.ok ? `${launched.method} ${label}` : `${launched.method} ${label} \u2014 failed: ${launched.detail || "unknown error"}`);
70863
- const supervised = await waitFor(paths2, (tree2) => SUPERVISED_LAYERS.every((layer) => tree2.layers[layer].length > 0), READY_TIMEOUT_MS);
70864
- const missing = SUPERVISED_LAYERS.filter((layer) => supervised.layers[layer].length === 0);
70865
- steps.push(missing.length === 0 ? "supervised tree ready" : `supervised tree incomplete \u2014 missing ${missing.join(", ")}`);
71364
+ supervisedReadiness = waitFor(paths2, (tree2) => SUPERVISED_LAYERS.every((layer) => tree2.layers[layer].length > 0), SUPERVISED_READY_TIMEOUT_MS);
70866
71365
  }
70867
71366
  const open = spawnSync5("open", [paths2.appBundlePath], { encoding: "utf8" });
70868
71367
  steps.push((open.status ?? 1) === 0 ? `open ${paths2.appBundlePath}` : `open ${paths2.appBundlePath} \u2014 failed: ${(open.stderr ?? "").trim() || "unknown error"}`);
70869
- const tree = await waitFor(paths2, (candidate) => candidate.layers.app.length > 0 && candidate.layers.menu.length > 0, READY_TIMEOUT_MS);
71368
+ if (supervisedReadiness) {
71369
+ const supervised = await supervisedReadiness;
71370
+ const missing = SUPERVISED_LAYERS.filter((layer) => supervised.layers[layer].length === 0);
71371
+ steps.push(missing.length === 0 ? "supervised tree ready" : `supervised tree still starting \u2014 missing ${missing.join(", ")}`);
71372
+ }
71373
+ const tree = await waitFor(paths2, (candidate) => startTreeReady(candidate, scope), READY_TIMEOUT_MS);
70870
71374
  const appsMissing = LAUNCH_SERVICES_LAYERS.filter((layer) => layer !== "pairing" && tree.layers[layer].length === 0);
70871
71375
  steps.push(appsMissing.length === 0 ? "Scout and embedded ScoutMenu ready" : `apps incomplete \u2014 missing ${appsMissing.join(", ")}`);
70872
71376
  return tree;
@@ -70992,7 +71496,7 @@ async function runAppCommand(context, args) {
70992
71496
  throw new ScoutCliError(result.message);
70993
71497
  }
70994
71498
  }
70995
- var HELP_FLAGS2, INSTALLED_APP_BUNDLE_ID = "app.openscout.scout", INSTALLED_APP_BUNDLE_NAME = "OpenScout.app", READY_TIMEOUT_MS = 30000, POLL_MS = 250;
71499
+ var HELP_FLAGS2, INSTALLED_APP_BUNDLE_ID = "app.openscout.scout", INSTALLED_APP_BUNDLE_NAME = "OpenScout.app", READY_TIMEOUT_MS = 30000, SUPERVISED_READY_TIMEOUT_MS = 120000, SUPERVISED_DRAIN_TIMEOUT_MS = 20000, POLL_MS = 250;
70996
71500
  var init_app = __esm(() => {
70997
71501
  init_app_lifecycle();
70998
71502
  init_context();
@@ -100958,7 +101462,7 @@ var init_stdio2 = __esm(() => {
100958
101462
  // ../../apps/desktop/src/shared/product.ts
100959
101463
  var SCOUT_APP_VERSION;
100960
101464
  var init_product = __esm(() => {
100961
- SCOUT_APP_VERSION = process.env.SCOUT_APP_VERSION?.trim() || "0.2.95";
101465
+ SCOUT_APP_VERSION = process.env.SCOUT_APP_VERSION?.trim() || "0.2.96";
100962
101466
  });
100963
101467
 
100964
101468
  // ../../apps/desktop/src/core/mcp/stdio-server-lifecycle.ts
@@ -102491,7 +102995,13 @@ function renderOpenScoutCaddyfile(config2) {
102491
102995
  const blocks = schemes.flatMap((scheme) => config2.routes.map((route) => route.mode === "vite-dev" ? renderCaddyViteDevRouteBlock(route, scheme) : renderCaddyDefaultRouteBlock(config2, route, scheme, startPage))).join(`
102492
102996
 
102493
102997
  `);
102494
- return `${blocks}
102998
+ return `{
102999
+ log {
103000
+ level WARN
103001
+ }
103002
+ }
103003
+
103004
+ ${blocks}
102495
103005
  `;
102496
103006
  }
102497
103007
  var init_local_edge = __esm(() => {
@@ -104741,11 +105251,11 @@ function buildFlightCommandResult(flight, env, options = {}) {
104741
105251
  };
104742
105252
  }
104743
105253
  function buildFlightFollowHandles(flight, env) {
104744
- const conversationId = metadataStringValue2(flight.metadata, "conversationId") ?? metadataReturnAddressStringValue(flight.metadata, "conversationId");
104745
- const messageId = metadataStringValue2(flight.metadata, "messageId") ?? metadataReturnAddressStringValue(flight.metadata, "replyToMessageId");
104746
- const workId = metadataStringValue2(flight.metadata, "workId") ?? metadataStringValue2(flight.metadata, "collaborationRecordId");
104747
- const sessionId = metadataStringValue2(flight.metadata, "sessionId") ?? metadataDispatchAckStringValue(flight.metadata, "sessionId");
104748
- const bindingRef = metadataStringValue2(flight.metadata, "bindingRef") ?? flight.id.slice(-8);
105254
+ const conversationId = metadataStringValue3(flight.metadata, "conversationId") ?? metadataReturnAddressStringValue(flight.metadata, "conversationId");
105255
+ const messageId = metadataStringValue3(flight.metadata, "messageId") ?? metadataReturnAddressStringValue(flight.metadata, "replyToMessageId");
105256
+ const workId = metadataStringValue3(flight.metadata, "workId") ?? metadataStringValue3(flight.metadata, "collaborationRecordId");
105257
+ const sessionId = metadataStringValue3(flight.metadata, "sessionId") ?? metadataDispatchAckStringValue(flight.metadata, "sessionId");
105258
+ const bindingRef = metadataStringValue3(flight.metadata, "bindingRef") ?? flight.id.slice(-8);
104749
105259
  const origin = resolveScoutWebOrigin(env);
104750
105260
  const links = buildFlightLinks(origin, {
104751
105261
  flightId: flight.id,
@@ -104833,7 +105343,7 @@ function isFlightWaitTimeout(error48) {
104833
105343
  function isTerminalFlightState(state) {
104834
105344
  return state === "completed" || state === "failed" || state === "cancelled";
104835
105345
  }
104836
- function metadataStringValue2(metadata, key) {
105346
+ function metadataStringValue3(metadata, key) {
104837
105347
  const value = metadata?.[key];
104838
105348
  return typeof value === "string" && value.trim() ? value.trim() : null;
104839
105349
  }
@@ -104841,13 +105351,13 @@ function metadataReturnAddressStringValue(metadata, key) {
104841
105351
  const value = metadata?.["returnAddress"];
104842
105352
  if (!value || typeof value !== "object" || Array.isArray(value))
104843
105353
  return null;
104844
- return metadataStringValue2(value, key);
105354
+ return metadataStringValue3(value, key);
104845
105355
  }
104846
105356
  function metadataDispatchAckStringValue(metadata, key) {
104847
105357
  const value = metadata?.["dispatchAck"];
104848
105358
  if (!value || typeof value !== "object" || Array.isArray(value))
104849
105359
  return null;
104850
- return metadataStringValue2(value, key);
105360
+ return metadataStringValue3(value, key);
104851
105361
  }
104852
105362
  function trimTrailingSlash(value) {
104853
105363
  return value.replace(/\/+$/g, "");
@@ -105019,16 +105529,33 @@ var init_inbox2 = __esm(() => {
105019
105529
  // ../../apps/desktop/src/cli/commands/install.ts
105020
105530
  var exports_install = {};
105021
105531
  __export(exports_install, {
105532
+ verifyStagedOpenScoutApp: () => verifyStagedOpenScoutApp,
105533
+ verifyDownloadedDmg: () => verifyDownloadedDmg,
105534
+ verifyDownloadedAsset: () => verifyDownloadedAsset,
105022
105535
  runInstallCommand: () => runInstallCommand,
105023
105536
  renderInstallCommandHelp: () => renderInstallCommandHelp,
105537
+ processIdsForInstalledApp: () => processIdsForInstalledApp,
105024
105538
  parseInstallArgs: () => parseInstallArgs,
105539
+ parseGithubAssetDigest: () => parseGithubAssetDigest,
105025
105540
  findAppDmgAsset: () => findAppDmgAsset,
105541
+ OPENSCOUT_SIGNING_TEAM_ID: () => OPENSCOUT_SIGNING_TEAM_ID,
105026
105542
  OPENSCOUT_RELEASE_REPOSITORY: () => OPENSCOUT_RELEASE_REPOSITORY,
105027
- OPENSCOUT_RELEASE_OWNER: () => OPENSCOUT_RELEASE_OWNER
105543
+ OPENSCOUT_RELEASE_OWNER: () => OPENSCOUT_RELEASE_OWNER,
105544
+ OPENSCOUT_APP_NAME: () => OPENSCOUT_APP_NAME,
105545
+ OPENSCOUT_APP_BUNDLE_ID: () => OPENSCOUT_APP_BUNDLE_ID,
105546
+ DEFAULT_OPENSCOUT_APP_PATH: () => DEFAULT_OPENSCOUT_APP_PATH
105028
105547
  });
105029
105548
  import { spawnSync as spawnSync8 } from "child_process";
105030
- import { existsSync as existsSync39, mkdtempSync, rmSync as rmSync5, writeFileSync as writeFileSync9 } from "fs";
105031
- import { tmpdir } from "os";
105549
+ import { createHash as createHash12 } from "crypto";
105550
+ import {
105551
+ existsSync as fsExistsSync,
105552
+ mkdirSync as fsMkdirSync,
105553
+ mkdtempSync as fsMkdtempSync,
105554
+ renameSync as fsRenameSync,
105555
+ rmSync as fsRmSync,
105556
+ writeFileSync as fsWriteFileSync
105557
+ } from "fs";
105558
+ import { tmpdir as osTmpdir } from "os";
105032
105559
  import { join as join48 } from "path";
105033
105560
  function renderInstallCommandHelp() {
105034
105561
  return [
@@ -105043,11 +105570,15 @@ function renderInstallCommandHelp() {
105043
105570
  "",
105044
105571
  "Behavior:",
105045
105572
  " Downloads the signed + notarized OpenScout.dmg from the GitHub release,",
105046
- " installs OpenScout.app (which embeds the menu bar helper) to /Applications,",
105047
- " and clears the Gatekeeper quarantine flag so it opens cleanly.",
105573
+ " verifies the published byte size and sha256 digest when GitHub provides one,",
105574
+ " then codesign and Gatekeeper-assess the DMG before mounting. OpenScout.app",
105575
+ " must match the pinned bundle id and Team ID, pass codesign --deep --strict,",
105576
+ " and pass Gatekeeper execute after staging. A running copy of the installed",
105577
+ " app is stopped first; replacement is staged and rolled back on failure.",
105578
+ " Quarantine attributes are not cleared.",
105048
105579
  "",
105049
- " The app drives the bundled local runtime from the global scout CLI, so",
105050
- " `bun add -g @openscout/scout` is the companion install for the command line."
105580
+ " The app uses the local scout CLI for the bundled runtime. Install the CLI",
105581
+ " with `bun add -g @openscout/scout`."
105051
105582
  ].join(`
105052
105583
  `);
105053
105584
  }
@@ -105085,11 +105616,19 @@ function parseInstallArgs(args) {
105085
105616
  continue;
105086
105617
  }
105087
105618
  if (arg.startsWith("--version=")) {
105088
- options.version = arg.slice("--version=".length);
105619
+ const value = arg.slice("--version=".length);
105620
+ if (!value) {
105621
+ throw new ScoutCliError("--version requires a release tag (e.g. --version v0.2.70)");
105622
+ }
105623
+ options.version = value;
105089
105624
  continue;
105090
105625
  }
105091
105626
  if (arg.startsWith("--tag=")) {
105092
- options.version = arg.slice("--tag=".length);
105627
+ const value = arg.slice("--tag=".length);
105628
+ if (!value) {
105629
+ throw new ScoutCliError("--tag requires a release tag (e.g. --tag v0.2.70)");
105630
+ }
105631
+ options.version = value;
105093
105632
  continue;
105094
105633
  }
105095
105634
  throw new ScoutCliError(`unknown option for install: ${arg} (try: scout install --help)`);
@@ -105100,6 +105639,13 @@ function stripLeadingV(tag) {
105100
105639
  const trimmed = tag.trim();
105101
105640
  return trimmed.startsWith("v") ? trimmed.slice(1) : trimmed;
105102
105641
  }
105642
+ function normalizeReleaseVersion(tag) {
105643
+ const version3 = stripLeadingV(tag);
105644
+ if (!/^\d+\.\d+\.\d+$/.test(version3)) {
105645
+ throw new ScoutCliError(`unsupported OpenScout release tag: ${tag}`);
105646
+ }
105647
+ return version3;
105648
+ }
105103
105649
  function formatBytes(bytes) {
105104
105650
  if (bytes <= 0)
105105
105651
  return "unknown size";
@@ -105107,20 +105653,130 @@ function formatBytes(bytes) {
105107
105653
  return `${(bytes / 1024).toFixed(0)} KB`;
105108
105654
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
105109
105655
  }
105110
- function getInstalledVersion() {
105111
- if (!existsSync39(INFO_PLIST_PATH))
105656
+ function combinedOutput(result) {
105657
+ return `${result.stdout ?? ""}
105658
+ ${result.stderr ?? ""}`;
105659
+ }
105660
+ function permissionDeniedMessage(destination, detail) {
105661
+ const suffix = detail?.trim() ? `: ${detail.trim()}` : ".";
105662
+ return `could not replace ${destination} (permission denied)${suffix} Grant write access to the destination and retry.`;
105663
+ }
105664
+ function isPermissionError(error48, result) {
105665
+ const code = error48?.code;
105666
+ if (code === "EACCES" || code === "EPERM")
105667
+ return true;
105668
+ const output = `${error48 instanceof Error ? error48.message : ""} ${result?.stderr ?? ""} ${result?.stdout ?? ""}`.toLowerCase();
105669
+ return output.includes("permission denied") || output.includes("operation not permitted");
105670
+ }
105671
+ function defaultRun(command, args) {
105672
+ const result = spawnSync8(command, [...args], { encoding: "utf8" });
105673
+ return {
105674
+ status: result.status,
105675
+ stdout: result.stdout ?? "",
105676
+ stderr: result.stderr ?? "",
105677
+ error: result.error
105678
+ };
105679
+ }
105680
+ function defaultSleep(ms) {
105681
+ Bun.sleepSync(ms);
105682
+ }
105683
+ function resolveInstallDependencies(dependencies = {}) {
105684
+ return {
105685
+ platform: dependencies.platform ?? process.platform,
105686
+ fetch: dependencies.fetch ?? fetch,
105687
+ run: dependencies.run ?? defaultRun,
105688
+ existsSync: dependencies.existsSync ?? fsExistsSync,
105689
+ mkdirSync: dependencies.mkdirSync ?? ((path, options) => {
105690
+ fsMkdirSync(path, options);
105691
+ }),
105692
+ mkdtempSync: dependencies.mkdtempSync ?? fsMkdtempSync,
105693
+ writeFileSync: dependencies.writeFileSync ?? ((path, data) => {
105694
+ fsWriteFileSync(path, data);
105695
+ }),
105696
+ rmSync: dependencies.rmSync ?? fsRmSync,
105697
+ renameSync: dependencies.renameSync ?? fsRenameSync,
105698
+ tmpdir: dependencies.tmpdir ?? osTmpdir,
105699
+ sleep: dependencies.sleep ?? defaultSleep,
105700
+ appPath: dependencies.appPath ?? DEFAULT_OPENSCOUT_APP_PATH
105701
+ };
105702
+ }
105703
+ function requireSuccess(result, message) {
105704
+ if (result.error && result.error.code === "ENOENT") {
105705
+ throw new ScoutCliError(`${message}: ${result.error.message}`);
105706
+ }
105707
+ if ((result.status ?? 1) !== 0) {
105708
+ throw new ScoutCliError(`${message}: ${result.stderr.trim() || result.stdout.trim() || `exit ${result.status ?? "unknown"}`}`);
105709
+ }
105710
+ return result;
105711
+ }
105712
+ function parseGithubAssetDigest(digest) {
105713
+ const trimmed = digest.trim();
105714
+ const separator = trimmed.indexOf(":");
105715
+ if (separator <= 0) {
105716
+ throw new ScoutCliError(`unsupported GitHub asset digest: ${digest}`);
105717
+ }
105718
+ const algorithm = trimmed.slice(0, separator).trim().toLowerCase();
105719
+ const hex4 = trimmed.slice(separator + 1).trim().toLowerCase();
105720
+ if (algorithm !== GITHUB_ASSET_DIGEST_ALGORITHM || !/^[0-9a-f]+$/.test(hex4) || hex4.length !== GITHUB_ASSET_DIGEST_HEX_LENGTH) {
105721
+ throw new ScoutCliError(`unsupported GitHub asset digest: ${digest}`);
105722
+ }
105723
+ return { algorithm, hex: hex4 };
105724
+ }
105725
+ function verifyDownloadedAsset(buffer, asset) {
105726
+ if (typeof asset.size !== "number" || !Number.isFinite(asset.size) || asset.size < 0) {
105727
+ throw new ScoutCliError(`release asset ${asset.name} is missing an exact byte size`);
105728
+ }
105729
+ if (buffer.byteLength !== asset.size) {
105730
+ throw new ScoutCliError(`download size mismatch for ${asset.name}: expected ${asset.size} bytes, got ${buffer.byteLength}`);
105731
+ }
105732
+ if (buffer.byteLength === 0) {
105733
+ throw new ScoutCliError("download failed: empty response body");
105734
+ }
105735
+ const digest = asset.digest?.trim();
105736
+ if (!digest)
105737
+ return;
105738
+ const parsed = parseGithubAssetDigest(digest);
105739
+ let actual;
105740
+ try {
105741
+ actual = createHash12(parsed.algorithm).update(buffer).digest("hex");
105742
+ } catch {
105743
+ throw new ScoutCliError(`unsupported GitHub asset digest algorithm: ${parsed.algorithm}`);
105744
+ }
105745
+ if (actual !== parsed.hex) {
105746
+ throw new ScoutCliError(`download digest mismatch for ${asset.name}: expected ${digest}, got ${parsed.algorithm}:${actual}`);
105747
+ }
105748
+ }
105749
+ function findAppDmgAsset(release) {
105750
+ const assets = release.assets ?? [];
105751
+ const versionedName = `OpenScout-${normalizeReleaseVersion(release.tag_name)}.dmg`;
105752
+ const versioned = assets.find((asset) => asset.name === versionedName);
105753
+ if (versioned)
105754
+ return versioned;
105755
+ const latestAlias = assets.find((asset) => asset.name === LATEST_DMG_ALIAS);
105756
+ if (latestAlias)
105757
+ return latestAlias;
105758
+ throw new ScoutCliError(`no OpenScout.app DMG found in release ${release.tag_name}. Assets: ${assets.map((asset) => asset.name).join(", ") || "(none)"}`);
105759
+ }
105760
+ function infoPlistPath(appPath) {
105761
+ return join48(appPath, "Contents", "Info.plist");
105762
+ }
105763
+ function readPlistString(deps, plistPath, key) {
105764
+ if (!deps.existsSync(plistPath))
105112
105765
  return null;
105113
- const result = spawnSync8("defaults", ["read", INFO_PLIST_PATH, "CFBundleShortVersionString"], { encoding: "utf8" });
105766
+ const result = deps.run("plutil", ["-extract", key, "raw", "-o", "-", plistPath]);
105114
105767
  if ((result.status ?? 1) !== 0)
105115
105768
  return null;
105116
- const version3 = result.stdout.trim();
105117
- return version3 || null;
105769
+ const value = result.stdout.trim();
105770
+ return value || null;
105118
105771
  }
105119
- async function fetchRelease(version3) {
105772
+ function getInstalledVersion(deps) {
105773
+ return readPlistString(deps, infoPlistPath(deps.appPath), "CFBundleShortVersionString");
105774
+ }
105775
+ async function fetchRelease(version3, deps) {
105120
105776
  const base = `https://api.github.com/repos/${OPENSCOUT_RELEASE_OWNER}/${OPENSCOUT_RELEASE_REPOSITORY}/releases`;
105121
- const apiUrl = version3 ? `${base}/tags/${version3}` : `${base}/latest`;
105777
+ const apiUrl = version3 ? `${base}/tags/${encodeURIComponent(version3)}` : `${base}/latest`;
105122
105778
  try {
105123
- const response = await fetch(apiUrl, {
105779
+ const response = await deps.fetch(apiUrl, {
105124
105780
  headers: { Accept: "application/vnd.github+json", "User-Agent": USER_AGENT }
105125
105781
  });
105126
105782
  if (response.ok) {
@@ -105128,30 +105784,15 @@ async function fetchRelease(version3) {
105128
105784
  }
105129
105785
  } catch {}
105130
105786
  const apiPath = version3 ? `repos/${OPENSCOUT_RELEASE_OWNER}/${OPENSCOUT_RELEASE_REPOSITORY}/releases/tags/${version3}` : `repos/${OPENSCOUT_RELEASE_OWNER}/${OPENSCOUT_RELEASE_REPOSITORY}/releases/latest`;
105131
- const gh = spawnSync8("gh", ["api", apiPath], { encoding: "utf8" });
105787
+ const gh = deps.run("gh", ["api", apiPath]);
105132
105788
  if ((gh.status ?? 1) === 0 && gh.stdout.trim()) {
105133
105789
  return JSON.parse(gh.stdout);
105134
105790
  }
105135
105791
  throw new ScoutCliError(version3 ? `release "${version3}" not found on GitHub (${OPENSCOUT_RELEASE_OWNER}/${OPENSCOUT_RELEASE_REPOSITORY})` : `could not fetch the latest OpenScout release from GitHub (${OPENSCOUT_RELEASE_OWNER}/${OPENSCOUT_RELEASE_REPOSITORY})`);
105136
105792
  }
105137
- function findAppDmgAsset(release) {
105138
- const assets = release.assets ?? [];
105139
- const isMenuOnly = (name2) => name2.toLowerCase().startsWith("openscoutmenu");
105140
- const isDmg = (name2) => name2.toLowerCase().endsWith(".dmg");
105141
- const versioned = assets.find((asset) => /^openscout-\d/i.test(asset.name) && isDmg(asset.name) && !isMenuOnly(asset.name));
105142
- if (versioned)
105143
- return versioned;
105144
- const latestAlias = assets.find((asset) => asset.name.toLowerCase() === "openscout.dmg");
105145
- if (latestAlias)
105146
- return latestAlias;
105147
- const anyProductDmg = assets.find((asset) => isDmg(asset.name) && !isMenuOnly(asset.name));
105148
- if (anyProductDmg)
105149
- return anyProductDmg;
105150
- throw new ScoutCliError(`no OpenScout.app DMG found in release ${release.tag_name}. Assets: ${assets.map((asset) => asset.name).join(", ") || "(none)"}`);
105151
- }
105152
- async function downloadDmg(asset, destination, context) {
105793
+ async function downloadDmg(asset, destination, context, deps) {
105153
105794
  context.stderr(`Downloading ${asset.name} (${formatBytes(asset.size)})\u2026`);
105154
- const response = await fetch(asset.browser_download_url, {
105795
+ const response = await deps.fetch(asset.browser_download_url, {
105155
105796
  redirect: "follow",
105156
105797
  headers: { "User-Agent": USER_AGENT }
105157
105798
  });
@@ -105159,61 +105800,266 @@ async function downloadDmg(asset, destination, context) {
105159
105800
  throw new ScoutCliError(`download failed: HTTP ${response.status} for ${asset.browser_download_url}`);
105160
105801
  }
105161
105802
  const buffer = Buffer.from(await response.arrayBuffer());
105162
- if (buffer.length === 0) {
105163
- throw new ScoutCliError("download failed: empty response body");
105803
+ verifyDownloadedAsset(buffer, asset);
105804
+ deps.writeFileSync(destination, buffer);
105805
+ }
105806
+ function mountDmg(dmgPath, mountPoint, deps) {
105807
+ deps.mkdirSync(mountPoint, { recursive: true });
105808
+ const result = deps.run("hdiutil", [
105809
+ "attach",
105810
+ dmgPath,
105811
+ "-mountpoint",
105812
+ mountPoint,
105813
+ "-nobrowse",
105814
+ "-readonly",
105815
+ "-noautoopen"
105816
+ ]);
105817
+ if ((result.status ?? 1) !== 0) {
105818
+ throw new ScoutCliError(`could not mount ${dmgPath}: ${result.stderr.trim() || result.stdout.trim() || "hdiutil attach failed"}`);
105164
105819
  }
105165
- writeFileSync9(destination, buffer);
105166
105820
  }
105167
- function mountDmg(dmgPath) {
105168
- const result = spawnSync8("hdiutil", ["attach", dmgPath, "-nobrowse", "-noverify", "-noautoopen", "-plist"], { encoding: "utf8" });
105169
- if ((result.status ?? 1) !== 0) {
105170
- throw new ScoutCliError(`could not mount ${dmgPath}: ${result.stderr.trim() || "hdiutil attach failed"}`);
105821
+ function unmountDmg(mountPoint, deps) {
105822
+ const detached = deps.run("hdiutil", ["detach", mountPoint, "-quiet"]);
105823
+ if ((detached.status ?? 1) === 0)
105824
+ return;
105825
+ deps.run("hdiutil", ["detach", mountPoint, "-force", "-quiet"]);
105826
+ }
105827
+ function requireMountedOpenScoutApp(mountPoint, deps) {
105828
+ const source = join48(mountPoint, OPENSCOUT_APP_NAME);
105829
+ if (!deps.existsSync(source) || !deps.existsSync(infoPlistPath(source))) {
105830
+ throw new ScoutCliError(`no ${OPENSCOUT_APP_NAME} found in the mounted DMG at ${mountPoint}`);
105171
105831
  }
105172
- const mountPointMatch = result.stdout.match(/<key>mount-point<\/key>\s*<string>([^<]+)<\/string>/);
105173
- if (mountPointMatch) {
105174
- return mountPointMatch[1];
105832
+ return source;
105833
+ }
105834
+ function codesignField(output, key) {
105835
+ const match = output.match(new RegExp(`^${key}=(.+)$`, "m"));
105836
+ return match ? match[1].trim() : null;
105837
+ }
105838
+ function verifyDownloadedDmg(dmgPath, deps = {}) {
105839
+ const resolved = resolveInstallDependencies(deps);
105840
+ requireSuccess(resolved.run("codesign", ["--verify", "--strict", dmgPath]), `codesign --verify --strict failed for ${dmgPath}`);
105841
+ requireSuccess(resolved.run("spctl", [
105842
+ "--assess",
105843
+ "--type",
105844
+ "open",
105845
+ "--context",
105846
+ "context:primary-signature",
105847
+ "-vv",
105848
+ dmgPath
105849
+ ]), `Gatekeeper rejected ${dmgPath}`);
105850
+ }
105851
+ function verifyStagedOpenScoutApp(bundlePath, deps = {}, expectedVersion) {
105852
+ const resolved = resolveInstallDependencies(deps);
105853
+ if (!resolved.existsSync(infoPlistPath(bundlePath))) {
105854
+ throw new ScoutCliError(`${bundlePath} is missing Contents/Info.plist`);
105855
+ }
105856
+ const bundleId = readPlistString(resolved, infoPlistPath(bundlePath), "CFBundleIdentifier");
105857
+ if (bundleId !== OPENSCOUT_APP_BUNDLE_ID) {
105858
+ throw new ScoutCliError(`${OPENSCOUT_APP_NAME} bundle id is ${bundleId ?? "(missing)"}; expected ${OPENSCOUT_APP_BUNDLE_ID}`);
105859
+ }
105860
+ const version3 = readPlistString(resolved, infoPlistPath(bundlePath), "CFBundleShortVersionString");
105861
+ if (!version3) {
105862
+ throw new ScoutCliError(`${OPENSCOUT_APP_NAME} is missing CFBundleShortVersionString`);
105863
+ }
105864
+ if (expectedVersion && version3 !== expectedVersion) {
105865
+ throw new ScoutCliError(`${OPENSCOUT_APP_NAME} version is ${version3}; expected release ${expectedVersion}`);
105866
+ }
105867
+ requireSuccess(resolved.run("codesign", ["--verify", "--deep", "--strict", bundlePath]), `codesign --verify --deep --strict failed for ${bundlePath}`);
105868
+ const details = requireSuccess(resolved.run("codesign", ["-dvv", bundlePath]), `could not read codesign details for ${bundlePath}`);
105869
+ const detailsOutput = combinedOutput(details);
105870
+ const identifier = codesignField(detailsOutput, "Identifier");
105871
+ if (identifier !== OPENSCOUT_APP_BUNDLE_ID) {
105872
+ throw new ScoutCliError(`${OPENSCOUT_APP_NAME} signature identifier is ${identifier ?? "(missing)"}; expected ${OPENSCOUT_APP_BUNDLE_ID}`);
105873
+ }
105874
+ const teamId = codesignField(detailsOutput, "TeamIdentifier");
105875
+ if (teamId !== OPENSCOUT_SIGNING_TEAM_ID) {
105876
+ throw new ScoutCliError(`${OPENSCOUT_APP_NAME} signing Team ID is ${teamId ?? "(missing)"}; expected ${OPENSCOUT_SIGNING_TEAM_ID}`);
105877
+ }
105878
+ if (!/^Authority=Developer ID Application:/m.test(detailsOutput)) {
105879
+ throw new ScoutCliError(`${OPENSCOUT_APP_NAME} is not signed with Developer ID Application`);
105880
+ }
105881
+ requireSuccess(resolved.run("spctl", ["--assess", "--type", "execute", "-vv", bundlePath]), `Gatekeeper rejected ${bundlePath}`);
105882
+ return version3;
105883
+ }
105884
+ function copyApp(source, destination, deps) {
105885
+ const copied = deps.run("ditto", [source, destination]);
105886
+ if ((copied.status ?? 1) !== 0) {
105887
+ if (isPermissionError(copied.error, copied)) {
105888
+ throw new ScoutCliError(permissionDeniedMessage(destination, copied.stderr));
105889
+ }
105890
+ throw new ScoutCliError(`could not copy the app to ${destination}: ${copied.stderr.trim() || copied.stdout.trim() || "ditto failed"}`);
105891
+ }
105892
+ }
105893
+ function moveReplacing(source, destination, deps) {
105894
+ try {
105895
+ deps.renameSync(source, destination);
105896
+ return;
105897
+ } catch (error48) {
105898
+ const code = error48?.code;
105899
+ if (code !== "EXDEV") {
105900
+ if (isPermissionError(error48)) {
105901
+ throw new ScoutCliError(permissionDeniedMessage(destination));
105902
+ }
105903
+ throw new ScoutCliError(`could not move ${source} to ${destination}: ${error48 instanceof Error ? error48.message : String(error48)}`);
105904
+ }
105175
105905
  }
105176
- throw new ScoutCliError("could not determine the DMG mount point");
105906
+ copyApp(source, destination, deps);
105907
+ deps.rmSync(source, { recursive: true, force: true });
105177
105908
  }
105178
- function unmountDmg(mountPoint) {
105179
- spawnSync8("hdiutil", ["detach", mountPoint, "-quiet"], { encoding: "utf8" });
105909
+ function backupPathFor(appPath) {
105910
+ return `${appPath}${BACKUP_SUFFIX}`;
105911
+ }
105912
+ function installLockPathFor(appPath) {
105913
+ return `${appPath}${INSTALL_LOCK_SUFFIX}`;
105914
+ }
105915
+ function acquireInstallLock(deps) {
105916
+ const lockPath = installLockPathFor(deps.appPath);
105917
+ const result = deps.run(SHLOCK_PATH, ["-f", lockPath, "-p", String(process.pid)]);
105918
+ if ((result.status ?? 1) !== 0) {
105919
+ if (isPermissionError(result.error, result)) {
105920
+ throw new ScoutCliError(permissionDeniedMessage(lockPath, result.stderr));
105921
+ }
105922
+ throw new ScoutCliError(`another scout install is already updating ${deps.appPath}. ` + `If no installer is running, remove the stale lock at ${lockPath} and retry.`);
105923
+ }
105924
+ let released = false;
105925
+ return () => {
105926
+ if (released)
105927
+ return;
105928
+ released = true;
105929
+ deps.rmSync(lockPath, { force: true });
105930
+ };
105180
105931
  }
105181
- function copyAppFromMount(mountPoint) {
105182
- const listing = spawnSync8("ls", [mountPoint], { encoding: "utf8" });
105183
- const appEntry = listing.stdout.split(`
105184
- `).map((line) => line.trim()).find((line) => line === APP_NAME) ?? listing.stdout.split(`
105185
- `).map((line) => line.trim()).find((line) => line.endsWith(".app") && !line.toLowerCase().startsWith("openscoutmenu"));
105186
- if (!appEntry) {
105187
- throw new ScoutCliError(`no ${APP_NAME} found in the mounted DMG at ${mountPoint}`);
105932
+ function recoverIncompleteInstall(deps) {
105933
+ const backupPath = backupPathFor(deps.appPath);
105934
+ const destExists = deps.existsSync(deps.appPath);
105935
+ const backupExists = deps.existsSync(backupPath);
105936
+ if (!destExists && backupExists) {
105937
+ verifyStagedOpenScoutApp(backupPath, deps);
105938
+ deps.renameSync(backupPath, deps.appPath);
105939
+ return;
105188
105940
  }
105189
- const source = join48(mountPoint, appEntry);
105190
- if (existsSync39(APP_PATH)) {
105191
- const removed = spawnSync8("rm", ["-rf", APP_PATH], { encoding: "utf8" });
105192
- if ((removed.status ?? 1) !== 0) {
105193
- throw new ScoutCliError(`could not replace ${APP_PATH} (permission denied?). Try: sudo scout install`);
105941
+ if (destExists && backupExists) {
105942
+ let destinationError = null;
105943
+ try {
105944
+ verifyStagedOpenScoutApp(deps.appPath, deps);
105945
+ } catch (error48) {
105946
+ destinationError = error48;
105947
+ }
105948
+ if (!destinationError) {
105949
+ deps.rmSync(backupPath, { recursive: true, force: true });
105950
+ return;
105194
105951
  }
105952
+ try {
105953
+ verifyStagedOpenScoutApp(backupPath, deps);
105954
+ } catch (backupError) {
105955
+ throw new ScoutCliError(`incomplete prior install found, but neither ${deps.appPath} nor ${backupPath} passed verification: ` + `${destinationError instanceof Error ? destinationError.message : String(destinationError)}; ` + `${backupError instanceof Error ? backupError.message : String(backupError)}`);
105956
+ }
105957
+ deps.rmSync(deps.appPath, { recursive: true, force: true });
105958
+ deps.renameSync(backupPath, deps.appPath);
105195
105959
  }
105196
- const copied = spawnSync8("cp", ["-R", source, APP_PATH], { encoding: "utf8" });
105197
- if ((copied.status ?? 1) !== 0) {
105198
- throw new ScoutCliError(`could not copy the app to ${APP_PATH}: ${copied.stderr.trim() || "permission denied?"}. Try: sudo scout install`);
105960
+ }
105961
+ function replaceAppTransactionally(stagedPath, deps, expectedVersion) {
105962
+ const backupPath = backupPathFor(deps.appPath);
105963
+ const hadPriorApp = deps.existsSync(deps.appPath);
105964
+ let backedUp = false;
105965
+ let installedVersion = "";
105966
+ try {
105967
+ if (hadPriorApp) {
105968
+ try {
105969
+ deps.renameSync(deps.appPath, backupPath);
105970
+ } catch (error48) {
105971
+ if (isPermissionError(error48)) {
105972
+ throw new ScoutCliError(permissionDeniedMessage(deps.appPath));
105973
+ }
105974
+ throw new ScoutCliError(`could not move the installed app aside: ${error48 instanceof Error ? error48.message : String(error48)}`);
105975
+ }
105976
+ backedUp = true;
105977
+ }
105978
+ moveReplacing(stagedPath, deps.appPath, deps);
105979
+ installedVersion = verifyStagedOpenScoutApp(deps.appPath, deps, expectedVersion);
105980
+ } catch (error48) {
105981
+ if (backedUp) {
105982
+ if (deps.existsSync(deps.appPath)) {
105983
+ deps.rmSync(deps.appPath, { recursive: true, force: true });
105984
+ }
105985
+ if (deps.existsSync(backupPath)) {
105986
+ try {
105987
+ deps.renameSync(backupPath, deps.appPath);
105988
+ } catch {
105989
+ throw new ScoutCliError(`install failed and rollback failed. The previous app is at ${backupPath}. ${error48 instanceof Error ? error48.message : String(error48)}`);
105990
+ }
105991
+ }
105992
+ } else if (!hadPriorApp && deps.existsSync(deps.appPath)) {
105993
+ deps.rmSync(deps.appPath, { recursive: true, force: true });
105994
+ }
105995
+ throw error48;
105996
+ }
105997
+ if (backedUp && deps.existsSync(backupPath)) {
105998
+ deps.rmSync(backupPath, { recursive: true, force: true });
105199
105999
  }
106000
+ if (!installedVersion) {
106001
+ throw new ScoutCliError(`installed ${OPENSCOUT_APP_NAME} has no verified version`);
106002
+ }
106003
+ return installedVersion;
105200
106004
  }
105201
- function removeQuarantine() {
105202
- spawnSync8("xattr", ["-rd", "com.apple.quarantine", APP_PATH], { encoding: "utf8" });
106005
+ function executableIsInsideApp(executable, appPath) {
106006
+ const normalizedApp = appPath.endsWith("/") ? appPath.slice(0, -1) : appPath;
106007
+ return executable === normalizedApp || executable.startsWith(`${normalizedApp}/`);
105203
106008
  }
105204
- function isAppRunning() {
105205
- return (spawnSync8("pgrep", ["-x", APP_PROCESS_NAME], { encoding: "utf8" }).status ?? 1) === 0;
106009
+ function processIdsForInstalledApp(psOutput, appPath) {
106010
+ const pids = [];
106011
+ for (const rawLine of psOutput.split(`
106012
+ `)) {
106013
+ const line = rawLine.trim();
106014
+ if (!line)
106015
+ continue;
106016
+ const match = line.match(/^(\d+)\s+(\S+)/);
106017
+ if (!match)
106018
+ continue;
106019
+ const pid = Number(match[1]);
106020
+ const executable = match[2];
106021
+ if (!Number.isInteger(pid) || pid <= 0)
106022
+ continue;
106023
+ if (executableIsInsideApp(executable, appPath))
106024
+ pids.push(pid);
106025
+ }
106026
+ return pids;
105206
106027
  }
105207
- function quitApp() {
105208
- spawnSync8("osascript", ["-e", `tell application id "${APP_BUNDLE_ID}" to quit`], {
105209
- encoding: "utf8"
105210
- });
106028
+ function listInstalledAppPids(deps) {
106029
+ const result = deps.run("ps", ["-axo", "pid=,args="]);
106030
+ requireSuccess(result, "could not inspect running OpenScout processes");
106031
+ return processIdsForInstalledApp(result.stdout, deps.appPath);
106032
+ }
106033
+ function isAppRunning(deps) {
106034
+ return listInstalledAppPids(deps).length > 0;
106035
+ }
106036
+ function waitUntilStopped2(deps, attempts) {
106037
+ for (let index2 = 0;index2 < attempts; index2 += 1) {
106038
+ if (!isAppRunning(deps))
106039
+ return true;
106040
+ if (index2 + 1 < attempts)
106041
+ deps.sleep(STOP_POLL_MS);
106042
+ }
106043
+ return !isAppRunning(deps);
105211
106044
  }
105212
- function launchApp() {
105213
- const byId = spawnSync8("open", ["-b", APP_BUNDLE_ID], { encoding: "utf8" });
105214
- if ((byId.status ?? 1) !== 0) {
105215
- spawnSync8("open", [APP_PATH], { encoding: "utf8" });
106045
+ function stopRunningApp(deps) {
106046
+ const initialPids = listInstalledAppPids(deps);
106047
+ if (initialPids.length === 0)
106048
+ return false;
106049
+ for (const pid of initialPids) {
106050
+ deps.run("kill", [String(pid)]);
105216
106051
  }
106052
+ if (waitUntilStopped2(deps, STOP_POLL_ATTEMPTS))
106053
+ return true;
106054
+ for (const pid of listInstalledAppPids(deps)) {
106055
+ deps.run("kill", ["-9", String(pid)]);
106056
+ }
106057
+ if (waitUntilStopped2(deps, STOP_POLL_ATTEMPTS))
106058
+ return true;
106059
+ throw new ScoutCliError("could not stop OpenScout before replacing it");
106060
+ }
106061
+ function launchApp(deps) {
106062
+ requireSuccess(deps.run("open", [deps.appPath]), `could not relaunch ${deps.appPath}`);
105217
106063
  }
105218
106064
  function renderInstallResult(result) {
105219
106065
  if (result.action === "check") {
@@ -105227,90 +106073,130 @@ function renderInstallResult(result) {
105227
106073
  }
105228
106074
  return result.message;
105229
106075
  }
105230
- async function runCheck(context, options) {
105231
- const installed = getInstalledVersion();
105232
- const release = await fetchRelease(options.version);
105233
- const target2 = stripLeadingV(release.tag_name);
106076
+ async function runCheck(context, options, deps) {
106077
+ const release = await fetchRelease(options.version, deps);
106078
+ const target2 = normalizeReleaseVersion(release.tag_name);
106079
+ let installed = getInstalledVersion(deps);
105234
106080
  let status;
105235
106081
  let message;
105236
- if (!installed) {
105237
- status = "not-installed";
105238
- message = "OpenScout is not installed \u2014 run `scout install`.";
105239
- } else if (installed === target2) {
105240
- status = "up-to-date";
105241
- message = `OpenScout ${installed} is up to date.`;
106082
+ if (!deps.existsSync(deps.appPath)) {
106083
+ if (deps.existsSync(backupPathFor(deps.appPath))) {
106084
+ status = "repair-needed";
106085
+ message = "An interrupted OpenScout install needs repair \u2014 run `scout install --force`.";
106086
+ } else {
106087
+ status = "not-installed";
106088
+ message = "OpenScout is not installed \u2014 run `scout install`.";
106089
+ }
105242
106090
  } else {
105243
- status = "update-available";
105244
- message = `Update available: ${installed} \u2192 ${target2}. Run \`scout install\`.`;
106091
+ try {
106092
+ installed = verifyStagedOpenScoutApp(deps.appPath, deps);
106093
+ if (installed === target2) {
106094
+ status = "up-to-date";
106095
+ message = `OpenScout ${installed} is up to date.`;
106096
+ } else {
106097
+ status = "update-available";
106098
+ message = `Update available: ${installed} \u2192 ${target2}. Run \`scout install\`.`;
106099
+ }
106100
+ } catch (error48) {
106101
+ status = "repair-needed";
106102
+ message = `OpenScout needs repair (${error48 instanceof Error ? error48.message : String(error48)}). ` + "Run `scout install --force`.";
106103
+ }
105245
106104
  }
105246
- context.output.writeValue({ action: "check", status, installed, target: target2, bundlePath: APP_PATH, message }, renderInstallResult);
106105
+ context.output.writeValue({ action: "check", status, installed, target: target2, bundlePath: deps.appPath, message }, renderInstallResult);
105247
106106
  }
105248
- async function runInstallCommand(context, args) {
106107
+ async function runInstallCommand(context, args, dependencies = {}) {
105249
106108
  if (HELP_FLAGS9.has(args[0] ?? "")) {
105250
106109
  context.output.writeText(renderInstallCommandHelp());
105251
106110
  return;
105252
106111
  }
105253
- if (process.platform !== "darwin") {
106112
+ const deps = resolveInstallDependencies(dependencies);
106113
+ if (deps.platform !== "darwin") {
105254
106114
  throw new ScoutCliError("scout install is only supported on macOS.");
105255
106115
  }
105256
106116
  const options = parseInstallArgs(args);
106117
+ if (options.version)
106118
+ normalizeReleaseVersion(options.version);
105257
106119
  if (options.check) {
105258
- await runCheck(context, options);
106120
+ await runCheck(context, options, deps);
105259
106121
  return;
105260
106122
  }
105261
- const installedBefore = getInstalledVersion();
105262
106123
  context.stderr(options.version ? `Fetching release ${options.version}\u2026` : "Fetching the latest OpenScout release\u2026");
105263
- const release = await fetchRelease(options.version);
105264
- const target2 = stripLeadingV(release.tag_name);
105265
- if (!options.force && installedBefore && installedBefore === target2) {
106124
+ const release = await fetchRelease(options.version, deps);
106125
+ const target2 = normalizeReleaseVersion(release.tag_name);
106126
+ const releaseInstallLock = acquireInstallLock(deps);
106127
+ try {
106128
+ recoverIncompleteInstall(deps);
106129
+ const hadInstalledApp = deps.existsSync(deps.appPath);
106130
+ const installedBefore = getInstalledVersion(deps);
106131
+ let repairingInstalledApp = false;
106132
+ if (!options.force && installedBefore === target2) {
106133
+ try {
106134
+ const verifiedVersion = verifyStagedOpenScoutApp(deps.appPath, deps, target2);
106135
+ context.output.writeValue({
106136
+ action: "install",
106137
+ status: "up-to-date",
106138
+ installed: verifiedVersion,
106139
+ target: target2,
106140
+ bundlePath: deps.appPath,
106141
+ message: `OpenScout ${target2} is already installed (use --force to reinstall).`
106142
+ }, renderInstallResult);
106143
+ return;
106144
+ } catch (error48) {
106145
+ repairingInstalledApp = true;
106146
+ context.stderr(`Installed OpenScout ${target2} failed verification; repairing it: ${error48 instanceof Error ? error48.message : String(error48)}`);
106147
+ }
106148
+ }
106149
+ const asset = findAppDmgAsset(release);
106150
+ const workDir = deps.mkdtempSync(join48(deps.tmpdir(), "scout-install-"));
106151
+ const dmgPath = join48(workDir, asset.name);
106152
+ const mountPoint = join48(workDir, "mnt");
106153
+ const stagedPath = join48(workDir, OPENSCOUT_APP_NAME);
106154
+ let mounted = false;
106155
+ let wasRunning = false;
106156
+ let installedAfter = "";
106157
+ try {
106158
+ await downloadDmg(asset, dmgPath, context, deps);
106159
+ context.stderr(`Installing OpenScout ${target2} to ${deps.appPath}\u2026`);
106160
+ verifyDownloadedDmg(dmgPath, deps);
106161
+ mountDmg(dmgPath, mountPoint, deps);
106162
+ mounted = true;
106163
+ const source = requireMountedOpenScoutApp(mountPoint, deps);
106164
+ copyApp(source, stagedPath, deps);
106165
+ verifyStagedOpenScoutApp(stagedPath, deps, target2);
106166
+ wasRunning = stopRunningApp(deps);
106167
+ installedAfter = replaceAppTransactionally(stagedPath, deps, target2);
106168
+ } finally {
106169
+ if (mounted)
106170
+ unmountDmg(mountPoint, deps);
106171
+ deps.rmSync(workDir, { recursive: true, force: true });
106172
+ }
106173
+ if (wasRunning && options.restart) {
106174
+ launchApp(deps);
106175
+ }
106176
+ const status = hadInstalledApp ? "updated" : "installed";
106177
+ const relaunchNote = wasRunning ? options.restart ? " (relaunched)" : " (restart OpenScout to use the new version)" : "";
106178
+ let verb = "Installed";
106179
+ if (repairingInstalledApp || hadInstalledApp && !installedBefore) {
106180
+ verb = "Repaired";
106181
+ } else if (installedBefore) {
106182
+ verb = `Updated ${installedBefore} \u2192`;
106183
+ }
105266
106184
  context.output.writeValue({
105267
106185
  action: "install",
105268
- status: "up-to-date",
105269
- installed: installedBefore,
106186
+ status,
106187
+ installed: installedAfter,
105270
106188
  target: target2,
105271
- bundlePath: APP_PATH,
105272
- message: `OpenScout ${target2} is already installed (use --force to reinstall).`
106189
+ bundlePath: deps.appPath,
106190
+ message: `${verb} OpenScout ${installedAfter} \u2192 ${deps.appPath}${relaunchNote}`
105273
106191
  }, renderInstallResult);
105274
- return;
105275
- }
105276
- const asset = findAppDmgAsset(release);
105277
- const wasRunning = isAppRunning();
105278
- const workDir = mkdtempSync(join48(tmpdir(), "scout-install-"));
105279
- const dmgPath = join48(workDir, asset.name);
105280
- let mountPoint = null;
105281
- try {
105282
- await downloadDmg(asset, dmgPath, context);
105283
- context.stderr(`Installing OpenScout ${target2} to ${APP_PATH}\u2026`);
105284
- mountPoint = mountDmg(dmgPath);
105285
- copyAppFromMount(mountPoint);
105286
106192
  } finally {
105287
- if (mountPoint)
105288
- unmountDmg(mountPoint);
105289
- rmSync5(workDir, { recursive: true, force: true });
105290
- }
105291
- removeQuarantine();
105292
- if (wasRunning && options.restart) {
105293
- quitApp();
105294
- launchApp();
105295
- }
105296
- const installedAfter = getInstalledVersion() ?? target2;
105297
- const status = installedBefore ? "updated" : "installed";
105298
- const relaunchNote = wasRunning ? options.restart ? " (relaunched)" : " (restart OpenScout to use the new version)" : "";
105299
- const verb = installedBefore ? `Updated ${installedBefore} \u2192` : "Installed";
105300
- context.output.writeValue({
105301
- action: "install",
105302
- status,
105303
- installed: installedAfter,
105304
- target: target2,
105305
- bundlePath: APP_PATH,
105306
- message: `${verb} OpenScout ${installedAfter} \u2192 ${APP_PATH}${relaunchNote}`
105307
- }, renderInstallResult);
106193
+ releaseInstallLock();
106194
+ }
105308
106195
  }
105309
- var OPENSCOUT_RELEASE_OWNER = "oscout", OPENSCOUT_RELEASE_REPOSITORY = "scout", APP_NAME = "OpenScout.app", APP_PATH, INFO_PLIST_PATH, APP_BUNDLE_ID = "app.openscout.scout", APP_PROCESS_NAME = "Scout", USER_AGENT = "scout-cli", HELP_FLAGS9;
106196
+ var OPENSCOUT_RELEASE_OWNER = "oscout", OPENSCOUT_RELEASE_REPOSITORY = "scout", OPENSCOUT_APP_NAME = "OpenScout.app", OPENSCOUT_APP_BUNDLE_ID = "app.openscout.scout", OPENSCOUT_SIGNING_TEAM_ID = "2U83JFPW66", DEFAULT_OPENSCOUT_APP_PATH, GITHUB_ASSET_DIGEST_ALGORITHM = "sha256", GITHUB_ASSET_DIGEST_HEX_LENGTH = 64, LATEST_DMG_ALIAS = "OpenScout.dmg", USER_AGENT = "scout-cli", BACKUP_SUFFIX = ".openscout-previous", INSTALL_LOCK_SUFFIX = ".openscout-install.lock", SHLOCK_PATH = "/usr/bin/shlock", STOP_POLL_ATTEMPTS = 50, STOP_POLL_MS = 100, HELP_FLAGS9;
105310
106197
  var init_install = __esm(() => {
105311
106198
  init_errors();
105312
- APP_PATH = `/Applications/${APP_NAME}`;
105313
- INFO_PLIST_PATH = `${APP_PATH}/Contents/Info.plist`;
106199
+ DEFAULT_OPENSCOUT_APP_PATH = `/Applications/${OPENSCOUT_APP_NAME}`;
105314
106200
  HELP_FLAGS9 = new Set(["help", "--help", "-h"]);
105315
106201
  });
105316
106202
 
@@ -110025,12 +110911,12 @@ function normalizedStringOrNull(value) {
110025
110911
  const trimmed = value?.trim();
110026
110912
  return trimmed ? trimmed : null;
110027
110913
  }
110028
- function metadataStringValue3(metadata, key) {
110914
+ function metadataStringValue4(metadata, key) {
110029
110915
  const value = metadata?.[key];
110030
110916
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
110031
110917
  }
110032
110918
  function isBuiltInDirectoryAgent(agent) {
110033
- const definitionId = agent.definitionId || metadataStringValue3(agent.metadata, "definitionId") || agent.id;
110919
+ const definitionId = agent.definitionId || metadataStringValue4(agent.metadata, "definitionId") || agent.id;
110034
110920
  return BUILT_IN_AGENT_DEFINITION_IDS.has(definitionId);
110035
110921
  }
110036
110922
  function rankState(state) {
@@ -113316,7 +114202,7 @@ var init_scout_mcp = __esm(() => {
113316
114202
 
113317
114203
  // ../../apps/desktop/src/cli/commands/mcp-install.ts
113318
114204
  import { spawnSync as spawnSync9 } from "child_process";
113319
- import { accessSync as accessSync4, constants as constants4, existsSync as existsSync40 } from "fs";
114205
+ import { accessSync as accessSync4, constants as constants4, existsSync as existsSync39 } from "fs";
113320
114206
  import { homedir as homedir31 } from "os";
113321
114207
  import { delimiter as delimiter4, join as join49, resolve as resolve29 } from "path";
113322
114208
  function isExecutable3(filePath) {
@@ -113357,7 +114243,7 @@ function resolveHostExecutable(host, env) {
113357
114243
  }
113358
114244
  function resolveCurrentScoutMcpLaunchCommand(env) {
113359
114245
  const currentScript = process.argv[1];
113360
- if (currentScript && existsSync40(currentScript) && isExecutable3(process.execPath)) {
114246
+ if (currentScript && existsSync39(currentScript) && isExecutable3(process.execPath)) {
113361
114247
  return {
113362
114248
  command: process.execPath,
113363
114249
  args: [resolve29(currentScript), "mcp"]
@@ -113730,7 +114616,7 @@ __export(exports_menu, {
113730
114616
  parseMenuCommand: () => parseMenuCommand
113731
114617
  });
113732
114618
  import { spawnSync as spawnSync10 } from "child_process";
113733
- import { existsSync as existsSync41 } from "fs";
114619
+ import { existsSync as existsSync40 } from "fs";
113734
114620
  import { homedir as homedir32 } from "os";
113735
114621
  import { dirname as dirname28, join as join50, resolve as resolve30 } from "path";
113736
114622
  import { fileURLToPath as fileURLToPath11 } from "url";
@@ -113820,7 +114706,7 @@ function findRepoMenuHelper(startDirectory) {
113820
114706
  let current = resolve30(startDirectory);
113821
114707
  while (true) {
113822
114708
  const candidate = join50(current, "apps", "macos", "bin", "openscout-menu.ts");
113823
- if (existsSync41(candidate)) {
114709
+ if (existsSync40(candidate)) {
113824
114710
  return candidate;
113825
114711
  }
113826
114712
  const parent = dirname28(current);
@@ -113830,7 +114716,7 @@ function findRepoMenuHelper(startDirectory) {
113830
114716
  current = parent;
113831
114717
  }
113832
114718
  const sourceRelativeCandidate = fileURLToPath11(new URL("../../../../macos/bin/openscout-menu.ts", import.meta.url).toString());
113833
- return existsSync41(sourceRelativeCandidate) ? sourceRelativeCandidate : null;
114719
+ return existsSync40(sourceRelativeCandidate) ? sourceRelativeCandidate : null;
113834
114720
  }
113835
114721
  function resolveRepoBundlePath(helperPath) {
113836
114722
  return resolve30(dirname28(helperPath), "..", "dist", "Scout.app", EMBEDDED_MENU_RELATIVE_PATH);
@@ -113862,14 +114748,14 @@ async function stopRunningMenu(helperBundlePath) {
113862
114748
  return survivors.length === 0;
113863
114749
  }
113864
114750
  function resolveInstalledAppBundlePath(env) {
113865
- const spotlight = runProcess("mdfind", [`kMDItemCFBundleIdentifier == '${APP_BUNDLE_ID2}'`], { env, allowFailure: true });
114751
+ const spotlight = runProcess("mdfind", [`kMDItemCFBundleIdentifier == '${APP_BUNDLE_ID}'`], { env, allowFailure: true });
113866
114752
  const indexedPath = spotlight.stdout.split(`
113867
114753
  `).map((line) => line.trim()).find(Boolean);
113868
114754
  if (indexedPath) {
113869
114755
  return indexedPath;
113870
114756
  }
113871
114757
  for (const candidate of COMMON_APP_BUNDLE_PATHS) {
113872
- if (existsSync41(candidate)) {
114758
+ if (existsSync40(candidate)) {
113873
114759
  return candidate;
113874
114760
  }
113875
114761
  }
@@ -113957,7 +114843,7 @@ async function runWithRepoHelper(context, helperPath, command) {
113957
114843
  });
113958
114844
  }
113959
114845
  const running = command.action === "quit" ? false : isMenuRunning(bundlePath);
113960
- const installed = existsSync41(bundlePath) || running;
114846
+ const installed = existsSync40(bundlePath) || running;
113961
114847
  return {
113962
114848
  action: command.action,
113963
114849
  mode: "repo-helper",
@@ -114023,7 +114909,7 @@ async function runMenuCommand(context, args) {
114023
114909
  const result = helperPath ? await runWithRepoHelper(context, helperPath, command) : await runWithInstalledApp(context, command);
114024
114910
  context.output.writeValue(result, renderMenuResult);
114025
114911
  }
114026
- var MENU_BUNDLE_ID = "app.openscout.scout.menu", MENU_PROCESS_NAME = "ScoutMenu", APP_BUNDLE_ID2 = "app.openscout.scout", APP_BUNDLE_NAME = "OpenScout.app", EMBEDDED_MENU_RELATIVE_PATH, HELP_FLAGS14, COMMON_APP_BUNDLE_PATHS;
114912
+ var MENU_BUNDLE_ID = "app.openscout.scout.menu", MENU_PROCESS_NAME = "ScoutMenu", APP_BUNDLE_ID = "app.openscout.scout", APP_BUNDLE_NAME = "OpenScout.app", EMBEDDED_MENU_RELATIVE_PATH, HELP_FLAGS14, COMMON_APP_BUNDLE_PATHS;
114027
114913
  var init_menu = __esm(() => {
114028
114914
  init_src3();
114029
114915
  init_app_lifecycle();
@@ -114840,7 +115726,7 @@ function renderMeshNodes(input) {
114840
115726
  var init_mesh = () => {};
114841
115727
 
114842
115728
  // ../../apps/desktop/src/core/mesh/enroll-pending.ts
114843
- import { existsSync as existsSync42, mkdirSync as mkdirSync12, readFileSync as readFileSync19, rmSync as rmSync6, writeFileSync as writeFileSync10 } from "fs";
115729
+ import { existsSync as existsSync41, mkdirSync as mkdirSync12, readFileSync as readFileSync19, rmSync as rmSync5, writeFileSync as writeFileSync9 } from "fs";
114844
115730
  import { dirname as dirname29, join as join51 } from "path";
114845
115731
  function pendingMeshEnrollmentPath(supportDirectory) {
114846
115732
  const dir = supportDirectory ?? resolveOpenScoutSupportPaths().supportDirectory;
@@ -114852,12 +115738,12 @@ function savePendingMeshEnrollment(handshake, supportDirectory) {
114852
115738
  }
114853
115739
  const path = pendingMeshEnrollmentPath(supportDirectory);
114854
115740
  mkdirSync12(dirname29(path), { recursive: true });
114855
- writeFileSync10(path, `${JSON.stringify(handshake, null, 2)}
115741
+ writeFileSync9(path, `${JSON.stringify(handshake, null, 2)}
114856
115742
  `, { encoding: "utf8", mode: 384 });
114857
115743
  }
114858
115744
  function loadPendingMeshEnrollment(supportDirectory) {
114859
115745
  const path = pendingMeshEnrollmentPath(supportDirectory);
114860
- if (!existsSync42(path)) {
115746
+ if (!existsSync41(path)) {
114861
115747
  return null;
114862
115748
  }
114863
115749
  let parsed;
@@ -114873,8 +115759,8 @@ function loadPendingMeshEnrollment(supportDirectory) {
114873
115759
  }
114874
115760
  function clearPendingMeshEnrollment(supportDirectory) {
114875
115761
  const path = pendingMeshEnrollmentPath(supportDirectory);
114876
- if (existsSync42(path)) {
114877
- rmSync6(path);
115762
+ if (existsSync41(path)) {
115763
+ rmSync5(path);
114878
115764
  }
114879
115765
  }
114880
115766
  var PENDING_FILE = "mesh-enroll-pending.json";
@@ -115637,7 +116523,7 @@ var exports_mesh_bridge = {};
115637
116523
  __export(exports_mesh_bridge, {
115638
116524
  runMeshBridgeCommand: () => runMeshBridgeCommand
115639
116525
  });
115640
- import { existsSync as existsSync43, mkdirSync as mkdirSync13, readFileSync as readFileSync21, unlinkSync, writeFileSync as writeFileSync11, chmodSync as chmodSync2 } from "fs";
116526
+ import { existsSync as existsSync42, mkdirSync as mkdirSync13, readFileSync as readFileSync21, unlinkSync, writeFileSync as writeFileSync10, chmodSync as chmodSync2 } from "fs";
115641
116527
  import { homedir as homedir33 } from "os";
115642
116528
  import { join as join52 } from "path";
115643
116529
  function supportDirectory() {
@@ -115656,7 +116542,7 @@ function readFlag(args, name2) {
115656
116542
  return args[index2 + 1]?.trim() || undefined;
115657
116543
  }
115658
116544
  function loadConfigFile(path) {
115659
- if (!existsSync43(path))
116545
+ if (!existsSync42(path))
115660
116546
  return null;
115661
116547
  return JSON.parse(readFileSync21(path, "utf8"));
115662
116548
  }
@@ -115744,7 +116630,7 @@ async function installBridge(context, args) {
115744
116630
  return;
115745
116631
  }
115746
116632
  mkdirSync13(supportDirectory(), { recursive: true });
115747
- writeFileSync11(configPath, `${JSON.stringify(config2, null, 2)}
116633
+ writeFileSync10(configPath, `${JSON.stringify(config2, null, 2)}
115748
116634
  `);
115749
116635
  chmodSync2(configPath, 384);
115750
116636
  const logDirectory = join52(supportDirectory(), "logs");
@@ -115772,7 +116658,7 @@ async function installBridge(context, args) {
115772
116658
  </dict>
115773
116659
  </plist>
115774
116660
  `;
115775
- writeFileSync11(launchAgentPlistPath2(), plist);
116661
+ writeFileSync10(launchAgentPlistPath2(), plist);
115776
116662
  const domain2 = `gui/${process.getuid?.() ?? 501}`;
115777
116663
  launchctl(context, ["bootout", `${domain2}/${LAUNCH_AGENT_LABEL}`]);
115778
116664
  const bootstrap = launchctl(context, ["bootstrap", domain2, launchAgentPlistPath2()]);
@@ -115789,7 +116675,7 @@ async function installBridge(context, args) {
115789
116675
  async function uninstallBridge(context) {
115790
116676
  const domain2 = `gui/${process.getuid?.() ?? 501}`;
115791
116677
  launchctl(context, ["bootout", `${domain2}/${LAUNCH_AGENT_LABEL}`]);
115792
- if (existsSync43(launchAgentPlistPath2())) {
116678
+ if (existsSync42(launchAgentPlistPath2())) {
115793
116679
  unlinkSync(launchAgentPlistPath2());
115794
116680
  }
115795
116681
  context.stdout(`Removed ${LAUNCH_AGENT_LABEL} (config file kept).`);
@@ -115993,7 +116879,7 @@ var init_mesh2 = __esm(() => {
115993
116879
  });
115994
116880
 
115995
116881
  // ../runtime/src/agent-workspace.ts
115996
- import { existsSync as existsSync44 } from "fs";
116882
+ import { existsSync as existsSync43 } from "fs";
115997
116883
  import { mkdir as mkdir13 } from "fs/promises";
115998
116884
  import { join as join53 } from "path";
115999
116885
  async function isGitRepo(projectRoot) {
@@ -116017,7 +116903,7 @@ async function createAgentWorkspace(projectRoot, agentName, requestedBranch) {
116017
116903
  validateWorktreeBranch(branch);
116018
116904
  const workspaceDir = join53(projectRoot, SCOUT_WORKSPACES_DIRNAME);
116019
116905
  const workspacePath = join53(workspaceDir, agentName);
116020
- if (existsSync44(workspacePath)) {
116906
+ if (existsSync43(workspacePath)) {
116021
116907
  return { path: workspacePath, branch };
116022
116908
  }
116023
116909
  await mkdir13(workspaceDir, { recursive: true });
@@ -117734,12 +118620,12 @@ var init_pairing_supervisor = () => {};
117734
118620
 
117735
118621
  // ../../apps/desktop/src/app/host/pairing.ts
117736
118622
  import {
117737
- existsSync as existsSync45,
118623
+ existsSync as existsSync44,
117738
118624
  mkdirSync as mkdirSync14,
117739
118625
  readFileSync as readFileSync22,
117740
118626
  statSync as statSync12,
117741
118627
  unlinkSync as unlinkSync2,
117742
- writeFileSync as writeFileSync12
118628
+ writeFileSync as writeFileSync11
117743
118629
  } from "fs";
117744
118630
  import { homedir as homedir35 } from "os";
117745
118631
  import { join as join55 } from "path";
@@ -117886,7 +118772,7 @@ async function withScoutPairingBridgeClient(port, run2) {
117886
118772
  }
117887
118773
  function loadScoutPairingConfig() {
117888
118774
  const { configPath } = resolveScoutPairingPaths();
117889
- if (!existsSync45(configPath)) {
118775
+ if (!existsSync44(configPath)) {
117890
118776
  return {};
117891
118777
  }
117892
118778
  try {
@@ -117922,7 +118808,7 @@ function resolveScoutPairingConfig() {
117922
118808
  }
117923
118809
  function readScoutPairingRuntimeSnapshot() {
117924
118810
  const { runtimeStatePath } = resolveScoutPairingPaths();
117925
- if (!existsSync45(runtimeStatePath)) {
118811
+ if (!existsSync44(runtimeStatePath)) {
117926
118812
  return null;
117927
118813
  }
117928
118814
  try {
@@ -117934,7 +118820,7 @@ function readScoutPairingRuntimeSnapshot() {
117934
118820
  }
117935
118821
  function readScoutPairingRuntimePid() {
117936
118822
  const { runtimePidPath } = resolveScoutPairingPaths();
117937
- if (!existsSync45(runtimePidPath)) {
118823
+ if (!existsSync44(runtimePidPath)) {
117938
118824
  return null;
117939
118825
  }
117940
118826
  try {
@@ -117986,7 +118872,7 @@ var init_pairing = __esm(() => {
117986
118872
 
117987
118873
  // ../../apps/desktop/src/app/host/agent-session.ts
117988
118874
  import { execFileSync as execFileSync6 } from "child_process";
117989
- import { existsSync as existsSync46 } from "fs";
118875
+ import { existsSync as existsSync45 } from "fs";
117990
118876
  import { open as open2 } from "fs/promises";
117991
118877
  import path from "path";
117992
118878
  function compactHomePath2(value) {
@@ -118127,7 +119013,7 @@ async function readAgentSessionLogs(agentId, tailLines) {
118127
119013
  let foundAny = false;
118128
119014
  let targetPath = null;
118129
119015
  for (const filePath of sources) {
118130
- if (!existsSync46(filePath)) {
119016
+ if (!existsSync45(filePath)) {
118131
119017
  continue;
118132
119018
  }
118133
119019
  foundAny = true;
@@ -121783,7 +122669,7 @@ var init_monitor2 = __esm(() => {
121783
122669
  });
121784
122670
 
121785
122671
  // ../../apps/desktop/src/core/pairing/runtime/config.ts
121786
- import { existsSync as existsSync47, mkdirSync as mkdirSync15, readFileSync as readFileSync23, writeFileSync as writeFileSync13 } from "fs";
122672
+ import { existsSync as existsSync46, mkdirSync as mkdirSync15, readFileSync as readFileSync23, writeFileSync as writeFileSync12 } from "fs";
121787
122673
  import { homedir as homedir36 } from "os";
121788
122674
  import path2 from "path";
121789
122675
  function pairingPaths() {
@@ -121800,7 +122686,7 @@ function pairingPaths() {
121800
122686
  }
121801
122687
  function loadPairingConfig() {
121802
122688
  const { configPath } = pairingPaths();
121803
- if (!existsSync47(configPath)) {
122689
+ if (!existsSync46(configPath)) {
121804
122690
  return {};
121805
122691
  }
121806
122692
  try {
@@ -123904,11 +124790,11 @@ var init_noise = __esm(() => {
123904
124790
  });
123905
124791
 
123906
124792
  // ../../apps/desktop/src/core/pairing/runtime/security/identity.ts
123907
- import { existsSync as existsSync48, mkdirSync as mkdirSync16, readFileSync as readFileSync24, writeFileSync as writeFileSync14 } from "fs";
124793
+ import { existsSync as existsSync47, mkdirSync as mkdirSync16, readFileSync as readFileSync24, writeFileSync as writeFileSync13 } from "fs";
123908
124794
  import { join as join56 } from "path";
123909
124795
  import { homedir as homedir37 } from "os";
123910
124796
  function loadOrCreateIdentity() {
123911
- if (existsSync48(IDENTITY_FILE)) {
124797
+ if (existsSync47(IDENTITY_FILE)) {
123912
124798
  return loadIdentity();
123913
124799
  }
123914
124800
  return createAndSaveIdentity();
@@ -123928,11 +124814,11 @@ function createAndSaveIdentity() {
123928
124814
  privateKey: bytesToHex2(keyPair.privateKey),
123929
124815
  createdAt: new Date().toISOString()
123930
124816
  };
123931
- writeFileSync14(IDENTITY_FILE, JSON.stringify(data, null, 2), { mode: 384 });
124817
+ writeFileSync13(IDENTITY_FILE, JSON.stringify(data, null, 2), { mode: 384 });
123932
124818
  return keyPair;
123933
124819
  }
123934
124820
  function loadTrustedPeers() {
123935
- if (!existsSync48(TRUSTED_PEERS_FILE))
124821
+ if (!existsSync47(TRUSTED_PEERS_FILE))
123936
124822
  return new Map;
123937
124823
  const data = JSON.parse(readFileSync24(TRUSTED_PEERS_FILE, "utf8"));
123938
124824
  return new Map(data.map((p) => [p.publicKey, p]));
@@ -123941,7 +124827,7 @@ function saveTrustedPeer(peer) {
123941
124827
  const peers = loadTrustedPeers();
123942
124828
  peers.set(peer.publicKey, peer);
123943
124829
  mkdirSync16(PAIRING_DIR, { recursive: true });
123944
- writeFileSync14(TRUSTED_PEERS_FILE, JSON.stringify([...peers.values()], null, 2), { mode: 384 });
124830
+ writeFileSync13(TRUSTED_PEERS_FILE, JSON.stringify([...peers.values()], null, 2), { mode: 384 });
123945
124831
  }
123946
124832
  function isTrustedPeer(publicKeyHex) {
123947
124833
  return loadTrustedPeers().has(publicKeyHex);
@@ -124146,10 +125032,10 @@ var init_security2 = __esm(() => {
124146
125032
  });
124147
125033
 
124148
125034
  // ../../apps/desktop/src/core/pairing/runtime/runtime-state.ts
124149
- import { existsSync as existsSync49, mkdirSync as mkdirSync17, readFileSync as readFileSync25, renameSync as renameSync5, unlinkSync as unlinkSync3, writeFileSync as writeFileSync15 } from "fs";
125035
+ import { existsSync as existsSync48, mkdirSync as mkdirSync17, readFileSync as readFileSync25, renameSync as renameSync5, unlinkSync as unlinkSync3, writeFileSync as writeFileSync14 } from "fs";
124150
125036
  function readPairingRuntimeSnapshot() {
124151
125037
  const { runtimeStatePath } = pairingPaths();
124152
- if (!existsSync49(runtimeStatePath)) {
125038
+ if (!existsSync48(runtimeStatePath)) {
124153
125039
  return null;
124154
125040
  }
124155
125041
  try {
@@ -124271,11 +125157,11 @@ var init_bridge = __esm(() => {
124271
125157
  });
124272
125158
 
124273
125159
  // ../../apps/desktop/src/core/pairing/runtime/bridge/config.ts
124274
- import { existsSync as existsSync50, readFileSync as readFileSync26 } from "fs";
125160
+ import { existsSync as existsSync49, readFileSync as readFileSync26 } from "fs";
124275
125161
  import { join as join58 } from "path";
124276
125162
  import { homedir as homedir39 } from "os";
124277
125163
  function loadConfigFile2() {
124278
- if (!existsSync50(CONFIG_FILE)) {
125164
+ if (!existsSync49(CONFIG_FILE)) {
124279
125165
  return {};
124280
125166
  }
124281
125167
  try {
@@ -124607,7 +125493,7 @@ var init_artifact_presentation = __esm(() => {
124607
125493
 
124608
125494
  // ../../apps/desktop/src/core/pairing/runtime/bridge/fileserver.ts
124609
125495
  import { randomUUID as randomUUID6 } from "crypto";
124610
- import { existsSync as existsSync51, mkdirSync as mkdirSync19, readFileSync as readFileSync27, realpathSync as realpathSync4, statSync as statSync14, unlinkSync as unlinkSync4, writeFileSync as writeFileSync16 } from "fs";
125496
+ import { existsSync as existsSync50, mkdirSync as mkdirSync19, readFileSync as readFileSync27, realpathSync as realpathSync4, statSync as statSync14, unlinkSync as unlinkSync4, writeFileSync as writeFileSync15 } from "fs";
124611
125497
  import { BlockList, isIP } from "net";
124612
125498
  import { isAbsolute as isAbsolute6, join as join59, relative as relative6, sep as sep4 } from "path";
124613
125499
  import { homedir as homedir40 } from "os";
@@ -124630,7 +125516,7 @@ function storePairingAttachmentBlob(input, options) {
124630
125516
  purgeExpiredPairingAttachments(options.now);
124631
125517
  const id = `att-${randomUUID6()}`;
124632
125518
  const path3 = join59(PAIRING_ATTACHMENT_ROOT, id);
124633
- writeFileSync16(path3, data, { mode: 384 });
125519
+ writeFileSync15(path3, data, { mode: 384 });
124634
125520
  const now = options.now ?? Date.now();
124635
125521
  const entry = {
124636
125522
  id,
@@ -124678,14 +125564,14 @@ function resolvePairingAttachment(id, now) {
124678
125564
  }
124679
125565
  const known = attachmentBlobs.get(id);
124680
125566
  if (known) {
124681
- if (known.expiresAt <= now || !existsSync51(known.path)) {
125567
+ if (known.expiresAt <= now || !existsSync50(known.path)) {
124682
125568
  forgetPairingAttachment(id);
124683
125569
  return null;
124684
125570
  }
124685
125571
  return known;
124686
125572
  }
124687
125573
  const rehydrated = readAttachmentSidecar(id);
124688
- if (!rehydrated || rehydrated.expiresAt <= now || !existsSync51(rehydrated.path)) {
125574
+ if (!rehydrated || rehydrated.expiresAt <= now || !existsSync50(rehydrated.path)) {
124689
125575
  return null;
124690
125576
  }
124691
125577
  attachmentBlobs.set(id, rehydrated);
@@ -124696,7 +125582,7 @@ function attachmentSidecarPath(id) {
124696
125582
  }
124697
125583
  function writeAttachmentSidecar(entry) {
124698
125584
  try {
124699
- writeFileSync16(attachmentSidecarPath(entry.id), JSON.stringify({
125585
+ writeFileSync15(attachmentSidecarPath(entry.id), JSON.stringify({
124700
125586
  id: entry.id,
124701
125587
  mediaType: entry.mediaType,
124702
125588
  fileName: entry.fileName,
@@ -125444,7 +126330,7 @@ var init_fileserver = __esm(() => {
125444
126330
  });
125445
126331
 
125446
126332
  // ../../apps/desktop/src/core/pairing/runtime/bridge/ssh-terminal-access.ts
125447
- import { createHash as createHash11 } from "crypto";
126333
+ import { createHash as createHash13 } from "crypto";
125448
126334
  function validateIosGeneratedSshPublicKey(publicKey) {
125449
126335
  const fields = publicKey.trim().split(/\s+/);
125450
126336
  if (fields.length < 2) {
@@ -125605,10 +126491,10 @@ function readSshWireString(buffer, offset) {
125605
126491
  };
125606
126492
  }
125607
126493
  function fingerprintKeyData(keyData) {
125608
- return `SHA256:${createHash11("sha256").update(Buffer.from(keyData, "base64")).digest("base64").replace(/=+$/, "")}`;
126494
+ return `SHA256:${createHash13("sha256").update(Buffer.from(keyData, "base64")).digest("base64").replace(/=+$/, "")}`;
125609
126495
  }
125610
126496
  function fingerprintUtf8(value) {
125611
- return `SHA256:${createHash11("sha256").update(value, "utf8").digest("base64").replace(/=+$/, "")}`;
126497
+ return `SHA256:${createHash13("sha256").update(value, "utf8").digest("base64").replace(/=+$/, "")}`;
125612
126498
  }
125613
126499
  function encodeMarkerValue(value) {
125614
126500
  return Buffer.from(value, "utf8").toString("base64url");
@@ -125631,10 +126517,10 @@ var init_ssh_terminal_access = __esm(() => {
125631
126517
  });
125632
126518
 
125633
126519
  // ../../apps/desktop/src/core/pairing/runtime/bridge/mobile-terminal-session.ts
125634
- import { createHash as createHash12 } from "crypto";
126520
+ import { createHash as createHash14 } from "crypto";
125635
126521
  function mobileTerminalSessionName(sshPublicKey, deviceClass) {
125636
126522
  const normalizedClass = normalizeMobileTerminalDeviceClass(deviceClass);
125637
- const signature = createHash12("sha256").update(sshPublicKey.trim()).digest("hex").slice(0, 8);
126523
+ const signature = createHash14("sha256").update(sshPublicKey.trim()).digest("hex").slice(0, 8);
125638
126524
  return `scout-${normalizedClass}-${signature}`;
125639
126525
  }
125640
126526
  function provisionedMobileTerminalSessionName(sshPublicKey, deviceClass) {
@@ -125670,23 +126556,23 @@ var init_mobile_terminal_session = __esm(() => {
125670
126556
  });
125671
126557
 
125672
126558
  // ../../apps/desktop/src/core/pairing/runtime/bridge/mobile-terminal-provision.ts
125673
- import { createHash as createHash13 } from "crypto";
126559
+ import { createHash as createHash15 } from "crypto";
125674
126560
  import {
125675
126561
  chmodSync as chmodSync3,
125676
126562
  closeSync,
125677
- existsSync as existsSync52,
126563
+ existsSync as existsSync51,
125678
126564
  mkdirSync as mkdirSync20,
125679
126565
  openSync,
125680
126566
  readFileSync as readFileSync28,
125681
126567
  renameSync as renameSync6,
125682
126568
  unlinkSync as unlinkSync5,
125683
- writeFileSync as writeFileSync17
126569
+ writeFileSync as writeFileSync16
125684
126570
  } from "fs";
125685
126571
  import { homedir as homedir41, hostname as hostname5, userInfo as userInfo2 } from "os";
125686
126572
  import { join as join60 } from "path";
125687
126573
  async function readMobileTerminalStatus(requestedSessionName, deviceId) {
125688
126574
  const authorizedKeysPath = join60(homedir41(), ".ssh", "authorized_keys");
125689
- const authorizedKeys = existsSync52(authorizedKeysPath) ? readFileSync28(authorizedKeysPath, "utf8") : "";
126575
+ const authorizedKeys = existsSync51(authorizedKeysPath) ? readFileSync28(authorizedKeysPath, "utf8") : "";
125690
126576
  const provisionedSessionName = findSshTerminalSessionForDevice(authorizedKeys, deviceId);
125691
126577
  const sessionName = authorizedMobileTerminalSessionName(requestedSessionName, provisionedSessionName);
125692
126578
  const base = {
@@ -125762,13 +126648,13 @@ async function provisionMobileTerminalAccess(sshPublicKey, deviceId, deviceClass
125762
126648
  const authorizedKeysPath = join60(sshDir, "authorized_keys");
125763
126649
  const hostKeyFingerprint = readRequiredHostKeyFingerprint();
125764
126650
  const result = withAuthorizedKeysLock(sshDir, () => {
125765
- if (!existsSync52(sshDir)) {
126651
+ if (!existsSync51(sshDir)) {
125766
126652
  mkdirSync20(sshDir, { recursive: true, mode: 448 });
125767
126653
  }
125768
126654
  try {
125769
126655
  chmodSync3(sshDir, 448);
125770
126656
  } catch {}
125771
- const existing = existsSync52(authorizedKeysPath) ? readFileSync28(authorizedKeysPath, "utf8") : "";
126657
+ const existing = existsSync51(authorizedKeysPath) ? readFileSync28(authorizedKeysPath, "utf8") : "";
125772
126658
  const result2 = provisionSshTerminalAccess({
125773
126659
  authorizedKeys: existing,
125774
126660
  deviceId: id,
@@ -125820,7 +126706,7 @@ function readRequiredHostKeyFingerprint() {
125820
126706
  const keyData = pub.trim().split(/\s+/)[1];
125821
126707
  if (!keyData)
125822
126708
  throw new Error("missing key data");
125823
- const digest = createHash13("sha256").update(Buffer.from(keyData, "base64")).digest("base64").replace(/=+$/, "");
126709
+ const digest = createHash15("sha256").update(Buffer.from(keyData, "base64")).digest("base64").replace(/=+$/, "");
125824
126710
  return `SHA256:${digest}`;
125825
126711
  } catch (error48) {
125826
126712
  const detail = error48 instanceof Error ? error48.message : String(error48);
@@ -125830,7 +126716,7 @@ function readRequiredHostKeyFingerprint() {
125830
126716
  function writeAuthorizedKeysAtomically(path3, contents) {
125831
126717
  const tmpPath = `${path3}.scout-${process.pid}-${Date.now()}.tmp`;
125832
126718
  try {
125833
- writeFileSync17(tmpPath, contents, { mode: 384, flag: "wx" });
126719
+ writeFileSync16(tmpPath, contents, { mode: 384, flag: "wx" });
125834
126720
  renameSync6(tmpPath, path3);
125835
126721
  } catch (error48) {
125836
126722
  try {
@@ -125840,7 +126726,7 @@ function writeAuthorizedKeysAtomically(path3, contents) {
125840
126726
  }
125841
126727
  }
125842
126728
  function withAuthorizedKeysLock(sshDir, action) {
125843
- if (!existsSync52(sshDir)) {
126729
+ if (!existsSync51(sshDir)) {
125844
126730
  mkdirSync20(sshDir, { recursive: true, mode: 448 });
125845
126731
  }
125846
126732
  const lockPath = join60(sshDir, ".scout-authorized-keys.lock");
@@ -130601,6 +131487,9 @@ function startRelay(port, options = {}) {
130601
131487
  } : {},
130602
131488
  fetch(req, server2) {
130603
131489
  const url2 = new URL(req.url);
131490
+ if (url2.pathname === "/pair" && req.method === "GET") {
131491
+ return proxyPairHttp(req, url2, options.pairHttpOrigin, server2.requestIP(req)?.address);
131492
+ }
130604
131493
  if (url2.pathname === "/resolve" && req.method === "POST") {
130605
131494
  return handleResolve(req, roomByBridgeKey, rooms);
130606
131495
  }
@@ -130744,6 +131633,46 @@ function startRelay(port, options = {}) {
130744
131633
  }
130745
131634
  };
130746
131635
  }
131636
+ async function proxyPairHttp(req, url2, pairHttpOrigin, clientIp) {
131637
+ const origin = pairHttpOrigin === undefined ? `http://127.0.0.1:${resolveWebPort()}` : pairHttpOrigin?.trim() || null;
131638
+ if (!origin) {
131639
+ return new Response("Pairing HTTP is not configured", { status: 503 });
131640
+ }
131641
+ const target2 = new URL("/pair", origin);
131642
+ target2.search = url2.search;
131643
+ const headers2 = pairProxyHeaders(req, clientIp);
131644
+ try {
131645
+ const response = await fetch(target2, {
131646
+ method: "GET",
131647
+ headers: headers2,
131648
+ redirect: "manual",
131649
+ signal: AbortSignal.timeout(3000)
131650
+ });
131651
+ const out = new Headers;
131652
+ for (const name2 of ["location", "cache-control", "content-type"]) {
131653
+ const value = response.headers.get(name2);
131654
+ if (value)
131655
+ out.set(name2, value);
131656
+ }
131657
+ return new Response(response.body, { status: response.status, headers: out });
131658
+ } catch {
131659
+ return new Response("Pairing service unreachable", { status: 502 });
131660
+ }
131661
+ }
131662
+ function pairProxyHeaders(req, clientIp) {
131663
+ const headers2 = new Headers;
131664
+ for (const name2 of ["accept", "user-agent", "x-scout-client", "x-scout-device-name"]) {
131665
+ const value = req.headers.get(name2);
131666
+ if (value)
131667
+ headers2.set(name2, value);
131668
+ }
131669
+ headers2.set("x-scout-pair-relay", "1");
131670
+ if (clientIp) {
131671
+ headers2.set("x-forwarded-for", clientIp);
131672
+ headers2.set("x-real-ip", clientIp);
131673
+ }
131674
+ return headers2;
131675
+ }
130747
131676
  async function handleResolve(req, roomByBridgeKey, rooms) {
130748
131677
  try {
130749
131678
  const body = await req.json();
@@ -130809,18 +131738,21 @@ function parseRelayEnvelope2(data) {
130809
131738
  }
130810
131739
  }
130811
131740
  var BRIDGE_ABSENCE_GRACE_MS = 30000, ROOM_IDLE_TIMEOUT_MS = 60000;
131741
+ var init_relay = __esm(() => {
131742
+ init_local_config();
131743
+ });
130812
131744
 
130813
131745
  // ../../apps/desktop/src/core/pairing/runtime/relay-runtime.ts
130814
- import { existsSync as existsSync53, mkdirSync as mkdirSync22 } from "fs";
131746
+ import { existsSync as existsSync52, mkdirSync as mkdirSync22 } from "fs";
130815
131747
  import { homedir as homedir46, networkInterfaces as networkInterfaces2 } from "os";
130816
131748
  import { join as join63 } from "path";
130817
131749
  async function findStoredTailscaleCert(hostname6) {
130818
- if (!existsSync53(PAIRING_DIR2)) {
131750
+ if (!existsSync52(PAIRING_DIR2)) {
130819
131751
  return null;
130820
131752
  }
130821
131753
  const certPath = join63(PAIRING_DIR2, `${hostname6}.crt`);
130822
131754
  const keyPath = join63(PAIRING_DIR2, `${hostname6}.key`);
130823
- if (!existsSync53(certPath) || !existsSync53(keyPath)) {
131755
+ if (!existsSync52(certPath) || !existsSync52(keyPath)) {
130824
131756
  return null;
130825
131757
  }
130826
131758
  if (!await storedCertificateLooksPubliclyTrusted(certPath)) {
@@ -131032,6 +131964,7 @@ var PAIRING_DIR2;
131032
131964
  var init_relay_runtime = __esm(() => {
131033
131965
  init_system_probes();
131034
131966
  init_log2();
131967
+ init_relay();
131035
131968
  PAIRING_DIR2 = join63(homedir46(), ".scout/pairing");
131036
131969
  });
131037
131970
 
@@ -133198,7 +134131,7 @@ __export(exports_session, {
133198
134131
  mergeTerminalSurfaces: () => mergeTerminalSurfaces
133199
134132
  });
133200
134133
  import { spawnSync as spawnSync11 } from "child_process";
133201
- import { createHash as createHash14 } from "crypto";
134134
+ import { createHash as createHash16 } from "crypto";
133202
134135
  import { mkdirSync as mkdirSync23 } from "fs";
133203
134136
  import { homedir as homedir47 } from "os";
133204
134137
  import { basename as basename22, join as join64, resolve as resolve35 } from "path";
@@ -133563,7 +134496,7 @@ function terminalSurfaceKey(surface) {
133563
134496
  function defaultTerminalSessionName(input) {
133564
134497
  const projectName2 = sanitizeTerminalSessionNamePart(basename22(input.cwd) || "workspace", 28);
133565
134498
  const harnessName = sanitizeTerminalSessionNamePart(input.harness, 18);
133566
- const fingerprint = createHash14("sha1").update(`${input.backend}\x00${input.harness}\x00${input.cwd}\x00${input.sessionId}`).digest("hex").slice(0, 10);
134499
+ const fingerprint = createHash16("sha1").update(`${input.backend}\x00${input.harness}\x00${input.cwd}\x00${input.sessionId}`).digest("hex").slice(0, 10);
133567
134500
  return `scout-${harnessName}-${projectName2}-${fingerprint}`;
133568
134501
  }
133569
134502
  function sanitizeTerminalSessionNamePart(value, maxLength) {
@@ -133932,7 +134865,7 @@ __export(exports_server, {
133932
134865
  normalizeServerOpenPath: () => normalizeServerOpenPath
133933
134866
  });
133934
134867
  import { spawn as spawn10 } from "child_process";
133935
- import { existsSync as existsSync54, mkdirSync as mkdirSync24, openSync as openSync2, writeFileSync as writeFileSync18 } from "fs";
134868
+ import { existsSync as existsSync53, mkdirSync as mkdirSync24, openSync as openSync2, writeFileSync as writeFileSync17 } from "fs";
133936
134869
  import { homedir as homedir48 } from "os";
133937
134870
  import { dirname as dirname31, join as join65, resolve as resolve36 } from "path";
133938
134871
  import { fileURLToPath as fileURLToPath12 } from "url";
@@ -134372,7 +135305,7 @@ async function runScoutLocalEdge(env) {
134372
135305
  const config3 = resolveServerLocalEdgeConfig(env);
134373
135306
  const schemes = config3.scheme === "both" ? ["http", "https"] : [config3.scheme];
134374
135307
  const caddyfilePath = resolveScoutLocalEdgeCaddyfilePath();
134375
- writeFileSync18(caddyfilePath, renderOpenScoutCaddyfile(config3), "utf8");
135308
+ writeFileSync17(caddyfilePath, renderOpenScoutCaddyfile(config3), "utf8");
134376
135309
  const mdnsProcesses = schemes.flatMap((scheme) => {
134377
135310
  const edgePort = scheme === "https" ? 443 : 80;
134378
135311
  const suffix = scheme.toUpperCase();
@@ -134514,14 +135447,14 @@ __export(exports_setup, {
134514
135447
  runSetupCommand: () => runSetupCommand,
134515
135448
  resolveSetupSourceRoots: () => resolveSetupSourceRoots
134516
135449
  });
134517
- import { existsSync as existsSync55 } from "fs";
135450
+ import { existsSync as existsSync54 } from "fs";
134518
135451
  import { homedir as homedir49 } from "os";
134519
135452
  import { dirname as dirname32, join as join66, resolve as resolve37 } from "path";
134520
135453
  import { createInterface as createInterface4 } from "readline/promises";
134521
135454
  function findGitRoot2(startDirectory) {
134522
135455
  let current = resolve37(startDirectory);
134523
135456
  while (true) {
134524
- if (existsSync55(join66(current, ".git")))
135457
+ if (existsSync54(join66(current, ".git")))
134525
135458
  return current;
134526
135459
  const parent = dirname32(current);
134527
135460
  if (parent === current)
@@ -134538,7 +135471,7 @@ function suggestProjectSourceRoot(currentDirectory, homeDirectory = homedir49())
134538
135471
  join66(homeDirectory, "Developer"),
134539
135472
  join66(homeDirectory, "Projects")
134540
135473
  ]) {
134541
- if (existsSync55(candidate))
135474
+ if (existsSync54(candidate))
134542
135475
  return candidate;
134543
135476
  }
134544
135477
  return resolve37(currentDirectory);
@@ -134575,7 +135508,7 @@ async function resolveSetupSourceRoots(context, currentDirectory, sourceRoots, e
134575
135508
  async function runSetupCommand(context, args) {
134576
135509
  const options = parseSetupCommandOptions(args, defaultScoutContextDirectory(context));
134577
135510
  const settings = await readOpenScoutSettings({ currentDirectory: options.currentDirectory });
134578
- const hasSavedSettings = existsSync55(resolveOpenScoutSupportPaths().settingsPath);
135511
+ const hasSavedSettings = existsSync54(resolveOpenScoutSupportPaths().settingsPath);
134579
135512
  options.sourceRoots = await resolveSetupSourceRoots({ ...context, isTty: context.isTty && Boolean(process.stdin.isTTY) }, options.currentDirectory, options.sourceRoots, {
134580
135513
  roots: hasSavedSettings ? settings.discovery.workspaceRoots : [],
134581
135514
  answeredAt: hasSavedSettings ? settings.onboarding.sourceRootsAnsweredAt : null
@@ -134831,7 +135764,7 @@ function readPositiveIntEnv(name2, fallback2) {
134831
135764
  const raw2 = Number.parseInt(process.env[name2] ?? "", 10);
134832
135765
  return Number.isFinite(raw2) && raw2 > 0 ? raw2 : fallback2;
134833
135766
  }
134834
- var TAIL_POLL_INTERVAL_MS, HOT_DISCOVERY_INTERVAL_MS, DISCOVERY_CACHE_MAX_AGE_MS, SHALLOW_DISCOVERY_INTERVAL_MS, DEEP_DISCOVERY_INTERVAL_MS, QUIET_EVENT_COALESCE_WINDOW_MS, QUIET_EVENT_COALESCE_MAX_KEYS, RECENT_TRANSCRIPT_READ_BYTES, SESSION_TRANSCRIPT_READ_BYTES, RECENT_TRANSCRIPT_KIND_SCAN_READ_BYTES, RECENT_TRANSCRIPT_MAX_FILES, NATIVE_TAIL_SOURCES, TRANSCRIPT_REPLAY_MEMO_MAX_ENTRIES, TRANSCRIPT_REPLAY_ACTIVE_GRACE_MS, transcriptReplayMemo, transcriptReplayInFlight, watchers, perSessionBuffer, subscribers, knownTranscripts, quietEventLastSeen, GROK_QUIET_PHASES;
135767
+ var DEFAULT_TAIL_POLL_INTERVAL_MS = 1e4, DEFAULT_HOT_DISCOVERY_INTERVAL_MS = 60000, TAIL_POLL_INTERVAL_MS, HOT_DISCOVERY_INTERVAL_MS, DISCOVERY_CACHE_MAX_AGE_MS, SHALLOW_DISCOVERY_INTERVAL_MS, DEEP_DISCOVERY_INTERVAL_MS, QUIET_EVENT_COALESCE_WINDOW_MS, QUIET_EVENT_COALESCE_MAX_KEYS, RECENT_TRANSCRIPT_READ_BYTES, WATCHER_READ_BYTES, WATCHER_DRAIN_BYTES, WATCHER_PUMP_CONCURRENCY, SESSION_TRANSCRIPT_READ_BYTES, RECENT_TRANSCRIPT_KIND_SCAN_READ_BYTES, RECENT_TRANSCRIPT_MAX_FILES, INTERNAL_RECONCILE_SESSIONS_PER_SOURCE, INTERNAL_RECONCILE_LINES_PER_SESSION, INTERNAL_RECONCILE_READ_BYTES, INTERNAL_HOT_WATCHER_WINDOW_MS, INTERNAL_IDLE_WATCHER_INTERVAL_MS, INTERNAL_IDLE_WATCHER_BATCH_SIZE, INTERNAL_ACTIVE_STALE_AFTER_MS, INTERNAL_PERSISTED_OBSERVED_SEED_LIMIT, NATIVE_TAIL_SOURCES, TRANSCRIPT_REPLAY_MEMO_MAX_ENTRIES, TRANSCRIPT_REPLAY_ACTIVE_GRACE_MS, transcriptReplayMemo, transcriptReplayInFlight, watchers, perSessionBuffer, subscribers, internalSubscribers, knownTranscripts, persistedObservedSessions, quietEventLastSeen, GROK_QUIET_PHASES;
134835
135768
  var init_service11 = __esm(() => {
134836
135769
  init_claude_source();
134837
135770
  init_codex_source();
@@ -134840,17 +135773,28 @@ var init_service11 = __esm(() => {
134840
135773
  init_kimi_source();
134841
135774
  init_opencode_source();
134842
135775
  init_pi_source();
134843
- TAIL_POLL_INTERVAL_MS = readPositiveIntEnv("OPENSCOUT_TAIL_POLL_INTERVAL_MS", 500);
134844
- HOT_DISCOVERY_INTERVAL_MS = readPositiveIntEnv("OPENSCOUT_TAIL_HOT_DISCOVERY_INTERVAL_MS", 30000);
135776
+ TAIL_POLL_INTERVAL_MS = readPositiveIntEnv("OPENSCOUT_TAIL_POLL_INTERVAL_MS", DEFAULT_TAIL_POLL_INTERVAL_MS);
135777
+ HOT_DISCOVERY_INTERVAL_MS = readPositiveIntEnv("OPENSCOUT_TAIL_HOT_DISCOVERY_INTERVAL_MS", DEFAULT_HOT_DISCOVERY_INTERVAL_MS);
134845
135778
  DISCOVERY_CACHE_MAX_AGE_MS = readPositiveIntEnv("OPENSCOUT_TAIL_DISCOVERY_CACHE_MAX_AGE_MS", HOT_DISCOVERY_INTERVAL_MS);
134846
135779
  SHALLOW_DISCOVERY_INTERVAL_MS = readPositiveIntEnv("OPENSCOUT_TAIL_SHALLOW_DISCOVERY_INTERVAL_MS", 10 * 60000);
134847
135780
  DEEP_DISCOVERY_INTERVAL_MS = readPositiveIntEnv("OPENSCOUT_TAIL_DEEP_DISCOVERY_INTERVAL_MS", 60 * 60000);
134848
135781
  QUIET_EVENT_COALESCE_WINDOW_MS = readPositiveIntEnv("OPENSCOUT_TAIL_QUIET_EVENT_COALESCE_WINDOW_MS", 5000);
134849
135782
  QUIET_EVENT_COALESCE_MAX_KEYS = readPositiveIntEnv("OPENSCOUT_TAIL_QUIET_EVENT_COALESCE_MAX_KEYS", 2000);
134850
135783
  RECENT_TRANSCRIPT_READ_BYTES = 512 * 1024;
135784
+ WATCHER_READ_BYTES = readPositiveIntEnv("OPENSCOUT_TAIL_WATCHER_READ_BYTES", 512 * 1024);
135785
+ WATCHER_DRAIN_BYTES = Math.max(WATCHER_READ_BYTES, readPositiveIntEnv("OPENSCOUT_TAIL_WATCHER_DRAIN_BYTES", 4 * 1024 * 1024));
135786
+ WATCHER_PUMP_CONCURRENCY = readPositiveIntEnv("OPENSCOUT_TAIL_WATCHER_PUMP_CONCURRENCY", 16);
134851
135787
  SESSION_TRANSCRIPT_READ_BYTES = 8 * 1024 * 1024;
134852
135788
  RECENT_TRANSCRIPT_KIND_SCAN_READ_BYTES = 32 * 1024 * 1024;
134853
135789
  RECENT_TRANSCRIPT_MAX_FILES = readPositiveIntEnv("OPENSCOUT_TAIL_RECENT_TRANSCRIPT_MAX_FILES", 24);
135790
+ INTERNAL_RECONCILE_SESSIONS_PER_SOURCE = readPositiveIntEnv("OPENSCOUT_TAIL_INTERNAL_RECONCILE_SESSIONS_PER_SOURCE", 12);
135791
+ INTERNAL_RECONCILE_LINES_PER_SESSION = readPositiveIntEnv("OPENSCOUT_TAIL_INTERNAL_RECONCILE_LINES_PER_SESSION", 128);
135792
+ INTERNAL_RECONCILE_READ_BYTES = readPositiveIntEnv("OPENSCOUT_TAIL_INTERNAL_RECONCILE_READ_BYTES", 256 * 1024);
135793
+ INTERNAL_HOT_WATCHER_WINDOW_MS = readPositiveIntEnv("OPENSCOUT_TAIL_INTERNAL_HOT_WATCHER_WINDOW_MS", 60000);
135794
+ INTERNAL_IDLE_WATCHER_INTERVAL_MS = readPositiveIntEnv("OPENSCOUT_TAIL_INTERNAL_IDLE_WATCHER_INTERVAL_MS", 15000);
135795
+ INTERNAL_IDLE_WATCHER_BATCH_SIZE = readPositiveIntEnv("OPENSCOUT_TAIL_INTERNAL_IDLE_WATCHER_BATCH_SIZE", 32);
135796
+ INTERNAL_ACTIVE_STALE_AFTER_MS = readPositiveIntEnv("OPENSCOUT_TAIL_INTERNAL_ACTIVE_STALE_AFTER_MS", 30 * 60000);
135797
+ INTERNAL_PERSISTED_OBSERVED_SEED_LIMIT = readPositiveIntEnv("OPENSCOUT_TAIL_PERSISTED_OBSERVED_SEED_LIMIT", 4096);
134854
135798
  NATIVE_TAIL_SOURCES = new Set(["grok", "kimi", "opencode", "cursor"]);
134855
135799
  TRANSCRIPT_REPLAY_MEMO_MAX_ENTRIES = readPositiveIntEnv("OPENSCOUT_TAIL_REPLAY_MEMO_MAX_ENTRIES", 256);
134856
135800
  TRANSCRIPT_REPLAY_ACTIVE_GRACE_MS = readPositiveIntEnv("OPENSCOUT_TAIL_REPLAY_MEMO_ACTIVE_GRACE_MS", 2000);
@@ -134859,7 +135803,9 @@ var init_service11 = __esm(() => {
134859
135803
  watchers = new Map;
134860
135804
  perSessionBuffer = new Map;
134861
135805
  subscribers = new Set;
135806
+ internalSubscribers = new Set;
134862
135807
  knownTranscripts = new Map;
135808
+ persistedObservedSessions = new Map;
134863
135809
  quietEventLastSeen = new Map;
134864
135810
  GROK_QUIET_PHASES = new Set([
134865
135811
  "streaming_reasoning",
@@ -135415,7 +136361,7 @@ __export(exports_tui, {
135415
136361
  parseTuiLaunchOptions: () => parseTuiLaunchOptions
135416
136362
  });
135417
136363
  import { spawnSync as spawnSync12 } from "child_process";
135418
- import { accessSync as accessSync5, constants as constants5, existsSync as existsSync56 } from "fs";
136364
+ import { accessSync as accessSync5, constants as constants5, existsSync as existsSync55 } from "fs";
135419
136365
  import { dirname as dirname33, join as join67, resolve as resolve38 } from "path";
135420
136366
  import { fileURLToPath as fileURLToPath13 } from "url";
135421
136367
  function renderTuiCommandHelp() {
@@ -135544,7 +136490,7 @@ function findScoutTuiCheckout(cwd, env) {
135544
136490
  for (const start of starts) {
135545
136491
  let current = resolve38(start);
135546
136492
  while (true) {
135547
- if (existsSync56(join67(current, "crates/scout-tui/Cargo.toml"))) {
136493
+ if (existsSync55(join67(current, "crates/scout-tui/Cargo.toml"))) {
135548
136494
  return current;
135549
136495
  }
135550
136496
  const parent = dirname33(current);
@@ -135598,7 +136544,7 @@ var exports_up = {};
135598
136544
  __export(exports_up, {
135599
136545
  runUpCommand: () => runUpCommand
135600
136546
  });
135601
- import { existsSync as existsSync57 } from "fs";
136547
+ import { existsSync as existsSync56 } from "fs";
135602
136548
  import { resolve as resolve39 } from "path";
135603
136549
  function looksLikePath(value) {
135604
136550
  return value.includes("/") || value.startsWith(".") || value.startsWith("~");
@@ -135707,7 +136653,7 @@ async function runUpCommand(context, args) {
135707
136653
  throw new ScoutCliError(`usage: scout up <name|path> [--name <alias>] [--harness <${SUPPORTED_LOCAL_AGENT_HARNESSES.join("|")}>] [--provider <provider>] [--model <model>] [--reasoning-effort <effort>] [--permission-profile <${formatScoutPermissionProfiles()}>]`);
135708
136654
  }
135709
136655
  let projectPath;
135710
- if (looksLikePath(target2) || existsSync57(resolve39(target2))) {
136656
+ if (looksLikePath(target2) || existsSync56(resolve39(target2))) {
135711
136657
  projectPath = resolve39(target2);
135712
136658
  } else {
135713
136659
  const resolved = await resolveLocalAgentByName(target2);
@@ -136117,7 +137063,7 @@ var init_whoami = __esm(() => {
136117
137063
  });
136118
137064
 
136119
137065
  // ../../apps/desktop/src/cli/main.ts
136120
- import { existsSync as existsSync58, statSync as statSync17 } from "fs";
137066
+ import { existsSync as existsSync57, statSync as statSync17 } from "fs";
136121
137067
  import { join as join70 } from "path";
136122
137068
  import { spawnSync as spawnSync13 } from "child_process";
136123
137069
  import { homedir as homedir50 } from "os";
@@ -136828,7 +137774,7 @@ function getScoutBinPath() {
136828
137774
  if (_scoutBinPath)
136829
137775
  return _scoutBinPath;
136830
137776
  _scoutBinPath = join70(homedir50(), ".bun", "bin", "scout");
136831
- if (!existsSync58(_scoutBinPath)) {
137777
+ if (!existsSync57(_scoutBinPath)) {
136832
137778
  _scoutBinPath = spawnSync13("which", ["scout"], { encoding: "utf8" }).stdout.trim();
136833
137779
  }
136834
137780
  return _scoutBinPath;