@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.
- package/README.md +41 -2
- package/bin/openscout-runtime.mjs +48 -30
- package/bin/scout.mjs +2 -2
- package/bin/scoutd +0 -0
- package/dist/build-manifest.json +3 -3
- package/dist/client/assets/ActivityScreen-Cu_1V4bq.js +1 -0
- package/dist/client/assets/AddProjectForm-DMnobKch.js +1 -0
- package/dist/client/assets/AgentAvatar-D90c1Rzk.js +1 -0
- package/dist/client/assets/AgentConfigurationScreen-BqfOz90D.js +1 -0
- package/dist/client/assets/AgentDefinitionsWorkspace-CUpUrY57.js +1 -0
- package/dist/client/assets/AgentDetailCard-BcRBRp88.js +1 -0
- package/dist/client/assets/AgentDetailCard-C4WVeJvJ.css +1 -0
- package/dist/client/assets/AgentFloorView-8LoAEBwS.js +1 -0
- package/dist/client/assets/AgentInfoScreen-DZs2_ibL.js +1 -0
- package/dist/client/assets/AgentLaneCard-RrNnDZu8.js +1 -0
- package/dist/client/assets/AgentLaneChrome-D9ZwUKrl.js +1 -0
- package/dist/client/assets/AgentLaneDetailSheet-BXbPls9N.js +5 -0
- package/dist/client/assets/AgentLaneSummaryResize-BhFmGNzT.js +1 -0
- package/dist/client/assets/AgentLanesEmbedScreen-W3qs022h.js +1 -0
- package/dist/client/assets/AgentLanesPreflight-eSAoDsPi.js +1 -0
- package/dist/client/assets/AgentLanesView-B9vuEEmZ.js +2 -0
- package/dist/client/assets/AgentLiveActions-CGS-Bxb7.css +1 -0
- package/dist/client/assets/AgentLiveActions-DBtnD0qE.js +1 -0
- package/dist/client/assets/AgentSessions-DyqOf4nG.js +6 -0
- package/dist/client/assets/AgentsConsole-BgiYP2wR.js +1 -0
- package/dist/client/assets/AgentsConsole-BjSTs-TV.css +1 -0
- package/dist/client/assets/AgentsScreen-DBi8x4MB.js +1 -0
- package/dist/client/assets/AgentsSubnav-DIEO4NPx.js +1 -0
- package/dist/client/assets/AtopView-BCkae3e1.js +1 -0
- package/dist/client/assets/BackToPicker-BRvfostO.js +1 -0
- package/dist/client/assets/BackToPicker-CdgVu-to.css +1 -0
- package/dist/client/assets/BriefingDetailScreen-BwFyysT8.js +6 -0
- package/dist/client/assets/BriefingsScreen-BQEevztH.js +1 -0
- package/dist/client/assets/BrokerMetadataPanel-7UjcuNjd.js +1 -0
- package/dist/client/assets/BrokerScreen-7ekklu88.js +5 -0
- package/dist/client/assets/ChatCollapsedStrip-CQSYSd8s.js +1 -0
- package/dist/client/assets/CodeDiffPane-DDPt6KPh.js +1 -0
- package/dist/client/assets/CodeProjectPicker-DqKFCpLU.js +2 -0
- package/dist/client/assets/CodeScreen-BxCrpRHd.js +1 -0
- package/dist/client/assets/ContextMenu-bARZqTzD.js +1 -0
- package/dist/client/assets/ConversationComposer-Bla3DDvM.js +1 -0
- package/dist/client/assets/ConversationFeedRows-B_gPxcqA.js +1 -0
- package/dist/client/assets/ConversationHeader-DE3FC0m-.js +1 -0
- package/dist/client/assets/ConversationPanels-DLek4H6A.js +2 -0
- package/dist/client/assets/ConversationScreen-BDRhx-RU.js +1 -0
- package/dist/client/assets/ConversationScreen-C9yMAMYF.css +1 -0
- package/dist/client/assets/ConversationStatus-BwVLiiO4.js +1 -0
- package/dist/client/assets/DataTable-E8s_MmoA.js +1 -0
- package/dist/client/assets/DispatchAftermath-Dpe88DFX.js +1 -0
- package/dist/client/assets/DocumentFocusViewer-BeVwwl26.js +1 -0
- package/dist/client/assets/EmbeddableSurfacesLab-BQqFQVnI.js +1 -0
- package/dist/client/assets/EmptyState-4F9XDFQm.js +1 -0
- package/dist/client/assets/FileViewerPane-CLgUhSm4.js +3 -0
- package/dist/client/assets/FleetSearch-Dz5euQJe.js +1 -0
- package/dist/client/assets/FleetSearch-EXOe8ulE.css +1 -0
- package/dist/client/assets/FlightObserveScreen-6RpZYwVz.js +1 -0
- package/dist/client/assets/FollowScreen-DZ4qfYOY.js +1 -0
- package/dist/client/assets/HarnessMark-Cbv3Ib0c.js +1 -0
- package/dist/client/assets/HarnessesScreen-CznAImej.js +1 -0
- package/dist/client/assets/HomeHero-B3uYd-pP.js +1 -0
- package/dist/client/assets/HomeHero-DEl-WBsT.css +1 -0
- package/dist/client/assets/KnowledgeSearchInspector-Dgdkfvvz.js +1 -0
- package/dist/client/assets/KnowledgeSearchScreen-DJDGGaqC.js +1 -0
- package/dist/client/assets/LaneToolHoverCard-Bla0gBdm.js +1 -0
- package/dist/client/assets/LaneTraceDetailSheet-D1CspRbl.js +1 -0
- package/dist/client/assets/LaneTraceEventFocus-BF9ERP5O.js +1 -0
- package/dist/client/assets/MeshCanvas-DFEPkpqY.js +3 -0
- package/dist/client/assets/MeshCanvasMinimap-CyVFYixr.js +1 -0
- package/dist/client/assets/MeshCanvasMinimap-Dv7nMbl5.css +1 -0
- package/dist/client/assets/MeshScreen-DFgevn8N.js +1 -0
- package/dist/client/assets/MeshTopologyView-CalkZghg.js +2 -0
- package/dist/client/assets/MessageComposerSuggestions-DpxN9WiB.js +1 -0
- package/dist/client/assets/MessagesScreen-C8YKW10Y.js +1 -0
- package/dist/client/assets/MissionControlView-lUeAiSVg.js +1 -0
- package/dist/client/assets/MissionFocusOverlay-wlCmWDCT.js +1 -0
- package/dist/client/assets/MissionLeftAgentRow-BpZWntfl.js +1 -0
- package/dist/client/assets/MissionLogPane-__MVtEl9.js +1 -0
- package/dist/client/assets/NewAgentModal-Bg-eWHpY.js +1 -0
- package/dist/client/assets/NewAgentModal-ru8u5YdJ.css +1 -0
- package/dist/client/assets/NewChatComposer-Cs6OsxK6.js +19 -0
- package/dist/client/assets/NewChatComposer-W-t-L4oV.css +1 -0
- package/dist/client/assets/NewChatOrigin-Bk2OyVjI.js +1 -0
- package/dist/client/assets/ObserveEmbedScreen-y2EpuqRZ.js +2 -0
- package/dist/client/assets/ObserveTextFlow-rsFj_rVo.js +2 -0
- package/dist/client/assets/ObservedTopologyPanel-BsBsvVPL.css +1 -0
- package/dist/client/assets/ObservedTopologyPanel-DyUeV98H.js +2 -0
- package/dist/client/assets/OpenScoutAppShell-Bh6FnEJO.css +1 -0
- package/dist/client/assets/OpenScoutAppShell-C_URc8sV.js +87 -0
- package/dist/client/assets/OpsAgentsView-UN7iOscs.js +1 -0
- package/dist/client/assets/OpsScreen-Buf3LKjb.js +1 -0
- package/dist/client/assets/OpsSubnav-DsuXzHah.js +1 -0
- package/dist/client/assets/PlanView-C1CjH3PG.js +1 -0
- package/dist/client/assets/ProjectAgentProfile-DJusrAV-.js +1 -0
- package/dist/client/assets/ProjectAgentProfileBar-CtTpj6fU.js +1 -0
- package/dist/client/assets/ProjectAgentProfileHero-BFwNJo_N.js +1 -0
- package/dist/client/assets/ProjectsInbox-GhVMxOhw.js +2 -0
- package/dist/client/assets/ProjectsRail-BgiuV4LR.js +1 -0
- package/dist/client/assets/ProjectsScreen-eNUBy4YU.js +1 -0
- package/dist/client/assets/ProjectsThreadAside-CoBgnHmr.js +1 -0
- package/dist/client/assets/Provider-C7UKGHQy.js +1 -0
- package/dist/client/assets/Provider-CCzjtkda.css +1 -0
- package/dist/client/assets/RailRow-BoGxAHNF.js +1 -0
- package/dist/client/assets/RailRow-Cf9LOiEj.css +1 -0
- package/dist/client/assets/RawSessionsTable-DL8y_eEy.js +1 -0
- package/dist/client/assets/RealtimeVoiceScreen-ffS-39zy.js +1 -0
- package/dist/client/assets/RepoDiffEmbedScreen-C0rumUME.js +1 -0
- package/dist/client/assets/RepoDiffPageScreen-DMv6DioL.js +1 -0
- package/dist/client/assets/RepoDiffViewer-D_exm6xK.js +7 -0
- package/dist/client/assets/RepoDiffViewerLazy-BPgF92Bg.js +2 -0
- package/dist/client/assets/ReposScreen-CB_YBWYf.js +6 -0
- package/dist/client/assets/ScoutDeckSurface-CxIYFyWx.js +1 -0
- package/dist/client/assets/ScoutDeckSurface-uhmuZRzC.css +1 -0
- package/dist/client/assets/ScoutSurface-CYz_TcWC.js +1 -0
- package/dist/client/assets/ScoutbotBroadcastChip-CxtYZWPZ.css +1 -0
- package/dist/client/assets/ScoutbotBroadcastChip-L_R9atj0.js +2 -0
- package/dist/client/assets/ScoutbotFxLab-CgiZMDMW.js +4 -0
- package/dist/client/assets/ScoutbotRealtimeVoiceCall-FMQOr1Np.js +1 -0
- package/dist/client/assets/SecondaryNav-B3-nh5dM.js +1 -0
- package/dist/client/assets/SessionEmbedScreen-BVC7yvWF.js +1 -0
- package/dist/client/assets/SessionObserve-BpggNO_M.css +1 -0
- package/dist/client/assets/SessionObserve-yfXFafp8.js +12 -0
- package/dist/client/assets/SessionRefScreen-DRgJu7Jo.js +1 -0
- package/dist/client/assets/SessionsScreen-D6XUsZfA.js +1 -0
- package/dist/client/assets/SettingsDrawer-CmJt72ww.css +1 -0
- package/dist/client/assets/SettingsDrawer-XfdAa_nD.js +3 -0
- package/dist/client/assets/SettingsScreen-Cy8z-EuR.js +1 -0
- package/dist/client/assets/ShikiPane-Ap1iPxYb.js +15 -0
- package/dist/client/assets/SlidePanel-Bg5dVaIa.css +1 -0
- package/dist/client/assets/SlidePanel-COwtoJqR.js +1 -0
- package/dist/client/assets/SpriteAvatar-DyaGuhik.js +1 -0
- package/dist/client/assets/StatusPill-DhBL__p8.js +1 -0
- package/dist/client/assets/TailView-DGj_5HA9.js +2 -0
- package/dist/client/assets/TailView-Mj3AU2u0.css +1 -0
- package/dist/client/assets/Terminal-CqvGbjXU.js +1 -0
- package/dist/client/assets/TerminalEmbedScreen-DuZZFFzW.js +1 -0
- package/dist/client/assets/TextDocumentSurface-BpAw4eQS.js +4 -0
- package/dist/client/assets/TmuxPeek-m1osv33Q.js +1 -0
- package/dist/client/assets/VoicePermissionsPanel-DsK53ar4.js +1 -0
- package/dist/client/assets/VoicePermissionsPanel-RijAZ1gP.css +1 -0
- package/dist/client/assets/WorkDetailScreen-Bx0JimPC.js +5 -0
- package/dist/client/assets/WorkFilesViewer-Btl6C2Q1.js +1 -0
- package/dist/client/assets/activity-CA8qS6PI.js +1 -0
- package/dist/client/assets/{addon-fit-BOSszMLK.js → addon-fit-BZ-kXjeN.js} +1 -1
- package/dist/client/assets/{addon-webgl-WE840gr0.js → addon-webgl-D9-EQVEK.js} +1 -1
- package/dist/client/assets/agent-chat-Bfjd9y6c.js +1 -0
- package/dist/client/assets/agent-definitions-CymTYqvo.css +1 -0
- package/dist/client/assets/agent-directory-studio-injection-Bc8590z5.css +1 -0
- package/dist/client/assets/agent-essentials-BSY1o46q.js +1 -0
- package/dist/client/assets/agent-floor-CuJr1iK1.css +1 -0
- package/dist/client/assets/agent-lane-card-Dm7YWoew.css +1 -0
- package/dist/client/assets/agent-lane-card-model-r2frk57c.js +1 -0
- package/dist/client/assets/agent-lane-detail-Djm3YJEa.js +1 -0
- package/dist/client/assets/agent-lane-preview-CmHVe3dU.js +4 -0
- package/dist/client/assets/agent-lanes-BDNktFBZ.css +1 -0
- package/dist/client/assets/agent-lanes-model-B4YTt4OF.js +2 -0
- package/dist/client/assets/agents-detail-redesign-h34ROjOW.css +1 -0
- package/dist/client/assets/agents-project-COzHxZAF.css +1 -0
- package/dist/client/assets/agents-project-model-UYiamtrU.js +1 -0
- package/dist/client/assets/agents-screen-BMu6PpRY.css +1 -0
- package/dist/client/assets/api-BkjHJfgJ.js +1 -0
- package/dist/client/assets/api-h5zurxmi.js +1 -0
- package/dist/client/assets/{arc.es-KGqGKGIy.js → arc.es-CQBb-dVu.js} +1 -1
- package/dist/client/assets/arrow-down-BPLe0am9.js +1 -0
- package/dist/client/assets/arrow-left-DEZzHiPS.js +1 -0
- package/dist/client/assets/arrow-up-right-ClxBnsi7.js +1 -0
- package/dist/client/assets/bash-format-BRV5C6Gv.js +1 -0
- package/dist/client/assets/bot-eu8pBNvI.js +1 -0
- package/dist/client/assets/briefings-BwuAFQK6.css +1 -0
- package/dist/client/assets/broker-display-pp33bLsu.js +2 -0
- package/dist/client/assets/cache-Dr0why2k.js +2 -0
- package/dist/client/assets/check-DjgFiBxb.js +1 -0
- package/dist/client/assets/chevron-down-BGk5qoEw.js +1 -0
- package/dist/client/assets/chevron-right-XiIHsk4m.js +1 -0
- package/dist/client/assets/chunk-T65CQEWV-CrzwSeEt.js +1 -0
- package/dist/client/assets/chunk-YOZR3KYS-Bet8khjg.js +47 -0
- package/dist/client/assets/clipboard-e3fSpeo7.js +1 -0
- package/dist/client/assets/code-screen-DrKinCyh.css +1 -0
- package/dist/client/assets/code-xml-B6jOCM4V.js +1 -0
- package/dist/client/assets/collapsed-strip-Dz-of2SM.css +1 -0
- package/dist/client/assets/colors-BtO5_zlx.js +1 -0
- package/dist/client/assets/console-B1IBqLI_.css +1 -0
- package/dist/client/assets/content-BDt9VBPk.js +1 -0
- package/dist/client/assets/content-BIXf4cKR.js +1 -0
- package/dist/client/assets/content-BLm0NBJM.js +1 -0
- package/dist/client/assets/content-C2EwTb2y.js +1 -0
- package/dist/client/assets/content-C5UbLsDF.js +1 -0
- package/dist/client/assets/content-CHU0wwA3.css +1 -0
- package/dist/client/assets/content-CR3vdrYY.js +1 -0
- package/dist/client/assets/content-CSPVmo2s.js +1 -0
- package/dist/client/assets/content-C_FGqx1X.js +1 -0
- package/dist/client/assets/content-CvlVUOG8.js +1 -0
- package/dist/client/assets/content-D5kJmfgl.js +1 -0
- package/dist/client/assets/content-DTpQsomG.js +1 -0
- package/dist/client/assets/content-DikVsqLf.js +1 -0
- package/dist/client/assets/content-DlUe5Ono.js +1 -0
- package/dist/client/assets/content-GIBv_55n.js +1 -0
- package/dist/client/assets/content-Q2oclDzi.js +1 -0
- package/dist/client/assets/context-budget-CbB4BDcO.js +1 -0
- package/dist/client/assets/conversation-icons-IIG5ha6D.js +1 -0
- package/dist/client/assets/conversation-model-B47vYmWN.js +1 -0
- package/dist/client/assets/conversation-motion-features-BdAONVls.js +1 -0
- package/dist/client/assets/conversation-prefs-DNre-Lcx.js +1 -0
- package/dist/client/assets/copy-CQGYbxdu.js +1 -0
- package/dist/client/assets/createLucideIcon-OpA4Amw5.js +1 -0
- package/dist/client/assets/ctx-panel-B4s49N9e.css +1 -0
- package/dist/client/assets/discover-C1YwpBDE.js +2 -0
- package/dist/client/assets/document-focus-viewer-BSC_JwVE.css +1 -0
- package/dist/client/assets/embed-entry-BAcGL3g9.js +2 -0
- package/dist/client/assets/external-link-CXBytO9o.js +1 -0
- package/dist/client/assets/eye-0PvebX_a.js +1 -0
- package/dist/client/assets/file-text-BODxCjcz.js +1 -0
- package/dist/client/assets/flight-observe-GFg9L8ft.css +1 -0
- package/dist/client/assets/follow-route-BvcGtBIL.js +1 -0
- package/dist/client/assets/fx-z37u1o2z.js +1 -0
- package/dist/client/assets/gestures-CcwOTu8C.js +1 -0
- package/dist/client/assets/harnesses-screen-DBZoTZz8.css +1 -0
- package/dist/client/assets/home-live-action-B22u89j7.js +1 -0
- package/dist/client/assets/home-moving-signal-CAa0V91u.css +1 -0
- package/dist/client/assets/home-moving-signal-CK147hxn.js +1 -0
- package/dist/client/assets/home-now-card-BgvNWuea.js +1 -0
- package/dist/client/assets/home-now-card-nano-BcjnOU9H.js +1 -0
- package/dist/client/assets/hooks-B6y_O2FB.js +2 -0
- package/dist/client/assets/hooks-D6NI15f6.css +1 -0
- package/dist/client/assets/inbox-thread-redesign-Bz4FjWzr.css +1 -0
- package/dist/client/assets/index-BWHgHrtv.js +1 -0
- package/dist/client/assets/index-BcuhqXLe.js +1 -0
- package/dist/client/assets/index-CJXzfjo9.js +1 -0
- package/dist/client/assets/index-CvF09yvf.css +1 -0
- package/dist/client/assets/index-DMiGbrBt.js +10 -0
- package/dist/client/assets/index-DQPvraRS.js +1 -0
- package/dist/client/assets/index-DxGoC5l5.css +1 -0
- package/dist/client/assets/inspector-panel-DPoCWxKs.js +2 -0
- package/dist/client/assets/keyboard-nav-2kv_tGUS.js +1 -0
- package/dist/client/assets/knowledge-search-CVxQwxPn.js +1 -0
- package/dist/client/assets/knowledge-search-DjrQdiiW.css +1 -0
- package/dist/client/assets/lane-ask-display-B6iCAVcd.js +18 -0
- package/dist/client/assets/lane-edit-display-C_Aujldz.js +9 -0
- package/dist/client/assets/lane-observe-D0rfKDnU.js +7 -0
- package/dist/client/assets/lane-roster-store-D8x1jac2.js +1 -0
- package/dist/client/assets/lane-tool-detail-0WhMf4Vj.js +9 -0
- package/dist/client/assets/left-Bk3XnxPD.css +1 -0
- package/dist/client/assets/left-C--GiIh8.js +2 -0
- package/dist/client/assets/left-CAaRBK9S.css +1 -0
- package/dist/client/assets/left-CCoobxPS.css +1 -0
- package/dist/client/assets/left-Cj7Rt89X.js +1 -0
- package/dist/client/assets/left-CpNEtFEg.js +1 -0
- package/dist/client/assets/left-CzXAuK_t.js +2 -0
- package/dist/client/assets/left-agents-Bo9sO1by.js +1 -0
- package/dist/client/assets/left-bN4PCAXa.js +1 -0
- package/dist/client/assets/left-default-DV9GdvYi.js +1 -0
- package/dist/client/assets/left-jYYGAOYD.js +1 -0
- package/dist/client/assets/left-lanes-D0l_Co7V.js +1 -0
- package/dist/client/assets/left-mission-Ci7zREkQ.js +1 -0
- package/dist/client/assets/left-mission-DSenPIyb.css +1 -0
- package/dist/client/assets/left-plan-D4U1uflW.js +2 -0
- package/dist/client/assets/library-D-RxGiCw.js +1 -0
- package/dist/client/assets/loader-circle-CbHjZsz1.js +1 -0
- package/dist/client/assets/local-agents--00gLMqr.js +1 -0
- package/dist/client/assets/mentions-jSuTGeet.js +1 -0
- package/dist/client/assets/mesh-buckets-CfAukILK.js +1 -0
- package/dist/client/assets/mesh-screen-BSDUjrnV.css +1 -0
- package/dist/client/assets/mesh-view-store-CWidRbTE.js +1 -0
- package/dist/client/assets/message-circle-CG-96zts.js +1 -0
- package/dist/client/assets/message-markup-3J9pi3nx.js +15 -0
- package/dist/client/assets/message-square-DSaGpjFU.js +1 -0
- package/dist/client/assets/message-visibility-kJM8XcSG.js +1 -0
- package/dist/client/assets/mission-control-D3ikEPND.css +1 -0
- package/dist/client/assets/mission-control-model-C0fByIjm.js +1 -0
- package/dist/client/assets/mission-control-store-BlnEhiCq.js +1 -0
- package/dist/client/assets/model-Co0zkMIc.js +1 -0
- package/dist/client/assets/model-CpAxGuis.js +1 -0
- package/dist/client/assets/observe-CuLGD9Zp.js +1 -0
- package/dist/client/assets/openAgent-Bjt57GdM.js +1 -0
- package/dist/client/assets/openContent-C6XO6kr5.js +1 -0
- package/dist/client/assets/operator-attention-BwSPeheT.js +1 -0
- package/dist/client/assets/ops-agents-BOYxzPTm.css +1 -0
- package/dist/client/assets/ops-atop-BB4B4JdE.css +1 -0
- package/dist/client/assets/ops-screen-giu3If_N.css +1 -0
- package/dist/client/assets/page-status-DpkedE1F.js +1 -0
- package/dist/client/assets/page-status-bar-ByUD7VPM.css +1 -0
- package/dist/client/assets/plan-view-D56fneVF.css +1 -0
- package/dist/client/assets/plus--b1raV_O.js +1 -0
- package/dist/client/assets/profile-CVRziEDA.js +1 -0
- package/dist/client/assets/project-overview-helpers-BQTc_Ous.js +1 -0
- package/dist/client/assets/projects-inbox-CHyUFQ6w.js +1 -0
- package/dist/client/assets/projects-inbox-COZ23dLR.css +1 -0
- package/dist/client/assets/radio-Bz8ZePxj.js +1 -0
- package/dist/client/assets/refresh-cw-BBmAnCB7.js +1 -0
- package/dist/client/assets/repo-diff-C9Qs-bEn.css +1 -0
- package/dist/client/assets/resizable-columns-C7ygvLt8.css +1 -0
- package/dist/client/assets/resolve-panes-r9B3mpW7.js +1 -0
- package/dist/client/assets/resolve-sidebar-context-DcG8xGaB.js +1 -0
- package/dist/client/assets/right-BHeiIaty.js +1 -0
- package/dist/client/assets/right-BkgKo9VT.js +1 -0
- package/dist/client/assets/right-BpEU5jWE.js +1 -0
- package/dist/client/assets/right-CRZXoy-X.js +1 -0
- package/dist/client/assets/right-ChF_pbPy.js +1 -0
- package/dist/client/assets/right-DMoUT3KN.js +1 -0
- package/dist/client/assets/right-DjRXbnRP.js +2 -0
- package/dist/client/assets/right-T4Ue6EqM.js +1 -0
- package/dist/client/assets/right-wzrLXKur.js +1 -0
- package/dist/client/assets/rocket-BSNS_rLs.js +1 -0
- package/dist/client/assets/router-Bq5dwf78.js +1 -0
- package/dist/client/assets/runtime-picker-Bcl5iIX5.js +1 -0
- package/dist/client/assets/runtime-picker-vhm0gtLs.css +1 -0
- package/dist/client/assets/scope-views-4khCg2_z.css +1 -0
- package/dist/client/assets/scope-views-U-ucT9m0.js +1 -0
- package/dist/client/assets/scout-voice-CU5c0LGi.js +1 -0
- package/dist/client/assets/scoutbot-BTIErYHo.js +3 -0
- package/dist/client/assets/scroll-text-D6Pdnar7.js +1 -0
- package/dist/client/assets/search-CWfZtOt2.js +1 -0
- package/dist/client/assets/secondaryNavConfig-DqUIp0Es.js +1 -0
- package/dist/client/assets/secondaryNavConfig-xssF_ubT.css +1 -0
- package/dist/client/assets/selection-bridge-16pk1qyG.js +1 -0
- package/dist/client/assets/send-horizontal-Bg5-QggH.js +1 -0
- package/dist/client/assets/server-CPp4ZJhZ.js +1 -0
- package/dist/client/assets/session-catalog-BmoyVTJ_.js +1 -0
- package/dist/client/assets/session-table-DZcrKoIH.js +1 -0
- package/dist/client/assets/sessionRead-CvFz2RHv.js +1 -0
- package/dist/client/assets/sliders-horizontal-1oW76Xc9.js +1 -0
- package/dist/client/assets/sparkles-ClfRJQ6w.js +1 -0
- package/dist/client/assets/sse-CjIkKo46.js +1 -0
- package/dist/client/assets/status-tone-BM_zuRy1.js +1 -0
- package/dist/client/assets/surface-activity-B1rgWB1i.js +1 -0
- package/dist/client/assets/system-surfaces-redesign-CD26LFc0.css +1 -0
- package/dist/client/assets/tail-display-BdyoLvzY.js +2 -0
- package/dist/client/assets/tail-events-D19uAGe3.js +1 -0
- package/dist/client/assets/terminal-B9AOZQKR.js +1 -0
- package/dist/client/assets/terminal-relay-CWbJ1RCW.js +1 -0
- package/dist/client/assets/terminal-screen-19jAI0Cw.css +1 -0
- package/dist/client/assets/terminal-sessions-D5CIR2OL.js +1 -0
- package/dist/client/assets/terminal-takeover-B8UeD9OX.js +1 -0
- package/dist/client/assets/text-DsBWV_4k.js +1 -0
- package/dist/client/assets/time-DltNTpLl.js +1 -0
- package/dist/client/assets/types-B0PlfpKc.js +1 -0
- package/dist/client/assets/ui-LM8pS8qE.js +1 -0
- package/dist/client/assets/use-conversation-list-Byab41G6.js +1 -0
- package/dist/client/assets/use-fleet-active-asks-BIbQx5AS.js +1 -0
- package/dist/client/assets/use-reduced-motion-RRBkmVkk.js +1 -0
- package/dist/client/assets/useAgentHoverCard-DMrbBif0.js +1 -0
- package/dist/client/assets/useContentSecondaryNav-DMl1WNm7.js +1 -0
- package/dist/client/assets/usePierreRuntime-wC-yMtBb.js +50 -0
- package/dist/client/assets/voice-levels-Dcr3jglk.js +1 -0
- package/dist/client/assets/wrench-Bkc_0lKF.js +1 -0
- package/dist/client/assets/x-D3GElQbe.js +1 -0
- package/dist/client/assets/{xterm-6eL7V7pF.js → xterm-BKR8oAkR.js} +1 -1
- package/dist/client/index.html +6 -3
- package/dist/drizzle/0003_harsh_meltdown.sql +45 -0
- package/dist/drizzle/0004_medical_aaron_stack.sql +40 -0
- package/dist/drizzle/0005_wet_shriek.sql +57 -0
- package/dist/drizzle/0006_woozy_dark_beast.sql +1 -0
- package/dist/drizzle/README.md +7 -0
- package/dist/drizzle/meta/0003_snapshot.json +4952 -0
- package/dist/drizzle/meta/0004_snapshot.json +5235 -0
- package/dist/drizzle/meta/0005_snapshot.json +5599 -0
- package/dist/drizzle/meta/0006_snapshot.json +5606 -0
- package/dist/drizzle/meta/_journal.json +28 -0
- package/dist/main.mjs +24907 -12910
- package/dist/node/main.mjs +10212 -195
- package/dist/openscout-terminal-relay.mjs +507 -64
- package/dist/pairing-runtime-controller.mjs +10793 -5165
- package/dist/runtime/base-daemon.mjs +627 -159
- package/dist/runtime/broker-daemon.mjs +65039 -30990
- package/dist/runtime/broker-process-manager.mjs +247 -54
- package/dist/runtime/mesh-discover.mjs +246 -54
- package/dist/scout-control-plane-web.mjs +56699 -47427
- package/dist/scout-web-server.mjs +56699 -47427
- package/package.json +1 -1
- package/dist/client/assets/RepoDiffViewer-DLVleMPW.js +0 -56
- package/dist/client/assets/embed-entry-BdmREZuc.js +0 -1
- package/dist/client/assets/index-DPFmfHm5.js +0 -271
- 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
|
|
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":
|
|
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, "|",
|
|
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
|
|
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() ||
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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_-]
|
|
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
|
-
|
|
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(
|
|
3636
|
+
session.pty.resize(acceptedCols, acceptedRows);
|
|
3321
3637
|
if (session.backend === "tmux" && session.tmuxSession) {
|
|
3322
|
-
|
|
3638
|
+
if (session.controlMode !== "observe") {
|
|
3639
|
+
await resizeTmuxWindow(session.tmuxSession, acceptedCols, acceptedRows);
|
|
3640
|
+
}
|
|
3323
3641
|
}
|
|
3324
|
-
session.cols =
|
|
3325
|
-
session.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
|
-
|
|
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
|
-
|
|
3542
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
agentArgs
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3687
|
-
|
|
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.
|
|
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 =
|
|
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, {
|
|
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, {
|
|
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) {
|