@openscout/scout 0.2.76 → 0.2.78

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 (372) hide show
  1. package/README.md +41 -2
  2. package/bin/openscout-runtime.mjs +48 -30
  3. package/bin/scout.mjs +2 -2
  4. package/bin/scoutd +0 -0
  5. package/dist/build-manifest.json +3 -3
  6. package/dist/client/assets/ActivityScreen-Cu_1V4bq.js +1 -0
  7. package/dist/client/assets/AddProjectForm-DMnobKch.js +1 -0
  8. package/dist/client/assets/AgentAvatar-D90c1Rzk.js +1 -0
  9. package/dist/client/assets/AgentConfigurationScreen-BqfOz90D.js +1 -0
  10. package/dist/client/assets/AgentDefinitionsWorkspace-CUpUrY57.js +1 -0
  11. package/dist/client/assets/AgentDetailCard-BcRBRp88.js +1 -0
  12. package/dist/client/assets/AgentDetailCard-C4WVeJvJ.css +1 -0
  13. package/dist/client/assets/AgentFloorView-8LoAEBwS.js +1 -0
  14. package/dist/client/assets/AgentInfoScreen-DZs2_ibL.js +1 -0
  15. package/dist/client/assets/AgentLaneCard-RrNnDZu8.js +1 -0
  16. package/dist/client/assets/AgentLaneChrome-D9ZwUKrl.js +1 -0
  17. package/dist/client/assets/AgentLaneDetailSheet-BXbPls9N.js +5 -0
  18. package/dist/client/assets/AgentLaneSummaryResize-BhFmGNzT.js +1 -0
  19. package/dist/client/assets/AgentLanesEmbedScreen-W3qs022h.js +1 -0
  20. package/dist/client/assets/AgentLanesPreflight-eSAoDsPi.js +1 -0
  21. package/dist/client/assets/AgentLanesView-B9vuEEmZ.js +2 -0
  22. package/dist/client/assets/AgentLiveActions-CGS-Bxb7.css +1 -0
  23. package/dist/client/assets/AgentLiveActions-DBtnD0qE.js +1 -0
  24. package/dist/client/assets/AgentSessions-DyqOf4nG.js +6 -0
  25. package/dist/client/assets/AgentsConsole-BgiYP2wR.js +1 -0
  26. package/dist/client/assets/AgentsConsole-BjSTs-TV.css +1 -0
  27. package/dist/client/assets/AgentsScreen-DBi8x4MB.js +1 -0
  28. package/dist/client/assets/AgentsSubnav-DIEO4NPx.js +1 -0
  29. package/dist/client/assets/AtopView-BCkae3e1.js +1 -0
  30. package/dist/client/assets/BackToPicker-BRvfostO.js +1 -0
  31. package/dist/client/assets/BackToPicker-CdgVu-to.css +1 -0
  32. package/dist/client/assets/BriefingDetailScreen-BwFyysT8.js +6 -0
  33. package/dist/client/assets/BriefingsScreen-BQEevztH.js +1 -0
  34. package/dist/client/assets/BrokerMetadataPanel-7UjcuNjd.js +1 -0
  35. package/dist/client/assets/BrokerScreen-7ekklu88.js +5 -0
  36. package/dist/client/assets/ChatCollapsedStrip-CQSYSd8s.js +1 -0
  37. package/dist/client/assets/CodeDiffPane-DDPt6KPh.js +1 -0
  38. package/dist/client/assets/CodeProjectPicker-DqKFCpLU.js +2 -0
  39. package/dist/client/assets/CodeScreen-BxCrpRHd.js +1 -0
  40. package/dist/client/assets/ContextMenu-bARZqTzD.js +1 -0
  41. package/dist/client/assets/ConversationComposer-Bla3DDvM.js +1 -0
  42. package/dist/client/assets/ConversationFeedRows-B_gPxcqA.js +1 -0
  43. package/dist/client/assets/ConversationHeader-DE3FC0m-.js +1 -0
  44. package/dist/client/assets/ConversationPanels-DLek4H6A.js +2 -0
  45. package/dist/client/assets/ConversationScreen-BDRhx-RU.js +1 -0
  46. package/dist/client/assets/ConversationScreen-C9yMAMYF.css +1 -0
  47. package/dist/client/assets/ConversationStatus-BwVLiiO4.js +1 -0
  48. package/dist/client/assets/DataTable-E8s_MmoA.js +1 -0
  49. package/dist/client/assets/DispatchAftermath-Dpe88DFX.js +1 -0
  50. package/dist/client/assets/DocumentFocusViewer-BeVwwl26.js +1 -0
  51. package/dist/client/assets/EmbeddableSurfacesLab-BQqFQVnI.js +1 -0
  52. package/dist/client/assets/EmptyState-4F9XDFQm.js +1 -0
  53. package/dist/client/assets/FileViewerPane-CLgUhSm4.js +3 -0
  54. package/dist/client/assets/FleetSearch-Dz5euQJe.js +1 -0
  55. package/dist/client/assets/FleetSearch-EXOe8ulE.css +1 -0
  56. package/dist/client/assets/FlightObserveScreen-6RpZYwVz.js +1 -0
  57. package/dist/client/assets/FollowScreen-DZ4qfYOY.js +1 -0
  58. package/dist/client/assets/HarnessMark-Cbv3Ib0c.js +1 -0
  59. package/dist/client/assets/HarnessesScreen-CznAImej.js +1 -0
  60. package/dist/client/assets/HomeHero-B3uYd-pP.js +1 -0
  61. package/dist/client/assets/HomeHero-DEl-WBsT.css +1 -0
  62. package/dist/client/assets/KnowledgeSearchInspector-Dgdkfvvz.js +1 -0
  63. package/dist/client/assets/KnowledgeSearchScreen-DJDGGaqC.js +1 -0
  64. package/dist/client/assets/LaneToolHoverCard-Bla0gBdm.js +1 -0
  65. package/dist/client/assets/LaneTraceDetailSheet-D1CspRbl.js +1 -0
  66. package/dist/client/assets/LaneTraceEventFocus-BF9ERP5O.js +1 -0
  67. package/dist/client/assets/MeshCanvas-DFEPkpqY.js +3 -0
  68. package/dist/client/assets/MeshCanvasMinimap-CyVFYixr.js +1 -0
  69. package/dist/client/assets/MeshCanvasMinimap-Dv7nMbl5.css +1 -0
  70. package/dist/client/assets/MeshScreen-DFgevn8N.js +1 -0
  71. package/dist/client/assets/MeshTopologyView-CalkZghg.js +2 -0
  72. package/dist/client/assets/MessageComposerSuggestions-DpxN9WiB.js +1 -0
  73. package/dist/client/assets/MessagesScreen-C8YKW10Y.js +1 -0
  74. package/dist/client/assets/MissionControlView-lUeAiSVg.js +1 -0
  75. package/dist/client/assets/MissionFocusOverlay-wlCmWDCT.js +1 -0
  76. package/dist/client/assets/MissionLeftAgentRow-BpZWntfl.js +1 -0
  77. package/dist/client/assets/MissionLogPane-__MVtEl9.js +1 -0
  78. package/dist/client/assets/NewAgentModal-Bg-eWHpY.js +1 -0
  79. package/dist/client/assets/NewAgentModal-ru8u5YdJ.css +1 -0
  80. package/dist/client/assets/NewChatComposer-Cs6OsxK6.js +19 -0
  81. package/dist/client/assets/NewChatComposer-W-t-L4oV.css +1 -0
  82. package/dist/client/assets/NewChatOrigin-Bk2OyVjI.js +1 -0
  83. package/dist/client/assets/ObserveEmbedScreen-y2EpuqRZ.js +2 -0
  84. package/dist/client/assets/ObserveTextFlow-rsFj_rVo.js +2 -0
  85. package/dist/client/assets/ObservedTopologyPanel-BsBsvVPL.css +1 -0
  86. package/dist/client/assets/ObservedTopologyPanel-DyUeV98H.js +2 -0
  87. package/dist/client/assets/OpenScoutAppShell-Bh6FnEJO.css +1 -0
  88. package/dist/client/assets/OpenScoutAppShell-C_URc8sV.js +87 -0
  89. package/dist/client/assets/OpsAgentsView-UN7iOscs.js +1 -0
  90. package/dist/client/assets/OpsScreen-Buf3LKjb.js +1 -0
  91. package/dist/client/assets/OpsSubnav-DsuXzHah.js +1 -0
  92. package/dist/client/assets/PlanView-C1CjH3PG.js +1 -0
  93. package/dist/client/assets/ProjectAgentProfile-DJusrAV-.js +1 -0
  94. package/dist/client/assets/ProjectAgentProfileBar-CtTpj6fU.js +1 -0
  95. package/dist/client/assets/ProjectAgentProfileHero-BFwNJo_N.js +1 -0
  96. package/dist/client/assets/ProjectsInbox-GhVMxOhw.js +2 -0
  97. package/dist/client/assets/ProjectsRail-BgiuV4LR.js +1 -0
  98. package/dist/client/assets/ProjectsScreen-eNUBy4YU.js +1 -0
  99. package/dist/client/assets/ProjectsThreadAside-CoBgnHmr.js +1 -0
  100. package/dist/client/assets/Provider-C7UKGHQy.js +1 -0
  101. package/dist/client/assets/Provider-CCzjtkda.css +1 -0
  102. package/dist/client/assets/RailRow-BoGxAHNF.js +1 -0
  103. package/dist/client/assets/RailRow-Cf9LOiEj.css +1 -0
  104. package/dist/client/assets/RawSessionsTable-DL8y_eEy.js +1 -0
  105. package/dist/client/assets/RealtimeVoiceScreen-ffS-39zy.js +1 -0
  106. package/dist/client/assets/RepoDiffEmbedScreen-C0rumUME.js +1 -0
  107. package/dist/client/assets/RepoDiffPageScreen-DMv6DioL.js +1 -0
  108. package/dist/client/assets/RepoDiffViewer-D_exm6xK.js +7 -0
  109. package/dist/client/assets/RepoDiffViewerLazy-BPgF92Bg.js +2 -0
  110. package/dist/client/assets/ReposScreen-CB_YBWYf.js +6 -0
  111. package/dist/client/assets/ScoutDeckSurface-CxIYFyWx.js +1 -0
  112. package/dist/client/assets/ScoutDeckSurface-uhmuZRzC.css +1 -0
  113. package/dist/client/assets/ScoutSurface-CYz_TcWC.js +1 -0
  114. package/dist/client/assets/ScoutbotBroadcastChip-CxtYZWPZ.css +1 -0
  115. package/dist/client/assets/ScoutbotBroadcastChip-L_R9atj0.js +2 -0
  116. package/dist/client/assets/ScoutbotFxLab-CgiZMDMW.js +4 -0
  117. package/dist/client/assets/ScoutbotRealtimeVoiceCall-FMQOr1Np.js +1 -0
  118. package/dist/client/assets/SecondaryNav-B3-nh5dM.js +1 -0
  119. package/dist/client/assets/SessionEmbedScreen-BVC7yvWF.js +1 -0
  120. package/dist/client/assets/SessionObserve-BpggNO_M.css +1 -0
  121. package/dist/client/assets/SessionObserve-yfXFafp8.js +12 -0
  122. package/dist/client/assets/SessionRefScreen-DRgJu7Jo.js +1 -0
  123. package/dist/client/assets/SessionsScreen-D6XUsZfA.js +1 -0
  124. package/dist/client/assets/SettingsDrawer-CmJt72ww.css +1 -0
  125. package/dist/client/assets/SettingsDrawer-XfdAa_nD.js +3 -0
  126. package/dist/client/assets/SettingsScreen-Cy8z-EuR.js +1 -0
  127. package/dist/client/assets/ShikiPane-Ap1iPxYb.js +15 -0
  128. package/dist/client/assets/SlidePanel-Bg5dVaIa.css +1 -0
  129. package/dist/client/assets/SlidePanel-COwtoJqR.js +1 -0
  130. package/dist/client/assets/SpriteAvatar-DyaGuhik.js +1 -0
  131. package/dist/client/assets/StatusPill-DhBL__p8.js +1 -0
  132. package/dist/client/assets/TailView-DGj_5HA9.js +2 -0
  133. package/dist/client/assets/TailView-Mj3AU2u0.css +1 -0
  134. package/dist/client/assets/Terminal-CqvGbjXU.js +1 -0
  135. package/dist/client/assets/TerminalEmbedScreen-DuZZFFzW.js +1 -0
  136. package/dist/client/assets/TextDocumentSurface-BpAw4eQS.js +4 -0
  137. package/dist/client/assets/TmuxPeek-m1osv33Q.js +1 -0
  138. package/dist/client/assets/VoicePermissionsPanel-DsK53ar4.js +1 -0
  139. package/dist/client/assets/VoicePermissionsPanel-RijAZ1gP.css +1 -0
  140. package/dist/client/assets/WorkDetailScreen-Bx0JimPC.js +5 -0
  141. package/dist/client/assets/WorkFilesViewer-Btl6C2Q1.js +1 -0
  142. package/dist/client/assets/activity-CA8qS6PI.js +1 -0
  143. package/dist/client/assets/{addon-fit-BOSszMLK.js → addon-fit-BZ-kXjeN.js} +1 -1
  144. package/dist/client/assets/{addon-webgl-WE840gr0.js → addon-webgl-D9-EQVEK.js} +1 -1
  145. package/dist/client/assets/agent-chat-Bfjd9y6c.js +1 -0
  146. package/dist/client/assets/agent-definitions-CymTYqvo.css +1 -0
  147. package/dist/client/assets/agent-directory-studio-injection-Bc8590z5.css +1 -0
  148. package/dist/client/assets/agent-essentials-BSY1o46q.js +1 -0
  149. package/dist/client/assets/agent-floor-CuJr1iK1.css +1 -0
  150. package/dist/client/assets/agent-lane-card-Dm7YWoew.css +1 -0
  151. package/dist/client/assets/agent-lane-card-model-r2frk57c.js +1 -0
  152. package/dist/client/assets/agent-lane-detail-Djm3YJEa.js +1 -0
  153. package/dist/client/assets/agent-lane-preview-CmHVe3dU.js +4 -0
  154. package/dist/client/assets/agent-lanes-BDNktFBZ.css +1 -0
  155. package/dist/client/assets/agent-lanes-model-B4YTt4OF.js +2 -0
  156. package/dist/client/assets/agents-detail-redesign-h34ROjOW.css +1 -0
  157. package/dist/client/assets/agents-project-COzHxZAF.css +1 -0
  158. package/dist/client/assets/agents-project-model-UYiamtrU.js +1 -0
  159. package/dist/client/assets/agents-screen-BMu6PpRY.css +1 -0
  160. package/dist/client/assets/api-BkjHJfgJ.js +1 -0
  161. package/dist/client/assets/api-h5zurxmi.js +1 -0
  162. package/dist/client/assets/{arc.es-KGqGKGIy.js → arc.es-CQBb-dVu.js} +1 -1
  163. package/dist/client/assets/arrow-down-BPLe0am9.js +1 -0
  164. package/dist/client/assets/arrow-left-DEZzHiPS.js +1 -0
  165. package/dist/client/assets/arrow-up-right-ClxBnsi7.js +1 -0
  166. package/dist/client/assets/bash-format-BRV5C6Gv.js +1 -0
  167. package/dist/client/assets/bot-eu8pBNvI.js +1 -0
  168. package/dist/client/assets/briefings-BwuAFQK6.css +1 -0
  169. package/dist/client/assets/broker-display-pp33bLsu.js +2 -0
  170. package/dist/client/assets/cache-Dr0why2k.js +2 -0
  171. package/dist/client/assets/check-DjgFiBxb.js +1 -0
  172. package/dist/client/assets/chevron-down-BGk5qoEw.js +1 -0
  173. package/dist/client/assets/chevron-right-XiIHsk4m.js +1 -0
  174. package/dist/client/assets/chunk-T65CQEWV-CrzwSeEt.js +1 -0
  175. package/dist/client/assets/chunk-YOZR3KYS-Bet8khjg.js +47 -0
  176. package/dist/client/assets/clipboard-e3fSpeo7.js +1 -0
  177. package/dist/client/assets/code-screen-DrKinCyh.css +1 -0
  178. package/dist/client/assets/code-xml-B6jOCM4V.js +1 -0
  179. package/dist/client/assets/collapsed-strip-Dz-of2SM.css +1 -0
  180. package/dist/client/assets/colors-BtO5_zlx.js +1 -0
  181. package/dist/client/assets/console-B1IBqLI_.css +1 -0
  182. package/dist/client/assets/content-BDt9VBPk.js +1 -0
  183. package/dist/client/assets/content-BIXf4cKR.js +1 -0
  184. package/dist/client/assets/content-BLm0NBJM.js +1 -0
  185. package/dist/client/assets/content-C2EwTb2y.js +1 -0
  186. package/dist/client/assets/content-C5UbLsDF.js +1 -0
  187. package/dist/client/assets/content-CHU0wwA3.css +1 -0
  188. package/dist/client/assets/content-CR3vdrYY.js +1 -0
  189. package/dist/client/assets/content-CSPVmo2s.js +1 -0
  190. package/dist/client/assets/content-C_FGqx1X.js +1 -0
  191. package/dist/client/assets/content-CvlVUOG8.js +1 -0
  192. package/dist/client/assets/content-D5kJmfgl.js +1 -0
  193. package/dist/client/assets/content-DTpQsomG.js +1 -0
  194. package/dist/client/assets/content-DikVsqLf.js +1 -0
  195. package/dist/client/assets/content-DlUe5Ono.js +1 -0
  196. package/dist/client/assets/content-GIBv_55n.js +1 -0
  197. package/dist/client/assets/content-Q2oclDzi.js +1 -0
  198. package/dist/client/assets/context-budget-CbB4BDcO.js +1 -0
  199. package/dist/client/assets/conversation-icons-IIG5ha6D.js +1 -0
  200. package/dist/client/assets/conversation-model-B47vYmWN.js +1 -0
  201. package/dist/client/assets/conversation-motion-features-BdAONVls.js +1 -0
  202. package/dist/client/assets/conversation-prefs-DNre-Lcx.js +1 -0
  203. package/dist/client/assets/copy-CQGYbxdu.js +1 -0
  204. package/dist/client/assets/createLucideIcon-OpA4Amw5.js +1 -0
  205. package/dist/client/assets/ctx-panel-B4s49N9e.css +1 -0
  206. package/dist/client/assets/discover-C1YwpBDE.js +2 -0
  207. package/dist/client/assets/document-focus-viewer-BSC_JwVE.css +1 -0
  208. package/dist/client/assets/embed-entry-BAcGL3g9.js +2 -0
  209. package/dist/client/assets/external-link-CXBytO9o.js +1 -0
  210. package/dist/client/assets/eye-0PvebX_a.js +1 -0
  211. package/dist/client/assets/file-text-BODxCjcz.js +1 -0
  212. package/dist/client/assets/flight-observe-GFg9L8ft.css +1 -0
  213. package/dist/client/assets/follow-route-BvcGtBIL.js +1 -0
  214. package/dist/client/assets/fx-z37u1o2z.js +1 -0
  215. package/dist/client/assets/gestures-CcwOTu8C.js +1 -0
  216. package/dist/client/assets/harnesses-screen-DBZoTZz8.css +1 -0
  217. package/dist/client/assets/home-live-action-B22u89j7.js +1 -0
  218. package/dist/client/assets/home-moving-signal-CAa0V91u.css +1 -0
  219. package/dist/client/assets/home-moving-signal-CK147hxn.js +1 -0
  220. package/dist/client/assets/home-now-card-BgvNWuea.js +1 -0
  221. package/dist/client/assets/home-now-card-nano-BcjnOU9H.js +1 -0
  222. package/dist/client/assets/hooks-B6y_O2FB.js +2 -0
  223. package/dist/client/assets/hooks-D6NI15f6.css +1 -0
  224. package/dist/client/assets/inbox-thread-redesign-Bz4FjWzr.css +1 -0
  225. package/dist/client/assets/index-BWHgHrtv.js +1 -0
  226. package/dist/client/assets/index-BcuhqXLe.js +1 -0
  227. package/dist/client/assets/index-CJXzfjo9.js +1 -0
  228. package/dist/client/assets/index-CvF09yvf.css +1 -0
  229. package/dist/client/assets/index-DMiGbrBt.js +10 -0
  230. package/dist/client/assets/index-DQPvraRS.js +1 -0
  231. package/dist/client/assets/index-DxGoC5l5.css +1 -0
  232. package/dist/client/assets/inspector-panel-DPoCWxKs.js +2 -0
  233. package/dist/client/assets/keyboard-nav-2kv_tGUS.js +1 -0
  234. package/dist/client/assets/knowledge-search-CVxQwxPn.js +1 -0
  235. package/dist/client/assets/knowledge-search-DjrQdiiW.css +1 -0
  236. package/dist/client/assets/lane-ask-display-B6iCAVcd.js +18 -0
  237. package/dist/client/assets/lane-edit-display-C_Aujldz.js +9 -0
  238. package/dist/client/assets/lane-observe-D0rfKDnU.js +7 -0
  239. package/dist/client/assets/lane-roster-store-D8x1jac2.js +1 -0
  240. package/dist/client/assets/lane-tool-detail-0WhMf4Vj.js +9 -0
  241. package/dist/client/assets/left-Bk3XnxPD.css +1 -0
  242. package/dist/client/assets/left-C--GiIh8.js +2 -0
  243. package/dist/client/assets/left-CAaRBK9S.css +1 -0
  244. package/dist/client/assets/left-CCoobxPS.css +1 -0
  245. package/dist/client/assets/left-Cj7Rt89X.js +1 -0
  246. package/dist/client/assets/left-CpNEtFEg.js +1 -0
  247. package/dist/client/assets/left-CzXAuK_t.js +2 -0
  248. package/dist/client/assets/left-agents-Bo9sO1by.js +1 -0
  249. package/dist/client/assets/left-bN4PCAXa.js +1 -0
  250. package/dist/client/assets/left-default-DV9GdvYi.js +1 -0
  251. package/dist/client/assets/left-jYYGAOYD.js +1 -0
  252. package/dist/client/assets/left-lanes-D0l_Co7V.js +1 -0
  253. package/dist/client/assets/left-mission-Ci7zREkQ.js +1 -0
  254. package/dist/client/assets/left-mission-DSenPIyb.css +1 -0
  255. package/dist/client/assets/left-plan-D4U1uflW.js +2 -0
  256. package/dist/client/assets/library-D-RxGiCw.js +1 -0
  257. package/dist/client/assets/loader-circle-CbHjZsz1.js +1 -0
  258. package/dist/client/assets/local-agents--00gLMqr.js +1 -0
  259. package/dist/client/assets/mentions-jSuTGeet.js +1 -0
  260. package/dist/client/assets/mesh-buckets-CfAukILK.js +1 -0
  261. package/dist/client/assets/mesh-screen-BSDUjrnV.css +1 -0
  262. package/dist/client/assets/mesh-view-store-CWidRbTE.js +1 -0
  263. package/dist/client/assets/message-circle-CG-96zts.js +1 -0
  264. package/dist/client/assets/message-markup-3J9pi3nx.js +15 -0
  265. package/dist/client/assets/message-square-DSaGpjFU.js +1 -0
  266. package/dist/client/assets/message-visibility-kJM8XcSG.js +1 -0
  267. package/dist/client/assets/mission-control-D3ikEPND.css +1 -0
  268. package/dist/client/assets/mission-control-model-C0fByIjm.js +1 -0
  269. package/dist/client/assets/mission-control-store-BlnEhiCq.js +1 -0
  270. package/dist/client/assets/model-Co0zkMIc.js +1 -0
  271. package/dist/client/assets/model-CpAxGuis.js +1 -0
  272. package/dist/client/assets/observe-CuLGD9Zp.js +1 -0
  273. package/dist/client/assets/openAgent-Bjt57GdM.js +1 -0
  274. package/dist/client/assets/openContent-C6XO6kr5.js +1 -0
  275. package/dist/client/assets/operator-attention-BwSPeheT.js +1 -0
  276. package/dist/client/assets/ops-agents-BOYxzPTm.css +1 -0
  277. package/dist/client/assets/ops-atop-BB4B4JdE.css +1 -0
  278. package/dist/client/assets/ops-screen-giu3If_N.css +1 -0
  279. package/dist/client/assets/page-status-DpkedE1F.js +1 -0
  280. package/dist/client/assets/page-status-bar-ByUD7VPM.css +1 -0
  281. package/dist/client/assets/plan-view-D56fneVF.css +1 -0
  282. package/dist/client/assets/plus--b1raV_O.js +1 -0
  283. package/dist/client/assets/profile-CVRziEDA.js +1 -0
  284. package/dist/client/assets/project-overview-helpers-BQTc_Ous.js +1 -0
  285. package/dist/client/assets/projects-inbox-CHyUFQ6w.js +1 -0
  286. package/dist/client/assets/projects-inbox-COZ23dLR.css +1 -0
  287. package/dist/client/assets/radio-Bz8ZePxj.js +1 -0
  288. package/dist/client/assets/refresh-cw-BBmAnCB7.js +1 -0
  289. package/dist/client/assets/repo-diff-C9Qs-bEn.css +1 -0
  290. package/dist/client/assets/resizable-columns-C7ygvLt8.css +1 -0
  291. package/dist/client/assets/resolve-panes-r9B3mpW7.js +1 -0
  292. package/dist/client/assets/resolve-sidebar-context-DcG8xGaB.js +1 -0
  293. package/dist/client/assets/right-BHeiIaty.js +1 -0
  294. package/dist/client/assets/right-BkgKo9VT.js +1 -0
  295. package/dist/client/assets/right-BpEU5jWE.js +1 -0
  296. package/dist/client/assets/right-CRZXoy-X.js +1 -0
  297. package/dist/client/assets/right-ChF_pbPy.js +1 -0
  298. package/dist/client/assets/right-DMoUT3KN.js +1 -0
  299. package/dist/client/assets/right-DjRXbnRP.js +2 -0
  300. package/dist/client/assets/right-T4Ue6EqM.js +1 -0
  301. package/dist/client/assets/right-wzrLXKur.js +1 -0
  302. package/dist/client/assets/rocket-BSNS_rLs.js +1 -0
  303. package/dist/client/assets/router-Bq5dwf78.js +1 -0
  304. package/dist/client/assets/runtime-picker-Bcl5iIX5.js +1 -0
  305. package/dist/client/assets/runtime-picker-vhm0gtLs.css +1 -0
  306. package/dist/client/assets/scope-views-4khCg2_z.css +1 -0
  307. package/dist/client/assets/scope-views-U-ucT9m0.js +1 -0
  308. package/dist/client/assets/scout-voice-CU5c0LGi.js +1 -0
  309. package/dist/client/assets/scoutbot-BTIErYHo.js +3 -0
  310. package/dist/client/assets/scroll-text-D6Pdnar7.js +1 -0
  311. package/dist/client/assets/search-CWfZtOt2.js +1 -0
  312. package/dist/client/assets/secondaryNavConfig-DqUIp0Es.js +1 -0
  313. package/dist/client/assets/secondaryNavConfig-xssF_ubT.css +1 -0
  314. package/dist/client/assets/selection-bridge-16pk1qyG.js +1 -0
  315. package/dist/client/assets/send-horizontal-Bg5-QggH.js +1 -0
  316. package/dist/client/assets/server-CPp4ZJhZ.js +1 -0
  317. package/dist/client/assets/session-catalog-BmoyVTJ_.js +1 -0
  318. package/dist/client/assets/session-table-DZcrKoIH.js +1 -0
  319. package/dist/client/assets/sessionRead-CvFz2RHv.js +1 -0
  320. package/dist/client/assets/sliders-horizontal-1oW76Xc9.js +1 -0
  321. package/dist/client/assets/sparkles-ClfRJQ6w.js +1 -0
  322. package/dist/client/assets/sse-CjIkKo46.js +1 -0
  323. package/dist/client/assets/status-tone-BM_zuRy1.js +1 -0
  324. package/dist/client/assets/surface-activity-B1rgWB1i.js +1 -0
  325. package/dist/client/assets/system-surfaces-redesign-CD26LFc0.css +1 -0
  326. package/dist/client/assets/tail-display-BdyoLvzY.js +2 -0
  327. package/dist/client/assets/tail-events-D19uAGe3.js +1 -0
  328. package/dist/client/assets/terminal-B9AOZQKR.js +1 -0
  329. package/dist/client/assets/terminal-relay-CWbJ1RCW.js +1 -0
  330. package/dist/client/assets/terminal-screen-19jAI0Cw.css +1 -0
  331. package/dist/client/assets/terminal-sessions-D5CIR2OL.js +1 -0
  332. package/dist/client/assets/terminal-takeover-B8UeD9OX.js +1 -0
  333. package/dist/client/assets/text-DsBWV_4k.js +1 -0
  334. package/dist/client/assets/time-DltNTpLl.js +1 -0
  335. package/dist/client/assets/types-B0PlfpKc.js +1 -0
  336. package/dist/client/assets/ui-LM8pS8qE.js +1 -0
  337. package/dist/client/assets/use-conversation-list-Byab41G6.js +1 -0
  338. package/dist/client/assets/use-fleet-active-asks-BIbQx5AS.js +1 -0
  339. package/dist/client/assets/use-reduced-motion-RRBkmVkk.js +1 -0
  340. package/dist/client/assets/useAgentHoverCard-DMrbBif0.js +1 -0
  341. package/dist/client/assets/useContentSecondaryNav-DMl1WNm7.js +1 -0
  342. package/dist/client/assets/usePierreRuntime-wC-yMtBb.js +50 -0
  343. package/dist/client/assets/voice-levels-Dcr3jglk.js +1 -0
  344. package/dist/client/assets/wrench-Bkc_0lKF.js +1 -0
  345. package/dist/client/assets/x-D3GElQbe.js +1 -0
  346. package/dist/client/assets/{xterm-6eL7V7pF.js → xterm-BKR8oAkR.js} +1 -1
  347. package/dist/client/index.html +6 -3
  348. package/dist/drizzle/0003_harsh_meltdown.sql +45 -0
  349. package/dist/drizzle/0004_medical_aaron_stack.sql +40 -0
  350. package/dist/drizzle/0005_wet_shriek.sql +57 -0
  351. package/dist/drizzle/0006_woozy_dark_beast.sql +1 -0
  352. package/dist/drizzle/README.md +7 -0
  353. package/dist/drizzle/meta/0003_snapshot.json +4952 -0
  354. package/dist/drizzle/meta/0004_snapshot.json +5235 -0
  355. package/dist/drizzle/meta/0005_snapshot.json +5599 -0
  356. package/dist/drizzle/meta/0006_snapshot.json +5606 -0
  357. package/dist/drizzle/meta/_journal.json +28 -0
  358. package/dist/main.mjs +24907 -12910
  359. package/dist/node/main.mjs +10212 -195
  360. package/dist/openscout-terminal-relay.mjs +507 -64
  361. package/dist/pairing-runtime-controller.mjs +10793 -5165
  362. package/dist/runtime/base-daemon.mjs +627 -159
  363. package/dist/runtime/broker-daemon.mjs +65039 -30990
  364. package/dist/runtime/broker-process-manager.mjs +247 -54
  365. package/dist/runtime/mesh-discover.mjs +246 -54
  366. package/dist/scout-control-plane-web.mjs +56699 -47427
  367. package/dist/scout-web-server.mjs +56699 -47427
  368. package/package.json +1 -1
  369. package/dist/client/assets/RepoDiffViewer-DLVleMPW.js +0 -56
  370. package/dist/client/assets/embed-entry-BdmREZuc.js +0 -1
  371. package/dist/client/assets/index-DPFmfHm5.js +0 -271
  372. package/dist/client/assets/index-jpYnsyHM.css +0 -1
@@ -2,7 +2,7 @@
2
2
  import { createServer } from "node:http";
3
3
  import { mkdir, writeFile } from "node:fs/promises";
4
4
  import { randomUUID } from "node:crypto";
5
- import { join as join6 } from "node:path";
5
+ import { join as join7 } from "node:path";
6
6
  import { createRequire as createRequire2 } from "node:module";
7
7
 
8
8
  // packages/web/server/relay.ts
@@ -15,6 +15,21 @@ function sanitizeUploadName(name) {
15
15
  return base;
16
16
  }
17
17
 
18
+ // packages/web/server/process-parent-watchdog.ts
19
+ function startProcessParentWatchdog(expectedParentPidRaw, options = {}) {
20
+ const expectedParentPid = Number.parseInt(expectedParentPidRaw?.trim() ?? "", 10);
21
+ if (!Number.isFinite(expectedParentPid) || expectedParentPid <= 0)
22
+ return null;
23
+ const parentPid = options.parentPid ?? (() => process.ppid);
24
+ const onOrphan = options.onOrphan ?? (() => process.kill(process.pid, "SIGTERM"));
25
+ const timer = setInterval(() => {
26
+ if (parentPid() !== expectedParentPid)
27
+ onOrphan();
28
+ }, options.intervalMs ?? 500);
29
+ timer.unref?.();
30
+ return timer;
31
+ }
32
+
18
33
  // packages/web/server/terminal-relay-session.ts
19
34
  import { createRequire } from "module";
20
35
 
@@ -533,7 +548,7 @@ var SCOUT_HOST_PROBE_SCHEMA_VERSIONS = {
533
548
  "git.mergeBase": 1,
534
549
  "git.logLastCommitUnix": 1,
535
550
  "git.worktreeListPorcelain": 1,
536
- "tmux.sessions": 1,
551
+ "tmux.sessions": 2,
537
552
  "tmux.panes": 1,
538
553
  "zellij.sessions": 1,
539
554
  "ps.runtime": 1,
@@ -2605,7 +2620,7 @@ function zellijSocketKey(input) {
2605
2620
  }
2606
2621
  function parseTmuxSessionList(output) {
2607
2622
  return output.split(/\r?\n/gu).map((line) => line.trim()).filter(Boolean).map((line) => {
2608
- const [name, windows, attached, createdAt, currentCommand, currentPath] = line.includes("|") ? splitDelimitedLine(line, "|", 6) : splitDelimitedLine(line, "\t", 6);
2623
+ const [name, windows, attached, createdAt, activityAt, currentCommand, currentPath] = line.includes("|") ? splitDelimitedLine(line, "|", 7) : splitDelimitedLine(line, "\t", 7);
2609
2624
  if (!name)
2610
2625
  return null;
2611
2626
  return {
@@ -2613,6 +2628,7 @@ function parseTmuxSessionList(output) {
2613
2628
  windows: parsePositiveInteger(windows, 1),
2614
2629
  attached: parsePositiveInteger(attached, 0),
2615
2630
  createdAt: createdAt ? Number.parseInt(createdAt, 10) || null : null,
2631
+ activityAt: activityAt ? Number.parseInt(activityAt, 10) || null : null,
2616
2632
  currentCommand: cleanOptionalString(currentCommand),
2617
2633
  currentPath: cleanOptionalString(currentPath)
2618
2634
  };
@@ -2639,7 +2655,7 @@ async function readTmuxSessionsLocal(key, ctx) {
2639
2655
  ...tmuxSocketArgs(key),
2640
2656
  "list-sessions",
2641
2657
  "-F",
2642
- "#{session_name}|#{session_windows}|#{session_attached}|#{session_created}|#{pane_current_command}|#{pane_current_path}"
2658
+ "#{session_name}|#{session_windows}|#{session_attached}|#{session_created}|#{session_activity}|#{pane_current_command}|#{pane_current_path}"
2643
2659
  ], {
2644
2660
  maxStdoutBytes: 512 * 1024,
2645
2661
  maxStderrBytes: 64 * 1024
@@ -2789,10 +2805,102 @@ async function readZellijSessionExists(sessionName, options = {}) {
2789
2805
  const snapshot = await zellijSessionsProbe.for({ env: options.env, socketDir: options.socketDir }).fresh({ maxAgeMs: options.maxAgeMs ?? TMUX_TTL_MS });
2790
2806
  return Boolean(snapshot.value?.some((session) => session.name === name));
2791
2807
  }
2808
+ // packages/runtime/dist/system-probes/herdr.js
2809
+ import { homedir as homedir3 } from "node:os";
2810
+ var HERDR_TTL_MS = 5000;
2811
+ var HERDR_TIMEOUT_MS = 2000;
2812
+ function herdrBin(env = process.env) {
2813
+ return env.OPENSCOUT_HERDR_BIN?.trim() || "herdr";
2814
+ }
2815
+ function herdrProbeTarget(env) {
2816
+ return {
2817
+ bin: herdrBin(env),
2818
+ path: env.PATH ?? "",
2819
+ home: env.XDG_CONFIG_HOME?.trim() || env.HOME?.trim() || homedir3()
2820
+ };
2821
+ }
2822
+ function parseHerdrProbeKey(key) {
2823
+ try {
2824
+ const parsed = JSON.parse(key);
2825
+ if (typeof parsed?.bin === "string" && typeof parsed.path === "string" && typeof parsed.home === "string") {
2826
+ return { bin: parsed.bin, path: parsed.path, home: parsed.home };
2827
+ }
2828
+ } catch {}
2829
+ return herdrProbeTarget(process.env);
2830
+ }
2831
+ function isUnavailable5(error) {
2832
+ return error instanceof ProbeCommandError && (error.code === "ENOENT" || error.code === "spawn" || error.code === "exit");
2833
+ }
2834
+ function herdrProbeKey(input) {
2835
+ if (typeof input === "string")
2836
+ return input.trim() || "default";
2837
+ return JSON.stringify(herdrProbeTarget(input?.env ?? process.env));
2838
+ }
2839
+ function parseHerdrSessionListJson(output) {
2840
+ const trimmed = output.trim();
2841
+ if (!trimmed)
2842
+ return [];
2843
+ let parsed;
2844
+ try {
2845
+ parsed = JSON.parse(trimmed);
2846
+ } catch {
2847
+ return [];
2848
+ }
2849
+ const sessions = Array.isArray(parsed) ? parsed : parsed && typeof parsed === "object" && Array.isArray(parsed.sessions) ? parsed.sessions : [];
2850
+ const out = [];
2851
+ for (const entry of sessions) {
2852
+ if (!entry || typeof entry !== "object")
2853
+ continue;
2854
+ const record = entry;
2855
+ const name = typeof record.name === "string" ? record.name.trim() : "";
2856
+ if (!name)
2857
+ continue;
2858
+ const isDefault = record.default === true || name === "default";
2859
+ const running = record.running === true;
2860
+ const sessionDir = typeof record.session_dir === "string" && record.session_dir.trim() ? record.session_dir.trim() : typeof record.sessionDir === "string" && record.sessionDir.trim() ? record.sessionDir.trim() : null;
2861
+ out.push({ name, isDefault, running, sessionDir });
2862
+ }
2863
+ return out;
2864
+ }
2865
+ async function readHerdrSessionsLocal(key, ctx) {
2866
+ const target = parseHerdrProbeKey(key);
2867
+ try {
2868
+ const { stdout } = await execProbeFile(ctx, target.bin, ["session", "list", "--json"], {
2869
+ env: { ...process.env, PATH: target.path, HOME: target.home, XDG_CONFIG_HOME: target.home },
2870
+ maxStdoutBytes: 512 * 1024,
2871
+ maxStderrBytes: 64 * 1024
2872
+ });
2873
+ return parseHerdrSessionListJson(stdout);
2874
+ } catch (error) {
2875
+ if (isUnavailable5(error))
2876
+ return [];
2877
+ throw error;
2878
+ }
2879
+ }
2880
+ var herdrSessionsProbe = defineProbeFamily({
2881
+ id: "herdr.sessions",
2882
+ ttlMs: HERDR_TTL_MS,
2883
+ timeoutMs: HERDR_TIMEOUT_MS,
2884
+ maxKeys: 8,
2885
+ idleKeyTtlMs: 5 * 60000,
2886
+ maxConcurrentKeys: 1,
2887
+ normalizeKey: herdrProbeKey,
2888
+ run: (key, ctx) => {
2889
+ if (key !== herdrProbeKey(process.env ? { env: process.env } : null)) {
2890
+ return readHerdrSessionsLocal(key, ctx).then((value) => probeRunOutput(value, { backend: "local" }));
2891
+ }
2892
+ return runWithScoutdFallback({
2893
+ probeId: "herdr.sessions",
2894
+ key,
2895
+ ctx,
2896
+ local: () => readHerdrSessionsLocal(key, ctx)
2897
+ });
2898
+ }
2899
+ });
2792
2900
  // packages/runtime/dist/system-probes/sessions.js
2793
2901
  import { createReadStream } from "node:fs";
2794
2902
  import { readdir, stat } from "node:fs/promises";
2795
- import { homedir as homedir3 } from "node:os";
2903
+ import { homedir as homedir4 } from "node:os";
2796
2904
  import { basename as basename2, dirname as dirname2, join as join4, resolve as resolve2 } from "node:path";
2797
2905
  import { createInterface } from "node:readline";
2798
2906
  function positiveInteger2(value, fallback, max) {
@@ -2800,7 +2908,7 @@ function positiveInteger2(value, fallback, max) {
2800
2908
  }
2801
2909
  function normalizeScanKey(input) {
2802
2910
  return {
2803
- home: resolve2(input.home?.trim() || homedir3()),
2911
+ home: resolve2(input.home?.trim() || homedir4()),
2804
2912
  workspaceRoot: input.workspaceRoot?.trim() ? resolve2(input.workspaceRoot) : null,
2805
2913
  maxAgeDays: positiveInteger2(input.maxAgeDays, 14, 3650),
2806
2914
  limit: positiveInteger2(input.limit, 250, 1e4)
@@ -3001,7 +3109,7 @@ function canonicalCertPath(path) {
3001
3109
  return resolve3(path);
3002
3110
  }
3003
3111
  }
3004
- function isUnavailable5(error) {
3112
+ function isUnavailable6(error) {
3005
3113
  return error instanceof ProbeCommandError && (error.code === "ENOENT" || error.code === "spawn" || error.code === "exit");
3006
3114
  }
3007
3115
  var certStatusProbe = defineProbeFamily({
@@ -3031,7 +3139,7 @@ var certStatusProbe = defineProbeFamily({
3031
3139
  });
3032
3140
  validAtLeast24h = true;
3033
3141
  } catch (error) {
3034
- if (!isUnavailable5(error)) {
3142
+ if (!isUnavailable6(error)) {
3035
3143
  throw error;
3036
3144
  }
3037
3145
  }
@@ -3045,7 +3153,7 @@ var certStatusProbe = defineProbeFamily({
3045
3153
  issuer = stdout.match(/^issuer=(.*)$/m)?.[1]?.trim() || null;
3046
3154
  subject = stdout.match(/^subject=(.*)$/m)?.[1]?.trim() || null;
3047
3155
  } catch (error) {
3048
- if (!isUnavailable5(error)) {
3156
+ if (!isUnavailable6(error)) {
3049
3157
  throw error;
3050
3158
  }
3051
3159
  }
@@ -3059,6 +3167,30 @@ var certStatusProbe = defineProbeFamily({
3059
3167
  };
3060
3168
  }
3061
3169
  });
3170
+ // packages/runtime/dist/terminal-environment.js
3171
+ var INHERITED_CLAUDE_SESSION_ENV_KEYS = [
3172
+ "CLAUDECODE",
3173
+ "CLAUDE_CODE_CHILD_SESSION",
3174
+ "CLAUDE_CODE_SESSION_ID",
3175
+ "CLAUDE_SESSION_ID",
3176
+ "CLAUDE_CODE_REMOTE",
3177
+ "CLAUDE_CODE_REMOTE_SESSION_ID",
3178
+ "CLAUDE_PID"
3179
+ ];
3180
+ function buildInteractiveTerminalEnvironment(base = process.env, overrides = {}) {
3181
+ const env = {
3182
+ ...base,
3183
+ ...overrides,
3184
+ COLORTERM: overrides.COLORTERM || base.COLORTERM || "truecolor",
3185
+ FORCE_COLOR: overrides.FORCE_COLOR || base.FORCE_COLOR || "1"
3186
+ };
3187
+ delete env.NO_COLOR;
3188
+ for (const key of INHERITED_CLAUDE_SESSION_ENV_KEYS) {
3189
+ delete env[key];
3190
+ }
3191
+ return env;
3192
+ }
3193
+
3062
3194
  // packages/web/server/terminal-relay-session.ts
3063
3195
  import { randomBytes, timingSafeEqual } from "crypto";
3064
3196
  import { existsSync as existsSync5, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, rmSync } from "fs";
@@ -3211,6 +3343,180 @@ function buildZellijAttachArgs({
3211
3343
  return args;
3212
3344
  }
3213
3345
 
3346
+ // packages/agent-sessions/dist/codex-executable.js
3347
+ import { execFileSync } from "node:child_process";
3348
+ import { accessSync, constants } from "node:fs";
3349
+ import { delimiter, join as join6 } from "node:path";
3350
+ function isExecutable(filePath) {
3351
+ if (!filePath)
3352
+ return false;
3353
+ if (filePath === "codex")
3354
+ return true;
3355
+ try {
3356
+ accessSync(filePath, constants.X_OK);
3357
+ return true;
3358
+ } catch {
3359
+ return false;
3360
+ }
3361
+ }
3362
+ function readCodexVersion(candidate) {
3363
+ if (!isExecutable(candidate)) {
3364
+ return { version: null, versionRaw: null };
3365
+ }
3366
+ try {
3367
+ const raw = execFileSync(candidate, ["--version"], {
3368
+ encoding: "utf8",
3369
+ stdio: ["ignore", "pipe", "ignore"],
3370
+ timeout: 3000
3371
+ }).trim();
3372
+ const version = raw.match(/\b(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)\b/)?.[1] ?? null;
3373
+ return { version, versionRaw: raw || null };
3374
+ } catch {
3375
+ return { version: null, versionRaw: null };
3376
+ }
3377
+ }
3378
+ function uniqueCandidates(candidates) {
3379
+ const seen = new Set;
3380
+ const unique = [];
3381
+ for (const candidate of candidates) {
3382
+ if (!candidate.path || seen.has(candidate.path))
3383
+ continue;
3384
+ seen.add(candidate.path);
3385
+ unique.push(candidate);
3386
+ }
3387
+ return unique;
3388
+ }
3389
+ function codexAppBundleCandidates(env) {
3390
+ const appNames = ["Codex.app", "ChatGPT.app"];
3391
+ const candidates = appNames.flatMap((appName) => [
3392
+ {
3393
+ path: join6("/Applications", appName, "Contents", "Resources", "codex"),
3394
+ source: "codex_app_bundle"
3395
+ },
3396
+ {
3397
+ path: join6(env.HOME ?? "", "Applications", appName, "Contents", "Resources", "codex"),
3398
+ source: "codex_app_bundle"
3399
+ }
3400
+ ]);
3401
+ return candidates.filter((candidate) => candidate.path.trim().length > 0);
3402
+ }
3403
+ function pathCandidates(env) {
3404
+ return (env.PATH ?? "").split(delimiter).filter(Boolean).map((directory) => ({
3405
+ path: join6(directory, "codex"),
3406
+ source: "path"
3407
+ }));
3408
+ }
3409
+ function commonCandidates(env) {
3410
+ return [
3411
+ `${env.HOME ?? ""}/.local/bin`,
3412
+ `${env.HOME ?? ""}/.bun/bin`,
3413
+ "/opt/homebrew/bin",
3414
+ "/usr/local/bin"
3415
+ ].filter(Boolean).map((directory) => ({
3416
+ path: join6(directory, "codex"),
3417
+ source: "common"
3418
+ }));
3419
+ }
3420
+ function resolveCodexExecutableCandidateInputs(env = process.env) {
3421
+ const explicit = [];
3422
+ if (env.OPENSCOUT_CODEX_BIN) {
3423
+ explicit.push({ path: env.OPENSCOUT_CODEX_BIN, source: "env:OPENSCOUT_CODEX_BIN" });
3424
+ }
3425
+ if (env.CODEX_BIN) {
3426
+ explicit.push({ path: env.CODEX_BIN, source: "env:CODEX_BIN" });
3427
+ }
3428
+ return uniqueCandidates([
3429
+ ...explicit,
3430
+ ...codexAppBundleCandidates(env),
3431
+ ...pathCandidates(env),
3432
+ ...commonCandidates(env),
3433
+ { path: "codex", source: "fallback" }
3434
+ ]);
3435
+ }
3436
+ function parseVersion(value) {
3437
+ if (!value)
3438
+ return null;
3439
+ const match = value.match(/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/);
3440
+ if (!match)
3441
+ return null;
3442
+ return {
3443
+ major: Number(match[1]),
3444
+ minor: Number(match[2]),
3445
+ patch: Number(match[3]),
3446
+ prerelease: match[4] ?? null
3447
+ };
3448
+ }
3449
+ function compareVersions(left, right) {
3450
+ const lhs = parseVersion(left);
3451
+ const rhs = parseVersion(right);
3452
+ if (!lhs && !rhs)
3453
+ return 0;
3454
+ if (!lhs)
3455
+ return -1;
3456
+ if (!rhs)
3457
+ return 1;
3458
+ for (const key of ["major", "minor", "patch"]) {
3459
+ if (lhs[key] !== rhs[key]) {
3460
+ return lhs[key] - rhs[key];
3461
+ }
3462
+ }
3463
+ if (lhs.prerelease === rhs.prerelease)
3464
+ return 0;
3465
+ if (!lhs.prerelease)
3466
+ return 1;
3467
+ if (!rhs.prerelease)
3468
+ return -1;
3469
+ return lhs.prerelease.localeCompare(rhs.prerelease);
3470
+ }
3471
+ function sourceRank(source) {
3472
+ switch (source) {
3473
+ case "env:OPENSCOUT_CODEX_BIN":
3474
+ return 0;
3475
+ case "env:CODEX_BIN":
3476
+ return 1;
3477
+ case "codex_app_bundle":
3478
+ return 2;
3479
+ case "path":
3480
+ return 3;
3481
+ case "common":
3482
+ return 4;
3483
+ case "fallback":
3484
+ return 5;
3485
+ }
3486
+ }
3487
+ function selectCodexCandidate(candidates) {
3488
+ const executable = candidates.filter((candidate) => candidate.executable);
3489
+ if (executable.length === 0)
3490
+ return null;
3491
+ const explicit = executable.find((candidate) => candidate.source === "env:OPENSCOUT_CODEX_BIN" || candidate.source === "env:CODEX_BIN");
3492
+ if (explicit)
3493
+ return explicit;
3494
+ return executable.slice().sort((left, right) => {
3495
+ const versionComparison = compareVersions(right.version, left.version);
3496
+ if (versionComparison !== 0)
3497
+ return versionComparison;
3498
+ return sourceRank(left.source) - sourceRank(right.source);
3499
+ })[0] ?? null;
3500
+ }
3501
+ function resolveCodexExecutableInventory(env = process.env) {
3502
+ const candidates = resolveCodexExecutableCandidateInputs(env).map((candidate) => {
3503
+ const executable = isExecutable(candidate.path);
3504
+ const version = readCodexVersion(candidate.path);
3505
+ return {
3506
+ ...candidate,
3507
+ executable,
3508
+ version: version.version,
3509
+ versionRaw: version.versionRaw
3510
+ };
3511
+ });
3512
+ const selected = selectCodexCandidate(candidates);
3513
+ return {
3514
+ selectedPath: selected?.path ?? "codex",
3515
+ selected,
3516
+ candidates
3517
+ };
3518
+ }
3519
+
3214
3520
  // packages/web/server/terminal-relay-session.ts
3215
3521
  var require2 = createRequire(import.meta.url);
3216
3522
  var pty = (() => {
@@ -3239,7 +3545,7 @@ function verifyReconnectToken(session, token) {
3239
3545
  return false;
3240
3546
  return timingSafeEqual(expected, supplied);
3241
3547
  }
3242
- var MULTIPLEXER_NAME_RE = /^[A-Za-z0-9_][A-Za-z0-9_-]{0,63}$/;
3548
+ var MULTIPLEXER_NAME_RE = /^[A-Za-z0-9_][A-Za-z0-9_-]*$/;
3243
3549
  function isValidMultiplexerName(name) {
3244
3550
  return MULTIPLEXER_NAME_RE.test(name);
3245
3551
  }
@@ -3311,18 +3617,31 @@ function writeSession(session, data) {
3311
3617
  throw err;
3312
3618
  }
3313
3619
  }
3314
- function resizeSession(session, cols, rows) {
3620
+ async function resizeSession(session, cols, rows) {
3315
3621
  if (session.exited)
3316
3622
  return false;
3317
- if (session.controlMode === "observe" && session.backend !== "zellij")
3623
+ let acceptedCols = cols;
3624
+ let acceptedRows = rows;
3625
+ if (session.controlMode === "observe" && session.backend === "tmux" && session.tmuxSession) {
3626
+ const source = await readTmuxDimensions(session.tmuxSession);
3627
+ const accepted = clampObserverDimensions({ cols, rows }, source);
3628
+ acceptedCols = accepted.cols;
3629
+ acceptedRows = accepted.rows;
3630
+ session.tmuxSourceCols = source.cols;
3631
+ session.tmuxSourceRows = source.rows;
3632
+ } else if (session.controlMode === "observe" && session.backend !== "zellij") {
3318
3633
  return false;
3634
+ }
3319
3635
  try {
3320
- session.pty.resize(cols, rows);
3636
+ session.pty.resize(acceptedCols, acceptedRows);
3321
3637
  if (session.backend === "tmux" && session.tmuxSession) {
3322
- resizeTmuxWindow(session.tmuxSession, cols, rows);
3638
+ if (session.controlMode !== "observe") {
3639
+ await resizeTmuxWindow(session.tmuxSession, acceptedCols, acceptedRows);
3640
+ }
3323
3641
  }
3324
- session.cols = cols;
3325
- session.rows = rows;
3642
+ session.cols = acceptedCols;
3643
+ session.rows = acceptedRows;
3644
+ send(session.ws, { type: "terminal:dimensions", cols: acceptedCols, rows: acceptedRows });
3326
3645
  return true;
3327
3646
  } catch (err) {
3328
3647
  if (ptyFdClosed(err)) {
@@ -3410,6 +3729,14 @@ async function findClaudeBin() {
3410
3729
  async function findPiBin() {
3411
3730
  return findBin("pi", "PI_BIN");
3412
3731
  }
3732
+ async function findCodexBin() {
3733
+ const selected = resolveCodexExecutableInventory().selected;
3734
+ if (!selected?.executable)
3735
+ return null;
3736
+ if (selected.path === "codex")
3737
+ return findBin("codex", "CODEX_BIN");
3738
+ return selected.path;
3739
+ }
3413
3740
  async function findShellBin() {
3414
3741
  const configured = process.env.SHELL;
3415
3742
  if (configured && existsSync5(configured))
@@ -3451,6 +3778,26 @@ async function resizeTmuxWindow(name, cols, rows) {
3451
3778
  return false;
3452
3779
  }
3453
3780
  }
3781
+ function clampObserverDimensions(requested, source) {
3782
+ return {
3783
+ cols: Math.max(1, Math.min(requested.cols, source.cols)),
3784
+ rows: Math.max(1, Math.min(requested.rows, source.rows))
3785
+ };
3786
+ }
3787
+ async function readTmuxDimensions(name) {
3788
+ const result = await execSystemFile("tmux", [
3789
+ "display-message",
3790
+ "-p",
3791
+ "-t",
3792
+ name,
3793
+ "#{window_width} #{window_height}"
3794
+ ], { timeoutMs: 2000 });
3795
+ const match = /^(\d+)\s+(\d+)$/.exec(result.stdout.trim());
3796
+ if (!match) {
3797
+ throw new Error(`Could not read terminal dimensions for tmux session '${name}'`);
3798
+ }
3799
+ return { cols: Number(match[1]), rows: Number(match[2]) };
3800
+ }
3454
3801
  function resolveBootstrapPath(cwd, relPath) {
3455
3802
  const base = pathResolve(cwd);
3456
3803
  const absPath = pathResolve(base, relPath);
@@ -3478,8 +3825,28 @@ function bootstrapFiles(cwd, files, sessionId) {
3478
3825
  }
3479
3826
  }
3480
3827
  }
3828
+ function buildTmuxAttachArgs(tmuxName, controlMode) {
3829
+ return controlMode === "observe" ? ["-u", "attach", "-r", "-t", tmuxName] : ["-u", "attach", "-t", tmuxName];
3830
+ }
3831
+ function bufferPtyOutput(ptyProcess) {
3832
+ const pending = [];
3833
+ let handler = null;
3834
+ ptyProcess.onData((data) => {
3835
+ if (handler)
3836
+ handler(data);
3837
+ else
3838
+ pending.push(data);
3839
+ });
3840
+ return (nextHandler) => {
3841
+ handler = nextHandler;
3842
+ for (const data of pending.splice(0))
3843
+ nextHandler(data);
3844
+ };
3845
+ }
3481
3846
  async function spawnTmuxSession(tmuxName, cols, rows, cwd, commandBin, commandArgs, env, controlMode) {
3482
3847
  const exists = await tmuxSessionExists(tmuxName);
3848
+ let dimensions = { cols, rows };
3849
+ let sourceDimensions;
3483
3850
  if (!exists) {
3484
3851
  if (controlMode === "observe") {
3485
3852
  throw new Error(`tmux session '${tmuxName}' does not exist`);
@@ -3508,14 +3875,19 @@ async function spawnTmuxSession(tmuxName, cols, rows, cwd, commandBin, commandAr
3508
3875
  }
3509
3876
  console.log(`[relay] Attaching to existing tmux session: ${tmuxName}${controlMode === "observe" ? " (observe)" : ""}`);
3510
3877
  markMuxSessionInUse("tmux", tmuxName);
3878
+ if (controlMode === "observe") {
3879
+ sourceDimensions = await readTmuxDimensions(tmuxName);
3880
+ dimensions = clampObserverDimensions(dimensions, sourceDimensions);
3881
+ }
3511
3882
  }
3512
- return pty.spawn("tmux", ["attach", "-t", tmuxName], {
3883
+ const ptyProcess = pty.spawn("tmux", buildTmuxAttachArgs(tmuxName, controlMode), {
3513
3884
  name: "xterm-256color",
3514
- cols,
3515
- rows,
3885
+ cols: dimensions.cols,
3886
+ rows: dimensions.rows,
3516
3887
  cwd,
3517
3888
  env
3518
3889
  });
3890
+ return { ptyProcess, attachOutput: bufferPtyOutput(ptyProcess), dimensions, sourceDimensions };
3519
3891
  }
3520
3892
  function spawnZellijSession(zellijBin2, zellijName, cols, rows, cwd, commandBin, commandArgs, env, controlMode) {
3521
3893
  const layoutPath = controlMode === "observe" ? undefined : createZellijLayoutFile({ cwd, commandBin, commandArgs });
@@ -3538,22 +3910,34 @@ function spawnZellijSession(zellijBin2, zellijName, cols, rows, cwd, commandBin,
3538
3910
  }
3539
3911
  async function createSession(ws, msg) {
3540
3912
  const id = generateId();
3541
- const cols = Math.max(msg.cols || 80, 20);
3542
- const rows = Math.max(msg.rows || 24, 4);
3913
+ let cols = Math.max(msg.cols || 80, 20);
3914
+ let rows = Math.max(msg.rows || 24, 4);
3543
3915
  const backend = msg.backend || "pty";
3544
3916
  const controlMode = msg.controlMode || "owner";
3545
3917
  const tmuxName = msg.tmuxSession || `hudson-${id}`;
3546
3918
  const zellijName = msg.zellijSession || `hudson-${id}`;
3919
+ const herdrName = msg.herdrSession || msg.tmuxSession || `scout-herdr-${id}`;
3547
3920
  const agent = msg.agent || "claude";
3548
- const multiplexerName = backend === "tmux" ? tmuxName : backend === "zellij" ? zellijName : null;
3921
+ const multiplexerName = backend === "tmux" ? tmuxName : backend === "zellij" ? zellijName : backend === "herdr" ? herdrName : null;
3549
3922
  if (multiplexerName && !isValidMultiplexerName(multiplexerName)) {
3550
- const reason = `Invalid ${backend} session name. Use letters, digits, dashes, and underscores (max 64 chars).`;
3923
+ const reason = `Invalid ${backend} session name. Use only letters, digits, dashes, and underscores.`;
3551
3924
  console.error(`[relay] Session ${id} failed: ${reason}`);
3552
3925
  send(ws, { type: "session:error", error: reason });
3553
3926
  return null;
3554
3927
  }
3555
- let agentBin;
3556
- if (agent === "shell") {
3928
+ let agentBin = null;
3929
+ let agentArgs = [];
3930
+ const herdrBin2 = backend === "herdr" ? await findBin("herdr", "OPENSCOUT_HERDR_BIN") : null;
3931
+ if (backend === "herdr") {
3932
+ if (!herdrBin2) {
3933
+ const reason = "herdr not found. Install it from https://herdr.dev/docs/install/";
3934
+ console.error(`[relay] Session ${id} failed: ${reason}`);
3935
+ send(ws, { type: "session:error", error: reason });
3936
+ return null;
3937
+ }
3938
+ agentBin = herdrBin2;
3939
+ agentArgs = !herdrName || herdrName === "default" ? [] : ["--session", herdrName];
3940
+ } else if (agent === "shell") {
3557
3941
  agentBin = await findShellBin();
3558
3942
  if (!agentBin) {
3559
3943
  const reason = "No login shell found. Set SHELL or install zsh, bash, or sh.";
@@ -3561,6 +3945,14 @@ async function createSession(ws, msg) {
3561
3945
  send(ws, { type: "session:error", error: reason });
3562
3946
  return null;
3563
3947
  }
3948
+ } else if (agent === "codex") {
3949
+ agentBin = await findCodexBin();
3950
+ if (!agentBin) {
3951
+ const reason = "Codex CLI not found. Install it with: npm install -g @openai/codex";
3952
+ console.error(`[relay] Session ${id} failed: ${reason}`);
3953
+ send(ws, { type: "session:error", error: reason });
3954
+ return null;
3955
+ }
3564
3956
  } else if (agent === "pi") {
3565
3957
  agentBin = await findPiBin();
3566
3958
  if (!agentBin) {
@@ -3578,8 +3970,8 @@ async function createSession(ws, msg) {
3578
3970
  return null;
3579
3971
  }
3580
3972
  }
3581
- if (!existsSync5(agentBin)) {
3582
- const reason = `${agent} binary not found at ${agentBin}`;
3973
+ if (!agentBin || !existsSync5(agentBin)) {
3974
+ const reason = `${backend === "herdr" ? "herdr" : agent} binary not found${agentBin ? ` at ${agentBin}` : ""}`;
3583
3975
  console.error(`[relay] Session ${id} failed: ${reason}`);
3584
3976
  send(ws, { type: "session:error", error: reason });
3585
3977
  return null;
@@ -3601,37 +3993,44 @@ async function createSession(ws, msg) {
3601
3993
  if (msg.workspaceFiles) {
3602
3994
  bootstrapFiles(cwd, msg.workspaceFiles, id);
3603
3995
  }
3604
- let agentArgs;
3605
- if (agent === "shell") {
3606
- const shellName = agentBin.split("/").pop() ?? "";
3607
- agentArgs = shellName === "sh" ? [] : ["-l"];
3608
- } else if (agent === "pi") {
3609
- agentArgs = ["--verbose"];
3610
- const provider = normalizePiProviderForCli(msg.provider);
3611
- if (provider)
3612
- agentArgs.push("--provider", provider);
3613
- if (msg.model)
3614
- agentArgs.push("--model", msg.model);
3615
- if (msg.systemPrompt)
3616
- agentArgs.push("--system-prompt", msg.systemPrompt);
3617
- } else {
3618
- agentArgs = ["--verbose"];
3619
- if (msg.systemPrompt)
3620
- agentArgs.push("--system-prompt", msg.systemPrompt);
3996
+ if (backend !== "herdr") {
3997
+ if (agent === "shell") {
3998
+ const shellName = agentBin.split("/").pop() ?? "";
3999
+ agentArgs = shellName === "sh" ? [] : ["-l"];
4000
+ } else if (agent === "codex") {
4001
+ agentArgs = [];
4002
+ } else if (agent === "pi") {
4003
+ agentArgs = ["--verbose"];
4004
+ const provider = normalizePiProviderForCli(msg.provider);
4005
+ if (provider)
4006
+ agentArgs.push("--provider", provider);
4007
+ if (msg.model)
4008
+ agentArgs.push("--model", msg.model);
4009
+ if (msg.systemPrompt)
4010
+ agentArgs.push("--system-prompt", msg.systemPrompt);
4011
+ } else {
4012
+ agentArgs = ["--verbose"];
4013
+ if (msg.systemPrompt)
4014
+ agentArgs.push("--system-prompt", msg.systemPrompt);
4015
+ }
3621
4016
  }
3622
- const env = {
3623
- ...process.env,
4017
+ const env = buildInteractiveTerminalEnvironment(process.env, {
3624
4018
  ...prepareZellijSocketDir(backend === "zellij" ? msg.zellijSocketDir : undefined),
3625
- TERM: "xterm-256color",
3626
- FORCE_COLOR: "1"
3627
- };
3628
- delete env.CLAUDECODE;
4019
+ TERM: "xterm-256color"
4020
+ });
3629
4021
  let ptyProcess;
4022
+ let attachPtyOutput = null;
3630
4023
  let zellijLayoutPath;
4024
+ let tmuxSourceDimensions;
3631
4025
  try {
3632
4026
  if (backend === "tmux") {
3633
4027
  console.log(`[relay] Session ${id}: tmux backend (session: ${tmuxName}) in ${cwd} [agent: ${agent}]`);
3634
- ptyProcess = await spawnTmuxSession(tmuxName, cols, rows, cwd, agentBin, agentArgs, env, controlMode);
4028
+ const spawned = await spawnTmuxSession(tmuxName, cols, rows, cwd, agentBin, agentArgs, env, controlMode);
4029
+ ptyProcess = spawned.ptyProcess;
4030
+ attachPtyOutput = spawned.attachOutput;
4031
+ cols = spawned.dimensions.cols;
4032
+ rows = spawned.dimensions.rows;
4033
+ tmuxSourceDimensions = spawned.sourceDimensions;
3635
4034
  } else if (backend === "zellij") {
3636
4035
  console.log(`[relay] Session ${id}: zellij backend (session: ${zellijName}, mode: ${controlMode}) in ${cwd} [agent: ${agent}]`);
3637
4036
  const trackZellij = muxTtlMs() > 0 && controlMode !== "observe" && !await zellijSessionExists(zellijBin2, zellijName, env);
@@ -3642,6 +4041,15 @@ async function createSession(ws, msg) {
3642
4041
  trackCreatedMuxSession("zellij", zellijName);
3643
4042
  else
3644
4043
  markMuxSessionInUse("zellij", zellijName);
4044
+ } else if (backend === "herdr") {
4045
+ console.log(`[relay] Session ${id}: herdr backend (session: ${herdrName}) in ${cwd}`);
4046
+ ptyProcess = pty.spawn(agentBin, agentArgs, {
4047
+ name: "xterm-256color",
4048
+ cols,
4049
+ rows,
4050
+ cwd,
4051
+ env
4052
+ });
3645
4053
  } else {
3646
4054
  console.log(`[relay] Session ${id}: pty backend, spawning ${agentBin} in ${cwd} [agent: ${agent}]`);
3647
4055
  ptyProcess = pty.spawn(agentBin, agentArgs, {
@@ -3672,21 +4080,33 @@ async function createSession(ws, msg) {
3672
4080
  backend,
3673
4081
  controlMode,
3674
4082
  ...backend === "tmux" ? { tmuxSession: tmuxName } : {},
4083
+ ...tmuxSourceDimensions ? {
4084
+ tmuxSourceCols: tmuxSourceDimensions.cols,
4085
+ tmuxSourceRows: tmuxSourceDimensions.rows
4086
+ } : {},
3675
4087
  ...backend === "zellij" ? {
3676
4088
  zellijSession: zellijName,
3677
4089
  ...msg.zellijSocketDir ? { zellijSocketDir: msg.zellijSocketDir } : {},
3678
4090
  ...zellijLayoutPath ? { zellijLayoutPath } : {}
3679
4091
  } : {},
4092
+ ...backend === "herdr" ? { herdrSession: herdrName } : {},
3680
4093
  flowControl: createTerminalFlowControlState(),
3681
4094
  flowControlEnabled: clientSupportsAck(msg.clientCapabilities),
3682
4095
  exited: false,
3683
4096
  exitCode: null
3684
4097
  };
3685
4098
  const startTime = Date.now();
3686
- ptyProcess.onData((data) => {
3687
- session.outputBuffer = truncateOutputBuffer(session.outputBuffer + data, MAX_BUFFER_SIZE);
4099
+ const handlePtyData = (data) => {
4100
+ if (session.controlMode !== "observe") {
4101
+ session.outputBuffer = truncateOutputBuffer(session.outputBuffer + data, MAX_BUFFER_SIZE);
4102
+ }
3688
4103
  sendTerminalOutput(session, data);
3689
- });
4104
+ };
4105
+ send(ws, { type: "terminal:dimensions", cols, rows });
4106
+ if (attachPtyOutput)
4107
+ attachPtyOutput(handlePtyData);
4108
+ else
4109
+ ptyProcess.onData(handlePtyData);
3690
4110
  ptyProcess.onExit(({ exitCode }) => {
3691
4111
  session.exited = true;
3692
4112
  session.exitCode = exitCode;
@@ -3710,7 +4130,7 @@ async function createSession(ws, msg) {
3710
4130
  console.log(`[relay] Session ${id} created (${cols}x${rows})`);
3711
4131
  return session;
3712
4132
  }
3713
- function attachSession(session, ws, cols, rows, clientCapabilities) {
4133
+ async function attachSession(session, ws, cols, rows, clientCapabilities) {
3714
4134
  if (session.reapTimer) {
3715
4135
  clearTimeout(session.reapTimer);
3716
4136
  session.reapTimer = null;
@@ -3722,7 +4142,7 @@ function attachSession(session, ws, cols, rows, clientCapabilities) {
3722
4142
  const c = Math.max(cols, 20);
3723
4143
  const r = Math.max(rows, 4);
3724
4144
  if (c !== session.cols || r !== session.rows) {
3725
- resizeSession(session, c, r);
4145
+ await resizeSession(session, c, r);
3726
4146
  }
3727
4147
  }
3728
4148
  if (session.exited) {
@@ -3778,6 +4198,8 @@ function destroy(sessionId) {
3778
4198
  console.log(`[relay] Session ${sessionId} bridge destroyed (zellij session '${session.zellijSession}' still alive)`);
3779
4199
  if (session.zellijSession)
3780
4200
  markMuxSessionDetached("zellij", session.zellijSession);
4201
+ } else if (session.backend === "herdr") {
4202
+ console.log(`[relay] Session ${sessionId} bridge destroyed (herdr session '${session.herdrSession}' still alive)`);
3781
4203
  } else {
3782
4204
  console.log(`[relay] Session ${sessionId} destroyed`);
3783
4205
  }
@@ -3810,6 +4232,7 @@ var require3 = createRequire2(import.meta.url);
3810
4232
  var { WebSocketServer } = require3("ws");
3811
4233
  var hostname = process.env.OPENSCOUT_WEB_TERMINAL_RELAY_HOST?.trim() || "127.0.0.1";
3812
4234
  var port = Number.parseInt(process.env.OPENSCOUT_WEB_TERMINAL_RELAY_PORT?.trim() || "3201", 10);
4235
+ var parentWatchdog = startProcessParentWatchdog(process.env.OPENSCOUT_WEB_RELAY_PARENT_PID);
3813
4236
  var UPLOAD_DIR = "/tmp/scout-uploads";
3814
4237
  var OUTPUT_BATCH_INTERVAL_MS = 8;
3815
4238
  var OUTPUT_BATCH_DRAIN_CONTINUE_MS = 1;
@@ -3969,7 +4392,7 @@ class FlowControlledRelaySocket {
3969
4392
  function sessionMatchesSurface(session, backend, sessionName) {
3970
4393
  if (!backend || !sessionName || session.backend !== backend)
3971
4394
  return false;
3972
- return session.terminalSession === sessionName || session.tmuxSession === sessionName || session.zellijSession === sessionName;
4395
+ return session.tmuxSession === sessionName || session.zellijSession === sessionName;
3973
4396
  }
3974
4397
  var pendingCommand = null;
3975
4398
  function queueTerminalCommand(input) {
@@ -4058,7 +4481,7 @@ var server = createServer(async (req, res) => {
4058
4481
  return;
4059
4482
  }
4060
4483
  await mkdir(UPLOAD_DIR, { recursive: true, mode: 448 });
4061
- const filepath = join6(UPLOAD_DIR, `${randomUUID()}-${safeName}`);
4484
+ const filepath = join7(UPLOAD_DIR, `${randomUUID()}-${safeName}`);
4062
4485
  await writeFile(filepath, Buffer.from(body.data, "base64"), { mode: 384 });
4063
4486
  writeJson(res, 200, { path: filepath });
4064
4487
  return;
@@ -4143,7 +4566,13 @@ wss.on("connection", (ws) => {
4143
4566
  }
4144
4567
  relaySocket.bindSession(session);
4145
4568
  sessionId = session.id;
4146
- send(ws, { type: "session:ready", sessionId: session.id, reconnectToken: session.reconnectToken });
4569
+ send(ws, {
4570
+ type: "session:ready",
4571
+ sessionId: session.id,
4572
+ reconnectToken: session.reconnectToken,
4573
+ cols: session.cols,
4574
+ rows: session.rows
4575
+ });
4147
4576
  if (pending) {
4148
4577
  setTimeout(() => writeSession(session, pending.command + `
4149
4578
  `), 400);
@@ -4172,14 +4601,20 @@ wss.on("connection", (ws) => {
4172
4601
  }
4173
4602
  relaySocket.bindSession(session);
4174
4603
  sessionId = session.id;
4175
- send(ws, { type: "session:ready", sessionId: session.id, reconnectToken: session.reconnectToken });
4604
+ send(ws, {
4605
+ type: "session:ready",
4606
+ sessionId: session.id,
4607
+ reconnectToken: session.reconnectToken,
4608
+ cols: session.cols,
4609
+ rows: session.rows
4610
+ });
4176
4611
  setTimeout(() => writeSession(session, pending.command + `
4177
4612
  `), 400);
4178
4613
  break;
4179
4614
  }
4180
4615
  const existing = sessions2.get(msg.sessionId);
4181
4616
  const requestedControlMode = msg.controlMode || "owner";
4182
- const canReconnect = existing && !existing.exited && existing.controlMode === requestedControlMode && verifyReconnectToken(existing, msg.reconnectToken);
4617
+ const canReconnect = existing && !existing.exited && existing.controlMode !== "observe" && existing.controlMode === requestedControlMode && verifyReconnectToken(existing, msg.reconnectToken);
4183
4618
  if (canReconnect) {
4184
4619
  if (sessionId && sessionId !== msg.sessionId) {
4185
4620
  const previous = sessions2.get(sessionId);
@@ -4192,12 +4627,14 @@ wss.on("connection", (ws) => {
4192
4627
  }
4193
4628
  sessionId = existing.id;
4194
4629
  relaySocket.bindSession(existing);
4195
- attachSession(existing, relaySocket, msg.cols, msg.rows, []);
4630
+ await attachSession(existing, relaySocket, msg.cols, msg.rows, []);
4196
4631
  send(ws, {
4197
4632
  type: "session:ready",
4198
4633
  sessionId: existing.id,
4199
4634
  reconnectToken: existing.reconnectToken,
4200
- reconnected: true
4635
+ reconnected: true,
4636
+ cols: existing.cols,
4637
+ rows: existing.rows
4201
4638
  });
4202
4639
  if (pending) {
4203
4640
  setTimeout(() => writeSession(existing, pending.command + `
@@ -4230,7 +4667,7 @@ wss.on("connection", (ws) => {
4230
4667
  if (session && sessionOwnsSocket(session, relaySocket)) {
4231
4668
  const cols = Math.max(msg.cols || 80, 20);
4232
4669
  const rows = Math.max(msg.rows || 24, 4);
4233
- resizeSession(session, cols, rows);
4670
+ await resizeSession(session, cols, rows);
4234
4671
  }
4235
4672
  break;
4236
4673
  }
@@ -4266,7 +4703,13 @@ wss.on("connection", (ws) => {
4266
4703
  server.listen(port, hostname, () => {
4267
4704
  console.log(`[relay] Server listening on http://${hostname}:${port} (HTTP + WebSocket)`);
4268
4705
  });
4706
+ var shuttingDown = false;
4269
4707
  var shutdown = () => {
4708
+ if (shuttingDown)
4709
+ return;
4710
+ shuttingDown = true;
4711
+ if (parentWatchdog)
4712
+ clearInterval(parentWatchdog);
4270
4713
  console.log(`
4271
4714
  [relay] Shutting down...`);
4272
4715
  for (const [id] of sessions2) {