ryco-cli 0.1.6 → 0.1.7

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 (152) hide show
  1. package/dist/{AzureDevOpsSourceControlProvider-6holYS_D.cjs → AzureDevOpsSourceControlProvider-5exivY-1.cjs} +2 -2
  2. package/dist/{AzureDevOpsSourceControlProvider-CC2_COxP.mjs → AzureDevOpsSourceControlProvider-CF5LuCHp.mjs} +2 -2
  3. package/dist/{BitbucketSourceControlProvider-a0IsNFyG.cjs → BitbucketSourceControlProvider-1GWENqcl.cjs} +2 -2
  4. package/dist/{BitbucketSourceControlProvider-CYR_BD1d.mjs → BitbucketSourceControlProvider-CKH09tfT.mjs} +2 -2
  5. package/dist/{ClaudeDriver-C6tQNEWO.cjs → ClaudeDriver-BXLdjrht.cjs} +177 -4
  6. package/dist/{ClaudeDriver-D3nsxwH9.mjs → ClaudeDriver-WwWFTu61.mjs} +178 -5
  7. package/dist/{CodexDriver-BILrJG8o.mjs → CodexDriver-93-TmCrO.mjs} +6 -5
  8. package/dist/{CodexDriver-ms_YgFD7.cjs → CodexDriver-BboMT9uk.cjs} +5 -4
  9. package/dist/{CodexTextGeneration-CHEgoANm.cjs → CodexTextGeneration-0pRbJji3.cjs} +2 -2
  10. package/dist/{CodexTextGeneration-BIKHl7E3.mjs → CodexTextGeneration-BU9Myn87.mjs} +3 -3
  11. package/dist/{CopilotDriver-CmD3Ffyl.mjs → CopilotDriver-BASi8pJ0.mjs} +4 -4
  12. package/dist/{CopilotDriver-B0--ZwIK.cjs → CopilotDriver-DCsv-17W.cjs} +3 -3
  13. package/dist/{CursorDriver-DTVPXZ-R.cjs → CursorDriver-BTSiM3A8.cjs} +161 -14
  14. package/dist/{CursorDriver-CbeaIbdb.mjs → CursorDriver-D5LvIqUk.mjs} +162 -15
  15. package/dist/{ForgejoSourceControlProvider-DwAog76b.cjs → ForgejoSourceControlProvider-BTXRDCGB.cjs} +2 -2
  16. package/dist/{ForgejoSourceControlProvider-DX6d9gvz.mjs → ForgejoSourceControlProvider-e-4hvvZ_.mjs} +2 -2
  17. package/dist/{GitHubSourceControlProvider-C-LGwho3.mjs → GitHubSourceControlProvider-26IofDAO.mjs} +2 -2
  18. package/dist/{GitHubSourceControlProvider-9lJFzjsu.cjs → GitHubSourceControlProvider-DWmwkA_y.cjs} +2 -2
  19. package/dist/{GitLabSourceControlProvider-CvKA74lg.cjs → GitLabSourceControlProvider-D-YHnxRe.cjs} +2 -2
  20. package/dist/{GitLabSourceControlProvider-CkeT2aEx.mjs → GitLabSourceControlProvider-DePct78W.mjs} +2 -2
  21. package/dist/{OpenCodeDriver-ClWtCk0j.mjs → OpenCodeDriver-BhvLOmvn.mjs} +325 -38
  22. package/dist/{OpenCodeDriver-CXUsnl5o.cjs → OpenCodeDriver-CVeZ4n9-.cjs} +324 -37
  23. package/dist/{SourceControlProviderDiscoveryCatalog-_rg0mc1o.cjs → SourceControlProviderDiscoveryCatalog-DeFR5xH3.cjs} +1 -64
  24. package/dist/{SourceControlProviderDiscoveryCatalog-yMDer_Yh.mjs → SourceControlProviderDiscoveryCatalog-mJV_Xitr.mjs} +3 -48
  25. package/dist/bin.cjs +1280 -519
  26. package/dist/bin.mjs +1234 -474
  27. package/dist/client/assets/{AnimatedHeight-DgItDSis.js → AnimatedHeight-BSU0lzYs.js} +1 -1
  28. package/dist/client/assets/AppearanceSettings-D7q0ujGK.js +1 -0
  29. package/dist/client/assets/{BranchToolbar.logic-C_xHEt9C.js → BranchToolbar.logic-CZIFSvhd.js} +1 -1
  30. package/dist/client/assets/ChatRightPanel-CWHOIuiQ.js +188 -0
  31. package/dist/client/assets/{ChatThreadRouteView-CV6ETYG5.js → ChatThreadRouteView-bA7xWXzc.js} +1 -1
  32. package/dist/client/assets/{CommandPaletteDialog-C_H7R8S5.js → CommandPaletteDialog-DNYaVOZO.js} +1 -1
  33. package/dist/client/assets/CompositeRoot-B_KEfCUE.js +1 -0
  34. package/dist/client/assets/ConnectionsSettings-CLZPbx_K.js +1 -0
  35. package/dist/client/assets/{DiagnosticsSettings-B340S_mq.js → DiagnosticsSettings-DtzPCb6N.js} +1 -1
  36. package/dist/client/assets/{DialogHandle-BJY7cHCV.js → DialogHandle-DuHnmWoE.js} +1 -1
  37. package/dist/client/assets/{DialogRoot-Ej1FVk-_.js → DialogRoot-BV25qAcA.js} +1 -1
  38. package/dist/client/assets/DialogTitle-DQsi-RTa.js +1 -0
  39. package/dist/client/assets/DialogTrigger-D0fA01C6.js +1 -0
  40. package/dist/client/assets/{DialogViewport-DvjAl76K.js → DialogViewport-CMV_BePU.js} +1 -1
  41. package/dist/client/assets/{DraftChatThreadRouteView-pOkyeKPS.js → DraftChatThreadRouteView-BoiKnrii.js} +1 -1
  42. package/dist/client/assets/{JetBrainsIcons-DTTF47I0.js → JetBrainsIcons-BcPxJlMf.js} +1 -1
  43. package/dist/client/assets/{KeybindingsSettings-CW3RRi-7.js → KeybindingsSettings-LuI98pdF.js} +1 -1
  44. package/dist/client/assets/McpServersSettings-BFMuWYVV.js +6 -0
  45. package/dist/client/assets/{NoActiveThreadState-DVHwrkCp.js → NoActiveThreadState-C2q_O1kP.js} +1 -1
  46. package/dist/client/assets/{OpinionatedPluginsSettings-Cjj23Fs4.js → OpinionatedPluginsSettings-Bqwct37O.js} +1 -1
  47. package/dist/client/assets/{ProjectFavicon-TDP7HRfn.js → ProjectFavicon-D2imiJ8M.js} +1 -1
  48. package/dist/client/assets/{ProviderUpdateLaunchNotification.logic-6TpFsmiI.js → ProviderUpdateLaunchNotification.logic-CJgA--nK.js} +1 -1
  49. package/dist/client/assets/ProvidersSettingsPanel-B97vbeu6.js +1 -0
  50. package/dist/client/assets/{RedactedSensitiveText-BfoVjPsE.js → RedactedSensitiveText-B2GFTyfq.js} +1 -1
  51. package/dist/client/assets/RootAppShell-C1xTR98P.js +12 -0
  52. package/dist/client/assets/SettingsDialog-Q0Q8O5oH.js +2 -0
  53. package/dist/client/assets/SourceControlSettings-KAvoPTNi.js +1 -0
  54. package/dist/client/assets/StatisticsPanel-BzsQ444K.js +64 -0
  55. package/dist/client/assets/{ThreadStatusIndicators-B0leIJGD.js → ThreadStatusIndicators-Cw_jLVQf.js} +1 -1
  56. package/dist/client/assets/{ThreadTerminalDrawer-COq2Fk17.js → ThreadTerminalDrawer-D1WnSemH.js} +17 -17
  57. package/dist/client/assets/ThreadWorkspacePanel-L4qCPTOA.js +166 -0
  58. package/dist/client/assets/{alert-dialog-lMfKpG2t.js → alert-dialog-CNmKa0BK.js} +1 -1
  59. package/dist/client/assets/chart-column-BWSKYZ_a.js +1 -0
  60. package/dist/client/assets/{chatThreadActions-PPyTj_x0.js → chatThreadActions-TtDsiwDC.js} +1 -1
  61. package/dist/client/assets/chevron-up-zopJ_99l.js +1 -0
  62. package/dist/client/assets/{clamp-JiD4IZ0Z.js → clamp-Ds6WJu8j.js} +1 -1
  63. package/dist/client/assets/{clipboard-copy-CYBLSG2q.js → clipboard-copy-BoJGpdmJ.js} +1 -1
  64. package/dist/client/assets/clock-CzUHThzk.js +1 -0
  65. package/dist/client/assets/{commandPaletteStore-uVfCD7zE.js → commandPaletteStore-KebG835b.js} +1 -1
  66. package/dist/client/assets/composerDraftStore-DpPEQ6BN.js +21 -0
  67. package/dist/client/assets/{desktopUpdateAtoms-X6uM5SoD.js → desktopUpdateAtoms-BQ0GGEfM.js} +1 -1
  68. package/dist/client/assets/{download-DLBlpp4h.js → download-CUiRE0N9.js} +1 -1
  69. package/dist/client/assets/{draft-input-dLlVMl5P.js → draft-input-CwpGDtoT.js} +1 -1
  70. package/dist/client/assets/editorPreferences-jN7DKbyt.js +1 -0
  71. package/dist/client/assets/{empty-DlLY-Hhj.js → empty-CBuXePtg.js} +1 -1
  72. package/dist/client/assets/{group-zDBPF7rR.js → group-BpZvxjG5.js} +1 -1
  73. package/dist/client/assets/{index-Dq8sT2lF.js → index-BKzXTNJ_.js} +2 -2
  74. package/dist/client/assets/{input-B9-RWT56.js → input-CgDawd6k.js} +1 -1
  75. package/dist/client/assets/kbd-QYSL97CK.js +1 -0
  76. package/dist/client/assets/{keybindings-Dx4Nc1vY.js → keybindings-CUTRYI_A.js} +1 -1
  77. package/dist/client/assets/{keyboard-DDTWQkr0.js → keyboard-DFFiI7JY.js} +1 -1
  78. package/dist/client/assets/{keyedQuery-Ds4OGhX2.js → keyedQuery-DiOCbGH0.js} +0 -0
  79. package/dist/client/assets/{main-DxfpmoKJ.js → main-BgFGju3e.js} +3 -3
  80. package/dist/client/assets/main-D0UFdwts.css +2 -0
  81. package/dist/client/assets/{palette-BQcz-ZYV.js → palette-BXCL909c.js} +1 -1
  82. package/dist/client/assets/{play-QloDGe4R.js → play-DI2LZohg.js} +1 -1
  83. package/dist/client/assets/plus-DzgIfHUF.js +1 -0
  84. package/dist/client/assets/projectAtoms-DXXpuERK.js +1 -0
  85. package/dist/client/assets/providerDriverMeta-CRNNp0q3.js +1 -0
  86. package/dist/client/assets/providerIconUtils-D-DFhem2.js +47 -0
  87. package/dist/client/assets/radio-group-_PPYg3YY.js +1 -0
  88. package/dist/client/assets/{refresh-cw-DkBMGllm.js → refresh-cw-BsQTNBXl.js} +1 -1
  89. package/dist/client/assets/{resolveAriaLabelledBy-DDfIbj05.js → resolveAriaLabelledBy-CRHo_s16.js} +1 -1
  90. package/dist/client/assets/{rightPanelRouteSearch-DfuWVvXN.js → rightPanelRouteSearch-CfmZ7osj.js} +1 -1
  91. package/dist/client/assets/{scale-BActunFu.js → scale-DDEJ-tvn.js} +1 -1
  92. package/dist/client/assets/{scroll-area-D-YOUG02.js → scroll-area-HgsI-ErG.js} +1 -1
  93. package/dist/client/assets/{separator-TInKeIDo.js → separator-ClnL4mUB.js} +1 -1
  94. package/dist/client/assets/{server-BtEG3NAw.js → server-Bbs3L-6_.js} +1 -1
  95. package/dist/client/assets/{session-logic-DNf1aXq_.js → session-logic-CKQkgIwo.js} +1 -1
  96. package/dist/client/assets/settingsDialogStore-SG-W1q0A.js +1 -0
  97. package/dist/client/assets/{settingsLayout-D22Mm0u3.js → settingsLayout-G5xVm-ZT.js} +1 -1
  98. package/dist/client/assets/sidebar-_u7SGgmC.js +1 -0
  99. package/dist/client/assets/sidebarStatusText-BTYnwflG.js +1 -0
  100. package/dist/client/assets/{skeleton-DWaac_qp.js → skeleton-CmUvhZGP.js} +1 -1
  101. package/dist/client/assets/{storeSelectors-Cx1IYPA4.js → storeSelectors-DhJRpdiw.js} +1 -1
  102. package/dist/client/assets/threadSelectionStore-ygmA4DNA.js +1 -0
  103. package/dist/client/assets/toast-DmA_ziPT.js +1 -0
  104. package/dist/client/assets/toggle-DGS7tKuj.js +1 -0
  105. package/dist/client/assets/{toggle-group-CnLjaHSL.js → toggle-group-Dtv1ZUFW.js} +1 -1
  106. package/dist/client/assets/{tokenModePresentation-BSYdIvBm.js → tokenModePresentation-Dor1DnBx.js} +1 -1
  107. package/dist/client/assets/{trash-2-BI5xcbsm.js → trash-2-C2G3VGoV.js} +1 -1
  108. package/dist/client/assets/{triangle-alert-DJef_Uvh.js → triangle-alert-Bpz3xGu5.js} +1 -1
  109. package/dist/client/assets/{undo-2-DeZ2cMGS.js → undo-2-C3rtxuqZ.js} +1 -1
  110. package/dist/client/assets/{useHandleNewThread-XB82O6SA.js → useHandleNewThread-ypSbzG0P.js} +1 -1
  111. package/dist/client/assets/useLabelableId-Bc7KEnHU.js +1 -0
  112. package/dist/client/assets/{useNavigate-B2tgshhW.js → useNavigate-_4hWGSey.js} +1 -1
  113. package/dist/client/assets/useTheme-HcKmBfpF.js +1 -0
  114. package/dist/client/assets/{vscode-icons-DM9qFoEr.js → vscode-icons-DdSTtxYd.js} +1 -1
  115. package/dist/client/assets/{wrench-je4QOyG-.js → wrench-C4jdis40.js} +1 -1
  116. package/dist/client/assets/x-CG2WU63t.js +1 -0
  117. package/dist/client/index.html +1 -1
  118. package/dist/{collectUint8StreamText-C2z5Y8tF.mjs → collectUint8StreamText-Lv4GGI79.mjs} +269 -14
  119. package/dist/{collectUint8StreamText-TCG6xW_P.cjs → collectUint8StreamText-uNXVRHOf.cjs} +291 -12
  120. package/dist/{makeManagedServerProvider-DPFw9gV_.cjs → makeManagedServerProvider-3SD-Q5xh.cjs} +1 -1
  121. package/dist/{makeManagedServerProvider-BXO8QvzC.mjs → makeManagedServerProvider-CkPEptun.mjs} +1 -1
  122. package/package.json +1 -1
  123. package/dist/client/assets/AppearanceSettings-BlsMFBvJ.js +0 -1
  124. package/dist/client/assets/ChatRightPanel-CThudBb1.js +0 -188
  125. package/dist/client/assets/CompositeRoot-DjnzUIwC.js +0 -1
  126. package/dist/client/assets/ConnectionsSettings-hArR4Oe3.js +0 -1
  127. package/dist/client/assets/DialogTitle-H1yIMmA9.js +0 -1
  128. package/dist/client/assets/DialogTrigger-BHMq_K2G.js +0 -1
  129. package/dist/client/assets/McpServersSettings-dQ3BzOWY.js +0 -6
  130. package/dist/client/assets/ProvidersSettingsPanel-D15EeWAq.js +0 -1
  131. package/dist/client/assets/RootAppShell-CWBPSA2w.js +0 -12
  132. package/dist/client/assets/SettingsDialog-oJCE5foT.js +0 -2
  133. package/dist/client/assets/SourceControlSettings-CPnlMxNm.js +0 -1
  134. package/dist/client/assets/ThreadWorkspacePanel-qF9y6QT9.js +0 -166
  135. package/dist/client/assets/composerDraftStore-D12lUSfh.js +0 -21
  136. package/dist/client/assets/editorPreferences-BLeEBSD_.js +0 -1
  137. package/dist/client/assets/folder-open-DMjz0lpx.js +0 -1
  138. package/dist/client/assets/kbd-aeSsjiPI.js +0 -1
  139. package/dist/client/assets/main-C57RhHZ_.css +0 -2
  140. package/dist/client/assets/plus-4Oy56d-3.js +0 -1
  141. package/dist/client/assets/projectAtoms-DUEBb7Zz.js +0 -1
  142. package/dist/client/assets/providerDriverMeta-Dwi6Zqgd.js +0 -1
  143. package/dist/client/assets/providerIconUtils-uhWb4bdg.js +0 -47
  144. package/dist/client/assets/radio-group-DHyQlLeX.js +0 -1
  145. package/dist/client/assets/settingsDialogStore-BINi7pdD.js +0 -1
  146. package/dist/client/assets/sidebar-DHwNQmWp.js +0 -1
  147. package/dist/client/assets/threadSelectionStore-C0ig4405.js +0 -1
  148. package/dist/client/assets/toast-DE7a4wkW.js +0 -1
  149. package/dist/client/assets/toggle-BIW4AyPY.js +0 -1
  150. package/dist/client/assets/useLabelableId-DBAgv9qQ.js +0 -1
  151. package/dist/client/assets/useTheme-Dv42Z8uy.js +0 -1
  152. package/dist/client/assets/x-fI9snvD3.js +0 -1
package/dist/bin.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { $ as ProviderStopSessionInput, $n as ApprovalRequestId, $t as ThreadMetaUpdatedPayload$1, A as OpinionatedPluginError, At as OrchestrationThread, B as ServerSettingsError, Bt as ProjectionPendingApprovalDecision, C as McpOauthLoginResult, Cn as SourceControlProviderError, Ct as OrchestrationMessageRole, D as McpServerName, Dt as OrchestrationSession, E as McpServerConfig, En as VcsDriverKind, Et as OrchestrationReplayEventsError, F as CopilotSettings, Fn as MODEL_SLUG_ALIASES_BY_PROVIDER, Ft as ProjectCreatedPayload$1, G as ResolvedKeybindingRule, Gn as EDITORS, Gt as RuntimeMode, H as KeybindingsConfig, Hn as TerminalHistoryError, I as CursorSettings, In as ProviderDriverKind, It as ProjectDeletedPayload$1, J as ProviderInterruptTurnInput, Jn as AuthClientMetadataDeviceType, Jt as ThreadAttachedToWorktreePayload$1, K as THREAD_JUMP_KEYBINDING_COMMANDS, Kn as OpenError, Kt as ThreadActivityAppendedPayload$1, L as DEFAULT_SERVER_SETTINGS, Ln as ProviderInstanceId, Lt as ProjectMetaUpdatedPayload$1, M as ServerProviderUpdateError, Mt as OrchestrationWorktreeShell, N as ClaudeSettings, Nn as DEFAULT_GIT_TEXT_GENERATION_MODEL_BY_PROVIDER, O as McpSettingsError, On as VcsProcessExitError, Ot as OrchestrationSessionStatus, P as CodexSettings, Pn as DEFAULT_MODEL, Pt as ProjectAvatarSetPayload$1, Q as ProviderSessionStartInput, Qn as AuthRpcError, Qt as ThreadMessageSentPayload, R as OpenCodeSettings, Rn as defaultInstanceIdForDriver, Rt as ProjectMetadataDir, S as McpListServersResult, St as OrchestrationMessage, T as McpServer, Tt as OrchestrationReadModel, U as KeybindingsConfigError, Un as TerminalNotRunningError, Ut as ProviderInteractionMode, V as KeybindingRule, Vn as TerminalCwdError, Vt as ProjectionPendingApprovalStatus, W as MODEL_PICKER_JUMP_KEYBINDING_COMMANDS, Wn as TerminalSessionLookupError, Wt as ProviderSessionRuntimeStatus, X as ProviderRespondToUserInputInput, Xn as AuthRevokeClientSessionInput, Xt as ThreadDeletedPayload$1, Y as ProviderRespondToRequestInput, Yn as AuthCreatePairingCredentialInput, Yt as ThreadCreatedPayload$1, Z as ProviderSendTurnInput, Zn as AuthRevokePairingLinkInput, Zt as ThreadInteractionModeSetPayload$1, _ as GitManagerError, _n as WorktreeId, _r as TrimmedNonEmptyString, _t as OrchestrationEventType, an as ThreadTokenModeSetPayload$1, ar as EnvironmentId, at as DEFAULT_PROVIDER_INTERACTION_MODE, b as McpInventoryResourceTemplate, bn as WorkItemProviderError, bt as OrchestrationGetTurnDiffError, c as ProjectSearchEntriesError, cn as WorktreeArchivedPayload$1, cr as MessageId, ct as OrchestrationActorKind, d as AtlassianCapability, dn as WorktreeManualPositionSetPayload$1, dr as ProjectId, dt as OrchestrationCheckpointStatus, en as ThreadProposedPlanUpsertedPayload$1, er as AtlassianConnectionId, et as AgentTokenMode, f as AtlassianConnectionError, fn as WorktreeMetaUpdatedPayload$1, ft as OrchestrationCheckpointSummary, g as GitCommandError, gn as Worktree, gr as ThreadId, gt as OrchestrationEventMetadata, h as AtlassianProduct, hn as StatusBucket, ht as OrchestrationEvent, i as FilesystemBrowseError, in as ThreadStatusBucketOverriddenPayload$1, ir as CommandId, j as ServerProvider, jn as VcsUnsupportedOperationError, jt as OrchestrationThreadActivityTone, k as McpWorkspaceId, kt as OrchestrationShellSnapshot, l as ProjectStageFileReferenceError, ln as WorktreeCreatedPayload$1, lr as NonNegativeInt, lt as OrchestrationAggregateKind, m as AtlassianConnectionStatus, mn as WorktreeSourceControlStateUpdatedPayload$1, mt as OrchestrationDispatchCommandError, n as WS_METHODS, nn as ThreadRuntimeModeSetPayload$1, nr as AuthSessionId, nt as ClientOrchestrationCommand, o as ProjectListEntriesError, on as ThreadTurnDiffCompletedPayload$1, or as EventId, ot as ModelSelection, p as AtlassianConnectionKind, pn as WorktreeRestoredPayload$1, pt as OrchestrationCommandReceiptStatus, q as isToolLifecycleItemType, qn as AuthBootstrapInput, qt as ThreadArchivedPayload$1, r as WsRpcGroup, rn as ThreadSessionSetPayload$1, rr as CheckpointRef, rt as DEFAULT_AGENT_TOKEN_MODE, s as ProjectReadFileError, sn as ThreadUnarchivedPayload$1, sr as IsoDateTime, st as ORCHESTRATION_WS_METHODS, t as collectUint8StreamText, tn as ThreadRevertedPayload$1, tr as AtlassianResourceId, tt as ChatAttachment, u as ProjectWriteFileError, un as WorktreeDeletedPayload$1, ur as PositiveInt, ut as OrchestrationCheckpointFile, v as TextGenerationError, vn as WORK_ITEM_DETAIL_BODY_MAX_BYTES, vr as TurnId, vt as OrchestrationGetFullThreadDiffError, w as McpProviderSupport, wn as SourceControlRepositoryError, wt as OrchestrationProposedPlanId, x as McpInventoryTool, xn as WorkItemProviderKind, xt as OrchestrationGetTurnDiffResult, y as McpInventoryResource, yn as WORK_ITEM_DETAIL_COMMENT_BODY_MAX_BYTES, yt as OrchestrationGetSnapshotError, z as ServerSettings, zn as isProviderDriverKind, zt as ProjectScript } from "./collectUint8StreamText-C2z5Y8tF.mjs";
4
- import { _ as formatSchemaError, a as makeForgejoDiscovery, c as sourceBranch, d as firstNonEmptyLine, f as probeSourceControlProvider, g as decodeJsonResult, h as layer$19, i as makeBitbucketDiscovery, m as VcsProcess, n as githubDiscovery, o as SourceControlProvider, p as refineUnknownRemoteProvider, r as gitlabDiscovery, s as parseSourceControlOwnerRef, t as azureDevOpsDiscovery, u as detailFromCause, v as fromLenientJson } from "./SourceControlProviderDiscoveryCatalog-yMDer_Yh.mjs";
3
+ import { $ as ProviderRespondToUserInputInput, $n as AuthRevokeClientSessionInput, $t as ThreadDeletedPayload$1, A as McpServerName, At as OrchestrationSession, B as DEFAULT_SERVER_SETTINGS, Bn as ProviderInstanceId, Bt as ProjectMetaUpdatedPayload$1, C as McpInventoryResourceTemplate, Cn as WorkItemProviderError, Ct as OrchestrationGetTurnDiffError, D as McpProviderSupport, Dn as SourceControlRepositoryError, Dt as OrchestrationProposedPlanId, E as McpOauthLoginResult, En as SourceControlProviderError, Et as OrchestrationMessageRole, F as ServerProviderUpdateError, Ft as OrchestrationWorktreeShell, G as KeybindingsConfig, Gn as TerminalHistoryError, H as ServerSettings, Hn as isProviderDriverKind, Ht as ProjectScript, I as ClaudeSettings, In as DEFAULT_GIT_TEXT_GENERATION_MODEL_BY_PROVIDER, J as ResolvedKeybindingRule, Jn as EDITORS, Jt as RuntimeMode, K as KeybindingsConfigError, Kn as TerminalNotRunningError, Kt as ProviderInteractionMode, L as CodexSettings, Ln as DEFAULT_MODEL, Lt as ProjectAvatarSetPayload$1, M as McpWorkspaceId, Mt as OrchestrationShellSnapshot, N as OpinionatedPluginError, Nt as OrchestrationThread, O as McpServer, Ot as OrchestrationReadModel, P as ServerProvider, Pn as VcsUnsupportedOperationError, Pt as OrchestrationThreadActivityTone, Q as ProviderRespondToRequestInput, Qn as AuthCreatePairingCredentialInput, Qt as ThreadCreatedPayload$1, R as CopilotSettings, Rn as MODEL_SLUG_ALIASES_BY_PROVIDER, Rt as ProjectCreatedPayload$1, S as McpInventoryResource, Sn as WORK_ITEM_DETAIL_COMMENT_BODY_MAX_BYTES, Sr as TurnId, St as OrchestrationGetSnapshotError, T as McpListServersResult, Tt as OrchestrationMessage, U as ServerSettingsError, Ut as ProjectionPendingApprovalDecision, V as OpenCodeSettings, Vn as defaultInstanceIdForDriver, Vt as ProjectMetadataDir, W as KeybindingRule, Wn as TerminalCwdError, Wt as ProjectionPendingApprovalStatus, X as isToolLifecycleItemType, Xn as AuthBootstrapInput, Xt as ThreadArchivedPayload$1, Y as THREAD_JUMP_KEYBINDING_COMMANDS, Yn as OpenError, Yt as ThreadActivityAppendedPayload$1, Z as ProviderInterruptTurnInput, Zn as AuthClientMetadataDeviceType, Zt as ThreadAttachedToWorktreePayload$1, _ as AtlassianConnectionStatus, _n as WorktreeSourceControlStateUpdatedPayload$1, _t as OrchestrationDispatchCommandError, a as WS_METHODS, an as ThreadRuntimeModeSetPayload$1, ar as AuthSessionId, at as ClientOrchestrationCommand, b as GitManagerError, bn as WorktreeId, br as ThreadId, bt as OrchestrationEventType, cn as ThreadTokenModeSetPayload$1, cr as EnvironmentId, ct as DEFAULT_PROVIDER_INTERACTION_MODE, d as ProjectSearchEntriesError, dn as WorktreeArchivedPayload$1, dr as MessageId, dt as OrchestrationActorKind, en as ThreadInteractionModeSetPayload$1, er as AuthRevokePairingLinkInput, et as ProviderSendTurnInput, f as ProjectStageFileReferenceError, fn as WorktreeCreatedPayload$1, fr as NonNegativeInt, ft as OrchestrationAggregateKind, g as AtlassianConnectionKind, gn as WorktreeRestoredPayload$1, gt as OrchestrationCommandReceiptStatus, h as AtlassianConnectionError, hn as WorktreeMetaUpdatedPayload$1, ht as OrchestrationCheckpointSummary, i as fromLenientJson, in as ThreadRevertedPayload$1, ir as AtlassianResourceId, it as ChatAttachment, j as McpSettingsError, jn as VcsProcessExitError, jt as OrchestrationSessionStatus, k as McpServerConfig, kn as VcsDriverKind, kt as OrchestrationReplayEventsError, l as ProjectListEntriesError, ln as ThreadTurnDiffCompletedPayload$1, lr as EventId, lt as ModelSelection, m as AtlassianCapability, mn as WorktreeManualPositionSetPayload$1, mr as ProjectId, mt as OrchestrationCheckpointStatus, n as decodeJsonResult, nn as ThreadMetaUpdatedPayload$1, nr as ApprovalRequestId, nt as ProviderStopSessionInput, o as WsRpcGroup, on as ThreadSessionSetPayload$1, or as CheckpointRef, ot as DEFAULT_AGENT_TOKEN_MODE, p as ProjectWriteFileError, pn as WorktreeDeletedPayload$1, pr as PositiveInt, pt as OrchestrationCheckpointFile, q as MODEL_PICKER_JUMP_KEYBINDING_COMMANDS, qn as TerminalSessionLookupError, qt as ProviderSessionRuntimeStatus, r as formatSchemaError, rn as ThreadProposedPlanUpsertedPayload$1, rr as AtlassianConnectionId, rt as AgentTokenMode, s as FilesystemBrowseError, sn as ThreadStatusBucketOverriddenPayload$1, sr as CommandId, t as collectUint8StreamText, tn as ThreadMessageSentPayload, tr as AuthRpcError, tt as ProviderSessionStartInput, u as ProjectReadFileError, un as ThreadUnarchivedPayload$1, ur as IsoDateTime, ut as ORCHESTRATION_WS_METHODS, v as AtlassianProduct, vn as StatusBucket, vt as OrchestrationEvent, w as McpInventoryTool, wn as WorkItemProviderKind, wt as OrchestrationGetTurnDiffResult, x as TextGenerationError, xn as WORK_ITEM_DETAIL_BODY_MAX_BYTES, xr as TrimmedNonEmptyString, xt as OrchestrationGetFullThreadDiffError, y as GitCommandError, yn as Worktree, yt as OrchestrationEventMetadata, z as CursorSettings, zn as ProviderDriverKind, zt as ProjectDeletedPayload$1 } from "./collectUint8StreamText-Lv4GGI79.mjs";
5
4
  import { A as terminalRestartsTotal, B as mergeGitStatusParts, C as runtimeQueueDequeuesTotal, D as startupCommandGateQueueDepth, E as startupCommandGateEnqueuesTotal, F as WORKTREE_BRANCH_PREFIX, G as compactTraceAttributes, H as resolveAutoFeatureBranchName, I as buildTemporaryWorktreeBranchName, J as RuntimeMode$1, K as outcomeFromExit, L as dedupeRemoteBranchesWithLocalMatches, M as withMetrics, N as LocalDiagnosticsMetrics, O as startupCommandGateQueueHighWater, P as LocalDiagnosticsMetricsLive, Q as resolveStaticDir, R as detectSourceControlProviderFromGitRemoteUrl, S as runtimeQueueDepth, T as runtimeQueueHighWater, U as sanitizeBranchFragment, V as normalizeGitRemoteUrl, W as sanitizeFeatureBranchName, X as deriveServerPaths, Y as ServerConfig, Z as ensureServerDirectories, _ as providerTurnDuration, a as orchestrationCommandAckDuration, b as rpcRequestDuration, c as orchestrationEventsProcessedTotal, d as providerRuntimeEventsTotal, f as providerSessionsTotal, g as providerStartupQueueWaitDuration, h as providerStartupQueueHighWater, i as metricAttributes, j as terminalSessionsTotal, k as startupCommandGateQueueWaitDuration, l as providerEventLogRecordsDroppedTotal, m as providerStartupQueueDepth, n as gitCommandsTotal, o as orchestrationCommandDuration, p as providerStartupAdmissionTotal, q as DEFAULT_PORT, r as increment, s as orchestrationCommandsTotal, t as gitCommandDuration, u as providerMetricAttributes, v as providerTurnMetricAttributes, w as runtimeQueueEnqueuesTotal, x as rpcRequestsTotal, y as providerTurnsTotal, z as isTemporaryWorktreeBranch } from "./Metrics-6Xj17Se3.mjs";
5
+ import { a as makeForgejoDiscovery, c as sourceBranch, d as firstNonEmptyLine, f as probeSourceControlProvider, h as layer$19, i as makeBitbucketDiscovery, m as VcsProcess, n as githubDiscovery, o as SourceControlProvider, p as refineUnknownRemoteProvider, r as gitlabDiscovery, s as parseSourceControlOwnerRef, t as azureDevOpsDiscovery, u as detailFromCause } from "./SourceControlProviderDiscoveryCatalog-mJV_Xitr.mjs";
6
6
  import { n as detectSourceControlProviderFromRemoteUrl, r as getChangeRequestTerminologyForKind } from "./sourceControl-iWG-m4wE.mjs";
7
7
  import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
8
8
  import * as NodeServices from "@effect/platform-node/NodeServices";
@@ -31,10 +31,10 @@ import sharp from "sharp";
31
31
  import { RpcSerialization, RpcServer } from "effect/unstable/rpc";
32
32
  import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
33
33
  import * as Semaphore$1 from "effect/Semaphore";
34
+ import * as Random$1 from "effect/Random";
34
35
  import "effect/PlatformError";
35
36
  import * as SqlClient from "effect/unstable/sql/SqlClient";
36
37
  import * as Migrator from "effect/unstable/sql/Migrator";
37
- import * as Random$1 from "effect/Random";
38
38
  import fsPromises, { open, realpath } from "node:fs/promises";
39
39
  import * as Context$1 from "effect/Context";
40
40
  import "effect/Scope";
@@ -46,8 +46,8 @@ import * as Ref$1 from "effect/Ref";
46
46
  import * as Stream$1 from "effect/Stream";
47
47
  import * as SchemaIssue$1 from "effect/SchemaIssue";
48
48
  import * as Sink$1 from "effect/Sink";
49
- import { clamp } from "effect/Number";
50
49
  import * as SqlSchema from "effect/unstable/sql/SqlSchema";
50
+ import { clamp } from "effect/Number";
51
51
  import { pathToFileURL } from "node:url";
52
52
  import { parsePatchFiles } from "@pierre/diffs";
53
53
  import { monitorEventLoopDelay } from "node:perf_hooks";
@@ -1629,6 +1629,388 @@ const makeProviderMaintenanceCommandCoordinator = Effect.fn("makeProviderMainten
1629
1629
  return { withCommandLock };
1630
1630
  });
1631
1631
  //#endregion
1632
+ //#region src/atomicWrite.ts
1633
+ const writeFileStringAtomically = (input) => Effect.scoped(Effect.gen(function* () {
1634
+ const fs = yield* FileSystem.FileSystem;
1635
+ const path = yield* Path.Path;
1636
+ const tempFileId = yield* Random$1.nextUUIDv4;
1637
+ const targetDirectory = path.dirname(input.filePath);
1638
+ yield* fs.makeDirectory(targetDirectory, { recursive: true });
1639
+ const tempDirectory = yield* fs.makeTempDirectoryScoped({
1640
+ directory: targetDirectory,
1641
+ prefix: `${path.basename(input.filePath)}.`
1642
+ });
1643
+ const tempPath = path.join(tempDirectory, `${tempFileId}.tmp`);
1644
+ yield* fs.writeFileString(tempPath, input.contents);
1645
+ yield* fs.rename(tempPath, input.filePath);
1646
+ }));
1647
+ //#endregion
1648
+ //#region src/auth/Services/ServerSecretStore.ts
1649
+ var SecretStoreError = class extends Data.TaggedError("SecretStoreError") {};
1650
+ var ServerSecretStore = class extends Context.Service()("ryco/auth/Services/ServerSecretStore") {};
1651
+ //#endregion
1652
+ //#region src/auth/Layers/ServerSecretStore.ts
1653
+ const makeServerSecretStore = Effect.gen(function* () {
1654
+ const fileSystem = yield* FileSystem.FileSystem;
1655
+ const path = yield* Path.Path;
1656
+ const serverConfig = yield* ServerConfig;
1657
+ yield* fileSystem.makeDirectory(serverConfig.secretsDir, { recursive: true });
1658
+ yield* fileSystem.chmod(serverConfig.secretsDir, 448).pipe(Effect.mapError((cause) => new SecretStoreError({
1659
+ message: `Failed to secure secrets directory ${serverConfig.secretsDir}.`,
1660
+ cause
1661
+ })));
1662
+ const resolveSecretPath = (name) => path.join(serverConfig.secretsDir, `${name}.bin`);
1663
+ const ensureSecretDirectory = (secretPath) => {
1664
+ const directory = path.dirname(secretPath);
1665
+ return fileSystem.makeDirectory(directory, { recursive: true }).pipe(Effect.flatMap(() => fileSystem.chmod(directory, 448)));
1666
+ };
1667
+ const isPlatformError = (u) => Predicate.isTagged(u, "PlatformError");
1668
+ const get = (name) => fileSystem.readFile(resolveSecretPath(name)).pipe(Effect.map((bytes) => Uint8Array.from(bytes)), Effect.catch((cause) => cause.reason._tag === "NotFound" ? Effect.succeed(null) : Effect.fail(new SecretStoreError({
1669
+ message: `Failed to read secret ${name}.`,
1670
+ cause
1671
+ }))));
1672
+ const set = (name, value) => {
1673
+ const secretPath = resolveSecretPath(name);
1674
+ const tempPath = `${secretPath}.${Crypto.randomUUID()}.tmp`;
1675
+ return Effect.gen(function* () {
1676
+ yield* ensureSecretDirectory(secretPath);
1677
+ yield* fileSystem.writeFile(tempPath, value);
1678
+ yield* fileSystem.chmod(tempPath, 384);
1679
+ yield* fileSystem.rename(tempPath, secretPath);
1680
+ yield* fileSystem.chmod(secretPath, 384);
1681
+ }).pipe(Effect.catch((cause) => fileSystem.remove(tempPath).pipe(Effect.ignore, Effect.flatMap(() => Effect.fail(new SecretStoreError({
1682
+ message: `Failed to persist secret ${name}.`,
1683
+ cause
1684
+ }))))));
1685
+ };
1686
+ const create = (name, value) => {
1687
+ const secretPath = resolveSecretPath(name);
1688
+ return Effect.scoped(Effect.gen(function* () {
1689
+ yield* ensureSecretDirectory(secretPath);
1690
+ const file = yield* fileSystem.open(secretPath, {
1691
+ flag: "wx",
1692
+ mode: 384
1693
+ });
1694
+ yield* file.writeAll(value);
1695
+ yield* file.sync;
1696
+ yield* fileSystem.chmod(secretPath, 384);
1697
+ })).pipe(Effect.mapError((cause) => new SecretStoreError({
1698
+ message: `Failed to persist secret ${name}.`,
1699
+ cause
1700
+ })));
1701
+ };
1702
+ const getOrCreateRandom = (name, bytes) => get(name).pipe(Effect.flatMap((existing) => {
1703
+ if (existing) return Effect.succeed(existing);
1704
+ const generated = Crypto.randomBytes(bytes);
1705
+ return create(name, generated).pipe(Effect.as(Uint8Array.from(generated)), Effect.catchTag("SecretStoreError", (error) => isPlatformError(error.cause) && error.cause.reason._tag === "AlreadyExists" ? get(name).pipe(Effect.flatMap((created) => created !== null ? Effect.succeed(created) : Effect.fail(new SecretStoreError({ message: `Failed to read secret ${name} after concurrent creation.` })))) : Effect.fail(error)));
1706
+ }));
1707
+ const remove = (name) => fileSystem.remove(resolveSecretPath(name)).pipe(Effect.catch((cause) => cause.reason._tag === "NotFound" ? Effect.void : Effect.fail(new SecretStoreError({
1708
+ message: `Failed to remove secret ${name}.`,
1709
+ cause
1710
+ }))));
1711
+ return {
1712
+ get,
1713
+ set,
1714
+ getOrCreateRandom,
1715
+ remove
1716
+ };
1717
+ });
1718
+ const ServerSecretStoreLive = Layer.effect(ServerSecretStore, makeServerSecretStore);
1719
+ //#endregion
1720
+ //#region src/serverSettings.ts
1721
+ /**
1722
+ * ServerSettings - Server-authoritative settings service.
1723
+ *
1724
+ * Owns persistence, validation, and change notification of settings that affect
1725
+ * server-side behavior (binary paths, streaming mode, env mode, custom models,
1726
+ * text generation model selection).
1727
+ *
1728
+ * Follows the same pattern as `keybindings.ts`: JSON file + Cache + PubSub +
1729
+ * Semaphore + FileSystem.watch for concurrency and external edit detection.
1730
+ *
1731
+ * @module ServerSettings
1732
+ */
1733
+ const textEncoder$2 = new TextEncoder();
1734
+ const textDecoder$2 = new TextDecoder();
1735
+ function providerEnvironmentSecretName(input) {
1736
+ return `provider-env-${Buffer.from(input.instanceId, "utf8").toString("base64url")}-${Buffer.from(input.name, "utf8").toString("base64url")}`;
1737
+ }
1738
+ function redactProviderEnvironmentVariable(variable) {
1739
+ if (!variable.sensitive) {
1740
+ const { valueRedacted: _omit, ...rest } = variable;
1741
+ return rest;
1742
+ }
1743
+ return {
1744
+ ...variable,
1745
+ value: "",
1746
+ ...variable.value.length > 0 || variable.valueRedacted ? { valueRedacted: true } : {}
1747
+ };
1748
+ }
1749
+ function redactServerSettingsForClient(settings) {
1750
+ const providerInstances = Object.fromEntries(Object.entries(settings.providerInstances).map(([instanceId, instance]) => [instanceId, instance.environment ? {
1751
+ ...instance,
1752
+ environment: instance.environment.map(redactProviderEnvironmentVariable)
1753
+ } : instance]));
1754
+ return {
1755
+ ...settings,
1756
+ providerInstances
1757
+ };
1758
+ }
1759
+ var ServerSettingsService = class ServerSettingsService extends Context.Service()("ryco/serverSettings/ServerSettingsService") {
1760
+ static layerTest = (overrides = {}) => Layer.effect(ServerSettingsService, Effect.gen(function* () {
1761
+ const currentSettingsRef = yield* Ref.make(deepMerge(DEFAULT_SERVER_SETTINGS, overrides));
1762
+ return {
1763
+ start: Effect.void,
1764
+ ready: Effect.void,
1765
+ getSettings: Ref.get(currentSettingsRef),
1766
+ updateSettings: (patch) => Ref.get(currentSettingsRef).pipe(Effect.flatMap((currentSettings) => Schema.decodeEffect(ServerSettings)(applyServerSettingsPatch(currentSettings, patch)).pipe(Effect.mapError((cause) => new ServerSettingsError({
1767
+ settingsPath: "<memory>",
1768
+ detail: `failed to normalize server settings: ${SchemaIssue.makeFormatterDefault()(cause.issue)}`,
1769
+ cause
1770
+ })))), Effect.tap((nextSettings) => Ref.set(currentSettingsRef, nextSettings))),
1771
+ streamChanges: Stream.empty
1772
+ };
1773
+ }));
1774
+ };
1775
+ const ServerSettingsJson = fromLenientJson(ServerSettings);
1776
+ const getLegacyProviderSettings = (settings, provider) => settings.providers[provider];
1777
+ /**
1778
+ * Ensure the `textGenerationModelSelection` points to an enabled provider.
1779
+ * If the selected provider is disabled, fall back to the first enabled
1780
+ * provider with its default model. This is applied at read-time so the
1781
+ * persisted preference is preserved for when a provider is re-enabled.
1782
+ */
1783
+ function resolveTextGenerationProvider(settings) {
1784
+ const selection = settings.textGenerationModelSelection;
1785
+ const instanceConfig = settings.providerInstances[selection.instanceId];
1786
+ if (instanceConfig !== void 0) return instanceConfig.enabled ?? true ? settings : fallbackTextGenerationProvider(settings);
1787
+ if (isProviderDriverKind(selection.instanceId) && getLegacyProviderSettings(settings, selection.instanceId)?.enabled) return settings;
1788
+ return fallbackTextGenerationProvider(settings);
1789
+ }
1790
+ function fallbackTextGenerationProvider(settings) {
1791
+ const fallbackEntry = Object.entries(settings.providers).find(([, provider]) => provider.enabled);
1792
+ const fallback = fallbackEntry ? ProviderDriverKind.make(fallbackEntry[0]) : void 0;
1793
+ if (!fallback) return settings;
1794
+ return {
1795
+ ...settings,
1796
+ textGenerationModelSelection: {
1797
+ instanceId: ProviderInstanceId.make(fallback),
1798
+ model: DEFAULT_GIT_TEXT_GENERATION_MODEL_BY_PROVIDER[fallback] ?? "gpt-5.4-mini"
1799
+ }
1800
+ };
1801
+ }
1802
+ const ATOMIC_SETTINGS_KEYS = new Set(["textGenerationModelSelection"]);
1803
+ function stripDefaultServerSettings(current, defaults) {
1804
+ if (Array.isArray(current) || Array.isArray(defaults)) return Equal.equals(current, defaults) ? void 0 : current;
1805
+ if (current !== null && defaults !== null && typeof current === "object" && typeof defaults === "object") {
1806
+ const currentRecord = current;
1807
+ const defaultsRecord = defaults;
1808
+ const next = {};
1809
+ for (const key of Object.keys(currentRecord)) if (ATOMIC_SETTINGS_KEYS.has(key)) {
1810
+ if (!Equal.equals(currentRecord[key], defaultsRecord[key])) next[key] = currentRecord[key];
1811
+ } else {
1812
+ const stripped = stripDefaultServerSettings(currentRecord[key], defaultsRecord[key]);
1813
+ if (stripped !== void 0) next[key] = stripped;
1814
+ }
1815
+ return Object.keys(next).length > 0 ? next : void 0;
1816
+ }
1817
+ return Object.is(current, defaults) ? void 0 : current;
1818
+ }
1819
+ const makeServerSettings = Effect.gen(function* () {
1820
+ const { settingsPath } = yield* ServerConfig;
1821
+ const fs = yield* FileSystem.FileSystem;
1822
+ const pathService = yield* Path.Path;
1823
+ const secretStore = yield* ServerSecretStore;
1824
+ const writeSemaphore = yield* Semaphore$1.make(1);
1825
+ const cacheKey = "settings";
1826
+ const changesPubSub = yield* PubSub.unbounded();
1827
+ const startedRef = yield* Ref.make(false);
1828
+ const startedDeferred = yield* Deferred.make();
1829
+ const watcherScope = yield* Scope.make("sequential");
1830
+ yield* Effect.addFinalizer(() => Scope.close(watcherScope, Exit.void));
1831
+ const emitChange = (settings) => PubSub.publish(changesPubSub, settings).pipe(Effect.asVoid);
1832
+ const readConfigExists = fs.exists(settingsPath).pipe(Effect.mapError((cause) => new ServerSettingsError({
1833
+ settingsPath,
1834
+ detail: "failed to check settings file existence",
1835
+ cause
1836
+ })));
1837
+ const readRawConfig = fs.readFileString(settingsPath).pipe(Effect.mapError((cause) => new ServerSettingsError({
1838
+ settingsPath,
1839
+ detail: "failed to read settings file",
1840
+ cause
1841
+ })));
1842
+ const loadSettingsFromDisk = Effect.gen(function* () {
1843
+ if (!(yield* readConfigExists)) return DEFAULT_SERVER_SETTINGS;
1844
+ const raw = yield* readRawConfig;
1845
+ const decoded = Schema.decodeUnknownExit(ServerSettingsJson)(raw);
1846
+ if (decoded._tag === "Failure") {
1847
+ yield* Effect.logWarning("failed to parse settings.json, using defaults", {
1848
+ path: settingsPath,
1849
+ issues: Cause.pretty(decoded.cause)
1850
+ });
1851
+ return DEFAULT_SERVER_SETTINGS;
1852
+ }
1853
+ return decoded.value;
1854
+ });
1855
+ const settingsCache = yield* Cache.make({
1856
+ capacity: 1,
1857
+ lookup: () => loadSettingsFromDisk
1858
+ });
1859
+ const getSettingsFromCache = Cache.get(settingsCache, cacheKey);
1860
+ const toSettingsError = (detail, cause) => new ServerSettingsError({
1861
+ settingsPath,
1862
+ detail,
1863
+ cause
1864
+ });
1865
+ const materializeProviderEnvironmentSecrets = (settings) => Effect.gen(function* () {
1866
+ const providerInstances = { ...settings.providerInstances };
1867
+ for (const [instanceId, instance] of Object.entries(settings.providerInstances)) {
1868
+ if (!instance.environment) continue;
1869
+ const environment = [];
1870
+ for (const variable of instance.environment) {
1871
+ if (!variable.sensitive || !variable.valueRedacted) {
1872
+ environment.push(variable);
1873
+ continue;
1874
+ }
1875
+ const secret = yield* secretStore.get(providerEnvironmentSecretName({
1876
+ instanceId,
1877
+ name: variable.name
1878
+ })).pipe(Effect.mapError((cause) => toSettingsError(`failed to read sensitive environment variable ${variable.name}`, cause)));
1879
+ environment.push({
1880
+ ...variable,
1881
+ value: secret ? textDecoder$2.decode(secret) : ""
1882
+ });
1883
+ }
1884
+ providerInstances[instanceId] = {
1885
+ ...instance,
1886
+ environment
1887
+ };
1888
+ }
1889
+ return {
1890
+ ...settings,
1891
+ providerInstances
1892
+ };
1893
+ });
1894
+ const persistProviderEnvironmentSecrets = (current, next) => Effect.gen(function* () {
1895
+ const providerInstances = { ...next.providerInstances };
1896
+ const nextSecretKeys = /* @__PURE__ */ new Set();
1897
+ for (const [instanceId, instance] of Object.entries(next.providerInstances)) {
1898
+ if (!instance.environment) continue;
1899
+ const environment = [];
1900
+ for (const variable of instance.environment) {
1901
+ const secretName = providerEnvironmentSecretName({
1902
+ instanceId,
1903
+ name: variable.name
1904
+ });
1905
+ if (!variable.sensitive) {
1906
+ yield* secretStore.remove(secretName).pipe(Effect.mapError((cause) => toSettingsError(`failed to remove environment secret ${variable.name}`, cause)));
1907
+ environment.push(redactProviderEnvironmentVariable(variable));
1908
+ continue;
1909
+ }
1910
+ nextSecretKeys.add(secretName);
1911
+ if (!variable.valueRedacted) {
1912
+ if (variable.value.length > 0) {
1913
+ yield* secretStore.set(secretName, textEncoder$2.encode(variable.value)).pipe(Effect.mapError((cause) => toSettingsError(`failed to persist environment secret ${variable.name}`, cause)));
1914
+ environment.push({
1915
+ ...variable,
1916
+ value: "",
1917
+ valueRedacted: true
1918
+ });
1919
+ } else {
1920
+ yield* secretStore.remove(secretName).pipe(Effect.mapError((cause) => toSettingsError(`failed to remove environment secret ${variable.name}`, cause)));
1921
+ const { valueRedacted: _omit, ...rest } = variable;
1922
+ environment.push(rest);
1923
+ }
1924
+ continue;
1925
+ }
1926
+ environment.push(redactProviderEnvironmentVariable(variable));
1927
+ }
1928
+ providerInstances[instanceId] = {
1929
+ ...instance,
1930
+ environment
1931
+ };
1932
+ }
1933
+ for (const [instanceId, instance] of Object.entries(current.providerInstances)) for (const variable of instance.environment ?? []) {
1934
+ if (!variable.sensitive) continue;
1935
+ const secretName = providerEnvironmentSecretName({
1936
+ instanceId,
1937
+ name: variable.name
1938
+ });
1939
+ if (nextSecretKeys.has(secretName)) continue;
1940
+ yield* secretStore.remove(secretName).pipe(Effect.mapError((cause) => toSettingsError(`failed to remove stale environment secret ${variable.name}`, cause)));
1941
+ }
1942
+ return {
1943
+ ...next,
1944
+ providerInstances
1945
+ };
1946
+ });
1947
+ const writeSettingsAtomically = (settings) => {
1948
+ const sparseSettings = stripDefaultServerSettings(settings, DEFAULT_SERVER_SETTINGS) ?? {};
1949
+ return writeFileStringAtomically({
1950
+ filePath: settingsPath,
1951
+ contents: `${JSON.stringify(sparseSettings, null, 2)}\n`
1952
+ }).pipe(Effect.provideService(FileSystem.FileSystem, fs), Effect.provideService(Path.Path, pathService), Effect.mapError((cause) => new ServerSettingsError({
1953
+ settingsPath,
1954
+ detail: "failed to write settings file",
1955
+ cause
1956
+ })));
1957
+ };
1958
+ const revalidateAndEmit = writeSemaphore.withPermits(1)(Effect.gen(function* () {
1959
+ yield* Cache.invalidate(settingsCache, cacheKey);
1960
+ yield* emitChange(yield* getSettingsFromCache);
1961
+ }));
1962
+ const startWatcher = Effect.gen(function* () {
1963
+ const settingsDir = pathService.dirname(settingsPath);
1964
+ const settingsFile = pathService.basename(settingsPath);
1965
+ const settingsPathResolved = pathService.resolve(settingsPath);
1966
+ yield* fs.makeDirectory(settingsDir, { recursive: true }).pipe(Effect.mapError((cause) => new ServerSettingsError({
1967
+ settingsPath,
1968
+ detail: "failed to prepare settings directory",
1969
+ cause
1970
+ })));
1971
+ const revalidateAndEmitSafely = revalidateAndEmit.pipe(Effect.ignoreCause({ log: true }));
1972
+ const debouncedSettingsEvents = fs.watch(settingsDir).pipe(Stream.filter((event) => {
1973
+ return event.path === settingsFile || event.path === settingsPath || pathService.resolve(settingsDir, event.path) === settingsPathResolved;
1974
+ }), Stream.debounce(Duration.millis(100)));
1975
+ yield* Stream.runForEach(debouncedSettingsEvents, () => revalidateAndEmitSafely).pipe(Effect.ignoreCause({ log: true }), Effect.forkIn(watcherScope), Effect.asVoid);
1976
+ });
1977
+ return {
1978
+ start: Effect.gen(function* () {
1979
+ if (!(yield* Ref.modify(startedRef, (started) => [!started, true]))) return yield* Deferred.await(startedDeferred);
1980
+ const startup = Effect.gen(function* () {
1981
+ yield* startWatcher;
1982
+ yield* Cache.invalidate(settingsCache, cacheKey);
1983
+ yield* getSettingsFromCache;
1984
+ });
1985
+ const startupExit = yield* Effect.exit(startup);
1986
+ if (startupExit._tag === "Failure") {
1987
+ yield* Deferred.failCause(startedDeferred, startupExit.cause).pipe(Effect.orDie);
1988
+ return yield* Effect.failCause(startupExit.cause);
1989
+ }
1990
+ yield* Deferred.succeed(startedDeferred, void 0).pipe(Effect.orDie);
1991
+ }),
1992
+ ready: Deferred.await(startedDeferred),
1993
+ getSettings: getSettingsFromCache.pipe(Effect.flatMap(materializeProviderEnvironmentSecrets), Effect.map(resolveTextGenerationProvider)),
1994
+ updateSettings: (patch) => writeSemaphore.withPermits(1)(Effect.gen(function* () {
1995
+ const current = yield* getSettingsFromCache;
1996
+ const nextPersisted = yield* persistProviderEnvironmentSecrets(current, applyServerSettingsPatch(current, patch));
1997
+ const next = yield* Schema.decodeEffect(ServerSettings)(nextPersisted).pipe(Effect.mapError((cause) => new ServerSettingsError({
1998
+ settingsPath: "<memory>",
1999
+ detail: `failed to normalize server settings: ${SchemaIssue.makeFormatterDefault()(cause.issue)}`,
2000
+ cause
2001
+ })));
2002
+ yield* writeSettingsAtomically(next);
2003
+ yield* Cache.set(settingsCache, cacheKey, next);
2004
+ yield* emitChange(next);
2005
+ return resolveTextGenerationProvider(yield* materializeProviderEnvironmentSecrets(next));
2006
+ })),
2007
+ get streamChanges() {
2008
+ return Stream.fromPubSub(changesPubSub).pipe(Stream.mapEffect((settings) => materializeProviderEnvironmentSecrets(settings).pipe(Effect.catch((error) => Effect.logWarning("failed to materialize provider environment secrets", { detail: error.detail }).pipe(Effect.as(settings))))), Stream.map(resolveTextGenerationProvider));
2009
+ }
2010
+ };
2011
+ });
2012
+ const ServerSettingsLive = Layer.effect(ServerSettingsService, makeServerSettings).pipe(Layer.provide(ServerSecretStoreLive));
2013
+ //#endregion
1632
2014
  //#region src/provider/cliVersion.ts
1633
2015
  const CLI_VERSION_NUMBER_SEGMENT = /^\d+$/;
1634
2016
  function normalizeCliVersion(version) {
@@ -1929,7 +2311,8 @@ const resolveLatestProviderVersion = Effect.fn("resolveLatestProviderVersion")(f
1929
2311
  });
1930
2312
  const enrichProviderSnapshotWithVersionAdvisory = Effect.fn("enrichProviderSnapshotWithVersionAdvisory")(function* (snapshot, maintenanceCapabilities) {
1931
2313
  const capabilities = maintenanceCapabilities ?? makeManualProviderMaintenanceCapabilities$1(snapshot.driver);
1932
- if (!snapshot.enabled || !snapshot.installed || !snapshot.version) return {
2314
+ const { enableProviderUpdateChecks } = yield* (yield* ServerSettingsService).getSettings.pipe(Effect.orElseSucceed(() => DEFAULT_SERVER_SETTINGS));
2315
+ if (!enableProviderUpdateChecks || !snapshot.enabled || !snapshot.installed || !snapshot.version) return {
1933
2316
  ...snapshot,
1934
2317
  versionAdvisory: createProviderVersionAdvisory({
1935
2318
  driver: snapshot.driver,
@@ -2024,6 +2407,7 @@ const make$21 = Effect.fn("ProviderMaintenanceRunner.make")(function* () {
2024
2407
  const providerRegistry = yield* ProviderRegistry;
2025
2408
  const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
2026
2409
  const httpClient = yield* HttpClient.HttpClient;
2410
+ const serverSettings = yield* ServerSettingsService;
2027
2411
  const runMaintenanceCommand = (command, args) => runProviderMaintenanceCommandWithSpawner({
2028
2412
  spawner,
2029
2413
  command,
@@ -2042,7 +2426,7 @@ const make$21 = Effect.fn("ProviderMaintenanceRunner.make")(function* () {
2042
2426
  providers,
2043
2427
  verifiedProviders: []
2044
2428
  });
2045
- return Effect.forEach(refreshedProviders, (refreshedProvider) => enrichProviderSnapshotWithVersionAdvisory(refreshedProvider, maintenanceCapabilities).pipe(Effect.provideService(HttpClient.HttpClient, httpClient)), { concurrency: "unbounded" }).pipe(Effect.map((verifiedProviders) => ({
2429
+ return Effect.forEach(refreshedProviders, (refreshedProvider) => enrichProviderSnapshotWithVersionAdvisory(refreshedProvider, maintenanceCapabilities).pipe(Effect.provideService(HttpClient.HttpClient, httpClient), Effect.provideService(ServerSettingsService, serverSettings)), { concurrency: "unbounded" }).pipe(Effect.map((verifiedProviders) => ({
2046
2430
  providers,
2047
2431
  verifiedProviders
2048
2432
  })), Effect.catchCause((cause) => Effect.logWarning("Provider post-update version verification failed", {
@@ -2132,78 +2516,6 @@ const make$21 = Effect.fn("ProviderMaintenanceRunner.make")(function* () {
2132
2516
  });
2133
2517
  const layer$18 = Layer.effect(ProviderMaintenanceRunner, make$21());
2134
2518
  //#endregion
2135
- //#region src/auth/Services/ServerSecretStore.ts
2136
- var SecretStoreError = class extends Data.TaggedError("SecretStoreError") {};
2137
- var ServerSecretStore = class extends Context.Service()("ryco/auth/Services/ServerSecretStore") {};
2138
- //#endregion
2139
- //#region src/auth/Layers/ServerSecretStore.ts
2140
- const makeServerSecretStore = Effect.gen(function* () {
2141
- const fileSystem = yield* FileSystem.FileSystem;
2142
- const path = yield* Path.Path;
2143
- const serverConfig = yield* ServerConfig;
2144
- yield* fileSystem.makeDirectory(serverConfig.secretsDir, { recursive: true });
2145
- yield* fileSystem.chmod(serverConfig.secretsDir, 448).pipe(Effect.mapError((cause) => new SecretStoreError({
2146
- message: `Failed to secure secrets directory ${serverConfig.secretsDir}.`,
2147
- cause
2148
- })));
2149
- const resolveSecretPath = (name) => path.join(serverConfig.secretsDir, `${name}.bin`);
2150
- const ensureSecretDirectory = (secretPath) => {
2151
- const directory = path.dirname(secretPath);
2152
- return fileSystem.makeDirectory(directory, { recursive: true }).pipe(Effect.flatMap(() => fileSystem.chmod(directory, 448)));
2153
- };
2154
- const isPlatformError = (u) => Predicate.isTagged(u, "PlatformError");
2155
- const get = (name) => fileSystem.readFile(resolveSecretPath(name)).pipe(Effect.map((bytes) => Uint8Array.from(bytes)), Effect.catch((cause) => cause.reason._tag === "NotFound" ? Effect.succeed(null) : Effect.fail(new SecretStoreError({
2156
- message: `Failed to read secret ${name}.`,
2157
- cause
2158
- }))));
2159
- const set = (name, value) => {
2160
- const secretPath = resolveSecretPath(name);
2161
- const tempPath = `${secretPath}.${Crypto.randomUUID()}.tmp`;
2162
- return Effect.gen(function* () {
2163
- yield* ensureSecretDirectory(secretPath);
2164
- yield* fileSystem.writeFile(tempPath, value);
2165
- yield* fileSystem.chmod(tempPath, 384);
2166
- yield* fileSystem.rename(tempPath, secretPath);
2167
- yield* fileSystem.chmod(secretPath, 384);
2168
- }).pipe(Effect.catch((cause) => fileSystem.remove(tempPath).pipe(Effect.ignore, Effect.flatMap(() => Effect.fail(new SecretStoreError({
2169
- message: `Failed to persist secret ${name}.`,
2170
- cause
2171
- }))))));
2172
- };
2173
- const create = (name, value) => {
2174
- const secretPath = resolveSecretPath(name);
2175
- return Effect.scoped(Effect.gen(function* () {
2176
- yield* ensureSecretDirectory(secretPath);
2177
- const file = yield* fileSystem.open(secretPath, {
2178
- flag: "wx",
2179
- mode: 384
2180
- });
2181
- yield* file.writeAll(value);
2182
- yield* file.sync;
2183
- yield* fileSystem.chmod(secretPath, 384);
2184
- })).pipe(Effect.mapError((cause) => new SecretStoreError({
2185
- message: `Failed to persist secret ${name}.`,
2186
- cause
2187
- })));
2188
- };
2189
- const getOrCreateRandom = (name, bytes) => get(name).pipe(Effect.flatMap((existing) => {
2190
- if (existing) return Effect.succeed(existing);
2191
- const generated = Crypto.randomBytes(bytes);
2192
- return create(name, generated).pipe(Effect.as(Uint8Array.from(generated)), Effect.catchTag("SecretStoreError", (error) => isPlatformError(error.cause) && error.cause.reason._tag === "AlreadyExists" ? get(name).pipe(Effect.flatMap((created) => created !== null ? Effect.succeed(created) : Effect.fail(new SecretStoreError({ message: `Failed to read secret ${name} after concurrent creation.` })))) : Effect.fail(error)));
2193
- }));
2194
- const remove = (name) => fileSystem.remove(resolveSecretPath(name)).pipe(Effect.catch((cause) => cause.reason._tag === "NotFound" ? Effect.void : Effect.fail(new SecretStoreError({
2195
- message: `Failed to remove secret ${name}.`,
2196
- cause
2197
- }))));
2198
- return {
2199
- get,
2200
- set,
2201
- getOrCreateRandom,
2202
- remove
2203
- };
2204
- });
2205
- const ServerSecretStoreLive = Layer.effect(ServerSecretStore, makeServerSecretStore);
2206
- //#endregion
2207
2519
  //#region src/persistence/Errors.ts
2208
2520
  var PersistenceSqlError = class extends Schema.TaggedErrorClass()("PersistenceSqlError", {
2209
2521
  operation: Schema.String,
@@ -3897,6 +4209,35 @@ var _040_ProjectionThreadsProjectUpdatedAtIndex_default = Effect$1.gen(function*
3897
4209
  `;
3898
4210
  });
3899
4211
  //#endregion
4212
+ //#region src/persistence/Migrations/041_ProjectionThreadsSubagentNesting.ts
4213
+ var _041_ProjectionThreadsSubagentNesting_default = Effect$1.gen(function* () {
4214
+ const sql = yield* SqlClient.SqlClient;
4215
+ const columns = yield* sql`
4216
+ PRAGMA table_info(projection_threads)
4217
+ `;
4218
+ const columnNames = new Set(columns.map((column) => column.name));
4219
+ if (!columnNames.has("thread_kind")) yield* sql`
4220
+ ALTER TABLE projection_threads
4221
+ ADD COLUMN thread_kind TEXT NOT NULL DEFAULT 'normal'
4222
+ `;
4223
+ if (!columnNames.has("visibility")) yield* sql`
4224
+ ALTER TABLE projection_threads
4225
+ ADD COLUMN visibility TEXT NOT NULL DEFAULT 'normal'
4226
+ `;
4227
+ if (!columnNames.has("parent_thread_id")) yield* sql`
4228
+ ALTER TABLE projection_threads
4229
+ ADD COLUMN parent_thread_id TEXT
4230
+ `;
4231
+ if (!columnNames.has("parent_subagent_id")) yield* sql`
4232
+ ALTER TABLE projection_threads
4233
+ ADD COLUMN parent_subagent_id TEXT
4234
+ `;
4235
+ yield* sql`
4236
+ CREATE INDEX IF NOT EXISTS idx_projection_threads_parent_thread
4237
+ ON projection_threads(parent_thread_id, created_at, thread_id)
4238
+ `;
4239
+ });
4240
+ //#endregion
3900
4241
  //#region src/persistence/Migrations.ts
3901
4242
  /**
3902
4243
  * MigrationsLive - Migration runner with inline loader
@@ -4117,6 +4458,11 @@ const migrationEntries = [
4117
4458
  40,
4118
4459
  "ProjectionThreadsProjectUpdatedAtIndex",
4119
4460
  _040_ProjectionThreadsProjectUpdatedAtIndex_default
4461
+ ],
4462
+ [
4463
+ 41,
4464
+ "ProjectionThreadsSubagentNesting",
4465
+ _041_ProjectionThreadsSubagentNesting_default
4120
4466
  ]
4121
4467
  ];
4122
4468
  const makeMigrationLoader = (throughId) => Migrator.fromRecord(Object.fromEntries(migrationEntries.filter(([id]) => throughId === void 0 || id <= throughId).map(([id, name, migration]) => [`${id}_${name}`, migration])));
@@ -4186,6 +4532,45 @@ const repairProjectionTokenModeColumns = Effect$1.fn("repairProjectionTokenModeC
4186
4532
  yield* Effect$1.log("Repaired projection_thread_sessions.token_mode column");
4187
4533
  }
4188
4534
  });
4535
+ const repairProjectionThreadSubagentNestingColumns = Effect$1.fn("repairProjectionThreadSubagentNestingColumns")(function* () {
4536
+ const sql = yield* SqlClient.SqlClient;
4537
+ if ((yield* sql`
4538
+ SELECT name FROM sqlite_master
4539
+ WHERE type = 'table' AND name = 'projection_threads'
4540
+ `).length === 0) return;
4541
+ const columns = yield* sql`
4542
+ PRAGMA table_info(projection_threads)
4543
+ `;
4544
+ const columnNames = new Set(columns.map((column) => column.name));
4545
+ if (!columnNames.has("thread_kind")) {
4546
+ yield* sql`
4547
+ ALTER TABLE projection_threads
4548
+ ADD COLUMN thread_kind TEXT NOT NULL DEFAULT 'normal'
4549
+ `;
4550
+ yield* Effect$1.log("Repaired projection_threads.thread_kind column");
4551
+ }
4552
+ if (!columnNames.has("visibility")) {
4553
+ yield* sql`
4554
+ ALTER TABLE projection_threads
4555
+ ADD COLUMN visibility TEXT NOT NULL DEFAULT 'normal'
4556
+ `;
4557
+ yield* Effect$1.log("Repaired projection_threads.visibility column");
4558
+ }
4559
+ if (!columnNames.has("parent_thread_id")) {
4560
+ yield* sql`
4561
+ ALTER TABLE projection_threads
4562
+ ADD COLUMN parent_thread_id TEXT
4563
+ `;
4564
+ yield* Effect$1.log("Repaired projection_threads.parent_thread_id column");
4565
+ }
4566
+ if (!columnNames.has("parent_subagent_id")) {
4567
+ yield* sql`
4568
+ ALTER TABLE projection_threads
4569
+ ADD COLUMN parent_subagent_id TEXT
4570
+ `;
4571
+ yield* Effect$1.log("Repaired projection_threads.parent_subagent_id column");
4572
+ }
4573
+ });
4189
4574
  /**
4190
4575
  * Run all pending migrations.
4191
4576
  *
@@ -4202,6 +4587,7 @@ const runMigrations = Effect$1.fn("runMigrations")(function* ({ toMigrationInclu
4202
4587
  if (toMigrationInclusive === void 0 || toMigrationInclusive >= 31) yield* repairProjectionWorktreeTitleColumn();
4203
4588
  if (toMigrationInclusive === void 0 || toMigrationInclusive >= 34) yield* repairProjectionProjectAvatarColumns();
4204
4589
  if (toMigrationInclusive === void 0 || toMigrationInclusive >= 35) yield* repairProjectionTokenModeColumns();
4590
+ if (toMigrationInclusive === void 0 || toMigrationInclusive >= 41) yield* repairProjectionThreadSubagentNestingColumns();
4205
4591
  yield* Effect$1.log("Migrations ran successfully").pipe(Effect$1.annotateLogs({ migrations: executedMigrations.map(([id, name]) => `${id}_${name}`) }));
4206
4592
  return executedMigrations;
4207
4593
  });
@@ -4995,7 +5381,7 @@ Schema.Struct({
4995
5381
  var ProjectAtlassianLinkRepository = class extends Context.Service()("ryco/persistence/Services/ProjectAtlassianLinks/ProjectAtlassianLinkRepository") {};
4996
5382
  //#endregion
4997
5383
  //#region src/atlassian/AtlassianConnectionService.ts
4998
- const textEncoder$2 = new TextEncoder();
5384
+ const textEncoder$1 = new TextEncoder();
4999
5385
  var AtlassianConnectionService = class extends Context.Service()("ryco/atlassian/AtlassianConnectionService") {};
5000
5386
  function atlassianError(operation, detail, cause) {
5001
5387
  return new AtlassianConnectionError({
@@ -5123,7 +5509,7 @@ const make$19 = Effect.fn("makeAtlassianConnectionService")(function* () {
5123
5509
  createdAt,
5124
5510
  updatedAt: createdAt
5125
5511
  };
5126
- return secretStore.set(manualBitbucketTokenSecretName(connectionId), textEncoder$2.encode(input.token)).pipe(Effect.flatMap(() => connections.upsert(record)), cleanupSecretOnFailure(manualBitbucketTokenSecretName(connectionId)), Effect.as(toSummary(record)), Effect.mapError(mapError$1("atlassian.saveManualBitbucketToken", "Failed to save the Bitbucket token.")));
5512
+ return secretStore.set(manualBitbucketTokenSecretName(connectionId), textEncoder$1.encode(input.token)).pipe(Effect.flatMap(() => connections.upsert(record)), cleanupSecretOnFailure(manualBitbucketTokenSecretName(connectionId)), Effect.as(toSummary(record)), Effect.mapError(mapError$1("atlassian.saveManualBitbucketToken", "Failed to save the Bitbucket token.")));
5127
5513
  },
5128
5514
  saveManualJiraToken: (input) => {
5129
5515
  const createdAt = nowIso$2();
@@ -5159,7 +5545,7 @@ const make$19 = Effect.fn("makeAtlassianConnectionService")(function* () {
5159
5545
  avatarUrl: null,
5160
5546
  updatedAt: createdAt
5161
5547
  };
5162
- return secretStore.set(manualJiraTokenSecretName(connectionId), textEncoder$2.encode(input.token)).pipe(Effect.flatMap(() => connections.upsert(record)), Effect.flatMap(() => resources.upsertForConnection({
5548
+ return secretStore.set(manualJiraTokenSecretName(connectionId), textEncoder$1.encode(input.token)).pipe(Effect.flatMap(() => connections.upsert(record)), Effect.flatMap(() => resources.upsertForConnection({
5163
5549
  connectionId,
5164
5550
  resources: [resource]
5165
5551
  })), cleanupSecretOnFailure(manualJiraTokenSecretName(connectionId)), Effect.as(toSummary(record)), Effect.mapError(mapError$1("atlassian.saveManualJiraToken", "Failed to save the Jira API token.")));
@@ -5275,6 +5661,11 @@ const NON_REPOSITORY_STATUS_DETAILS = Object.freeze({
5275
5661
  behindCount: 0,
5276
5662
  aheadOfDefaultCount: 0
5277
5663
  });
5664
+ const emptyDiffTotals = () => ({
5665
+ files: [],
5666
+ insertions: 0,
5667
+ deletions: 0
5668
+ });
5278
5669
  var StatusRemoteRefreshCacheKey = class extends Data.Class {};
5279
5670
  function parseBranchAb(value) {
5280
5671
  const match = value.match(/^\+(\d+)\s+-(\d+)$/);
@@ -5921,6 +6312,31 @@ const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function* (option
5921
6312
  const parsed = Number.parseInt(result.stdout.trim(), 10);
5922
6313
  return Number.isFinite(parsed) ? Math.max(0, parsed) : 0;
5923
6314
  });
6315
+ const readCommittedAgainstBase = Effect.fn("readCommittedAgainstBase")(function* (cwd, refName) {
6316
+ const baseRef = yield* resolveBaseBranchForNoUpstream(cwd, refName).pipe(Effect.catch(() => Effect.succeed(null)));
6317
+ if (!baseRef) return emptyDiffTotals();
6318
+ const result = yield* executeGit("GitVcsDriver.readCommittedAgainstBase.diff", cwd, [
6319
+ "diff",
6320
+ "--numstat",
6321
+ `${baseRef}...HEAD`
6322
+ ], { allowNonZeroExit: true });
6323
+ if (result.exitCode !== 0) return emptyDiffTotals();
6324
+ let insertions = 0;
6325
+ let deletions = 0;
6326
+ return {
6327
+ files: parseNumstatEntries(result.stdout).map((entry) => {
6328
+ insertions += entry.insertions;
6329
+ deletions += entry.deletions;
6330
+ return {
6331
+ path: entry.path,
6332
+ insertions: entry.insertions,
6333
+ deletions: entry.deletions
6334
+ };
6335
+ }).toSorted((a, b) => a.path.localeCompare(b.path)),
6336
+ insertions,
6337
+ deletions
6338
+ };
6339
+ });
5924
6340
  const readBranchRecency = Effect.fn("readBranchRecency")(function* (cwd) {
5925
6341
  const branchRecency = yield* executeGit("GitVcsDriver.readBranchRecency", cwd, [
5926
6342
  "for-each-ref",
@@ -6039,6 +6455,7 @@ const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function* (option
6039
6455
  });
6040
6456
  }
6041
6457
  files.sort((a, b) => a.path.localeCompare(b.path));
6458
+ const committed = refName && !isDefaultBranch ? yield* readCommittedAgainstBase(cwd, refName).pipe(Effect.catch(() => Effect.succeed(emptyDiffTotals()))) : void 0;
6042
6459
  return {
6043
6460
  isRepo: true,
6044
6461
  hasOriginRemote: hasPrimaryRemote,
@@ -6051,6 +6468,7 @@ const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function* (option
6051
6468
  insertions,
6052
6469
  deletions
6053
6470
  },
6471
+ ...committed ? { committed } : {},
6054
6472
  hasUpstream: upstreamRef !== null,
6055
6473
  aheadCount,
6056
6474
  behindCount,
@@ -6071,6 +6489,7 @@ const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function* (option
6071
6489
  refName: details.branch,
6072
6490
  hasWorkingTreeChanges: details.hasWorkingTreeChanges,
6073
6491
  workingTree: details.workingTree,
6492
+ ...details.committed ? { committed: details.committed } : {},
6074
6493
  hasUpstream: details.hasUpstream,
6075
6494
  aheadCount: details.aheadCount,
6076
6495
  behindCount: details.behindCount,
@@ -6963,7 +7382,7 @@ const layer$13 = Layer.effect(VcsDriverRegistry, make$16()).pipe(Layer.provide(l
6963
7382
  //#endregion
6964
7383
  //#region src/sourceControl/BitbucketApi.ts
6965
7384
  const DEFAULT_API_BASE_URL = "https://api.bitbucket.org/2.0";
6966
- const textDecoder$2 = new TextDecoder();
7385
+ const textDecoder$1 = new TextDecoder();
6967
7386
  const BitbucketApiEnvConfig = Config.all({
6968
7387
  baseUrl: Config.string("RYCO_BITBUCKET_API_BASE_URL").pipe(Config.withDefault(DEFAULT_API_BASE_URL)),
6969
7388
  accessToken: Config.string("RYCO_BITBUCKET_ACCESS_TOKEN").pipe(Config.option),
@@ -7308,7 +7727,7 @@ const make$15 = Effect.fn("makeBitbucketApi")(function* () {
7308
7727
  cause
7309
7728
  })));
7310
7729
  if (!tokenBytes || tokenBytes.length === 0) continue;
7311
- const token = textDecoder$2.decode(tokenBytes).trim();
7730
+ const token = textDecoder$1.decode(tokenBytes).trim();
7312
7731
  if (!token) continue;
7313
7732
  return {
7314
7733
  source: "stored",
@@ -10532,26 +10951,26 @@ const make$11 = Effect.fn("makeSourceControlProviderRegistry")(function* () {
10532
10951
  const azureDevOpsCli = yield* AzureDevOpsCli;
10533
10952
  const fileSystem = yield* FileSystem.FileSystem;
10534
10953
  const github = yield* makeLazyProvider("github", Effect.tryPromise({
10535
- try: () => import("./GitHubSourceControlProvider-C-LGwho3.mjs"),
10954
+ try: () => import("./GitHubSourceControlProvider-26IofDAO.mjs"),
10536
10955
  catch: (cause) => providerLoadError("github", cause)
10537
10956
  }).pipe(Effect.flatMap((module) => module.make()), Effect.provideService(GitHubCli, githubCli), Effect.provideService(FileSystem.FileSystem, fileSystem)));
10538
10957
  const gitlab = yield* makeLazyProvider("gitlab", Effect.tryPromise({
10539
- try: () => import("./GitLabSourceControlProvider-CkeT2aEx.mjs"),
10958
+ try: () => import("./GitLabSourceControlProvider-DePct78W.mjs"),
10540
10959
  catch: (cause) => providerLoadError("gitlab", cause)
10541
10960
  }).pipe(Effect.flatMap((module) => module.make()), Effect.provideService(GitLabCli, gitlabCli)));
10542
10961
  const bitbucket = yield* makeLazyProvider("bitbucket", Effect.tryPromise({
10543
- try: () => import("./BitbucketSourceControlProvider-CYR_BD1d.mjs"),
10962
+ try: () => import("./BitbucketSourceControlProvider-CKH09tfT.mjs"),
10544
10963
  catch: (cause) => providerLoadError("bitbucket", cause)
10545
10964
  }).pipe(Effect.flatMap((module) => module.make()), Effect.provideService(BitbucketApi, bitbucketApi)), {
10546
10965
  searchRepositories: true,
10547
10966
  cloneAuthentication: true
10548
10967
  });
10549
10968
  const forgejo = yield* makeLazyProvider("forgejo", Effect.tryPromise({
10550
- try: () => import("./ForgejoSourceControlProvider-DX6d9gvz.mjs"),
10969
+ try: () => import("./ForgejoSourceControlProvider-e-4hvvZ_.mjs"),
10551
10970
  catch: (cause) => providerLoadError("forgejo", cause)
10552
10971
  }).pipe(Effect.flatMap((module) => module.make()), Effect.provideService(ForgejoApi, forgejoApi)));
10553
10972
  const azureDevOps = yield* makeLazyProvider("azure-devops", Effect.tryPromise({
10554
- try: () => import("./AzureDevOpsSourceControlProvider-CC2_COxP.mjs"),
10973
+ try: () => import("./AzureDevOpsSourceControlProvider-CF5LuCHp.mjs"),
10555
10974
  catch: (cause) => providerLoadError("azure-devops", cause)
10556
10975
  }).pipe(Effect.flatMap((module) => module.make()), Effect.provideService(AzureDevOpsCli, azureDevOpsCli)));
10557
10976
  const bitbucketDiscovery = makeBitbucketDiscovery(bitbucketApi);
@@ -10674,22 +11093,6 @@ var CheckpointDiffQuery = class extends Context.Service()("ryco/checkpointing/Se
10674
11093
  //#region src/diagnostics/Services/Diagnostics.ts
10675
11094
  var Diagnostics = class extends Context.Service()("ryco/diagnostics/Services/Diagnostics") {};
10676
11095
  //#endregion
10677
- //#region src/atomicWrite.ts
10678
- const writeFileStringAtomically = (input) => Effect.scoped(Effect.gen(function* () {
10679
- const fs = yield* FileSystem.FileSystem;
10680
- const path = yield* Path.Path;
10681
- const tempFileId = yield* Random$1.nextUUIDv4;
10682
- const targetDirectory = path.dirname(input.filePath);
10683
- yield* fs.makeDirectory(targetDirectory, { recursive: true });
10684
- const tempDirectory = yield* fs.makeTempDirectoryScoped({
10685
- directory: targetDirectory,
10686
- prefix: `${path.basename(input.filePath)}.`
10687
- });
10688
- const tempPath = path.join(tempDirectory, `${tempFileId}.tmp`);
10689
- yield* fs.writeFileString(tempPath, input.contents);
10690
- yield* fs.rename(tempPath, input.filePath);
10691
- }));
10692
- //#endregion
10693
11096
  //#region ../../packages/shared/src/keybindings.ts
10694
11097
  const DEFAULT_KEYBINDINGS = [
10695
11098
  {
@@ -26075,300 +26478,6 @@ async function runProcess(command, args, options = {}) {
26075
26478
  });
26076
26479
  }
26077
26480
  //#endregion
26078
- //#region src/serverSettings.ts
26079
- /**
26080
- * ServerSettings - Server-authoritative settings service.
26081
- *
26082
- * Owns persistence, validation, and change notification of settings that affect
26083
- * server-side behavior (binary paths, streaming mode, env mode, custom models,
26084
- * text generation model selection).
26085
- *
26086
- * Follows the same pattern as `keybindings.ts`: JSON file + Cache + PubSub +
26087
- * Semaphore + FileSystem.watch for concurrency and external edit detection.
26088
- *
26089
- * @module ServerSettings
26090
- */
26091
- const textEncoder$1 = new TextEncoder();
26092
- const textDecoder$1 = new TextDecoder();
26093
- function providerEnvironmentSecretName(input) {
26094
- return `provider-env-${Buffer.from(input.instanceId, "utf8").toString("base64url")}-${Buffer.from(input.name, "utf8").toString("base64url")}`;
26095
- }
26096
- function redactProviderEnvironmentVariable(variable) {
26097
- if (!variable.sensitive) {
26098
- const { valueRedacted: _omit, ...rest } = variable;
26099
- return rest;
26100
- }
26101
- return {
26102
- ...variable,
26103
- value: "",
26104
- ...variable.value.length > 0 || variable.valueRedacted ? { valueRedacted: true } : {}
26105
- };
26106
- }
26107
- function redactServerSettingsForClient(settings) {
26108
- const providerInstances = Object.fromEntries(Object.entries(settings.providerInstances).map(([instanceId, instance]) => [instanceId, instance.environment ? {
26109
- ...instance,
26110
- environment: instance.environment.map(redactProviderEnvironmentVariable)
26111
- } : instance]));
26112
- return {
26113
- ...settings,
26114
- providerInstances
26115
- };
26116
- }
26117
- var ServerSettingsService = class ServerSettingsService extends Context.Service()("ryco/serverSettings/ServerSettingsService") {
26118
- static layerTest = (overrides = {}) => Layer.effect(ServerSettingsService, Effect.gen(function* () {
26119
- const currentSettingsRef = yield* Ref.make(deepMerge(DEFAULT_SERVER_SETTINGS, overrides));
26120
- return {
26121
- start: Effect.void,
26122
- ready: Effect.void,
26123
- getSettings: Ref.get(currentSettingsRef),
26124
- updateSettings: (patch) => Ref.get(currentSettingsRef).pipe(Effect.flatMap((currentSettings) => Schema.decodeEffect(ServerSettings)(applyServerSettingsPatch(currentSettings, patch)).pipe(Effect.mapError((cause) => new ServerSettingsError({
26125
- settingsPath: "<memory>",
26126
- detail: `failed to normalize server settings: ${SchemaIssue.makeFormatterDefault()(cause.issue)}`,
26127
- cause
26128
- })))), Effect.tap((nextSettings) => Ref.set(currentSettingsRef, nextSettings))),
26129
- streamChanges: Stream.empty
26130
- };
26131
- }));
26132
- };
26133
- const ServerSettingsJson = fromLenientJson(ServerSettings);
26134
- const getLegacyProviderSettings = (settings, provider) => settings.providers[provider];
26135
- /**
26136
- * Ensure the `textGenerationModelSelection` points to an enabled provider.
26137
- * If the selected provider is disabled, fall back to the first enabled
26138
- * provider with its default model. This is applied at read-time so the
26139
- * persisted preference is preserved for when a provider is re-enabled.
26140
- */
26141
- function resolveTextGenerationProvider(settings) {
26142
- const selection = settings.textGenerationModelSelection;
26143
- const instanceConfig = settings.providerInstances[selection.instanceId];
26144
- if (instanceConfig !== void 0) return instanceConfig.enabled ?? true ? settings : fallbackTextGenerationProvider(settings);
26145
- if (isProviderDriverKind(selection.instanceId) && getLegacyProviderSettings(settings, selection.instanceId)?.enabled) return settings;
26146
- return fallbackTextGenerationProvider(settings);
26147
- }
26148
- function fallbackTextGenerationProvider(settings) {
26149
- const fallbackEntry = Object.entries(settings.providers).find(([, provider]) => provider.enabled);
26150
- const fallback = fallbackEntry ? ProviderDriverKind.make(fallbackEntry[0]) : void 0;
26151
- if (!fallback) return settings;
26152
- return {
26153
- ...settings,
26154
- textGenerationModelSelection: {
26155
- instanceId: ProviderInstanceId.make(fallback),
26156
- model: DEFAULT_GIT_TEXT_GENERATION_MODEL_BY_PROVIDER[fallback] ?? "gpt-5.4-mini"
26157
- }
26158
- };
26159
- }
26160
- const ATOMIC_SETTINGS_KEYS = new Set(["textGenerationModelSelection"]);
26161
- function stripDefaultServerSettings(current, defaults) {
26162
- if (Array.isArray(current) || Array.isArray(defaults)) return Equal.equals(current, defaults) ? void 0 : current;
26163
- if (current !== null && defaults !== null && typeof current === "object" && typeof defaults === "object") {
26164
- const currentRecord = current;
26165
- const defaultsRecord = defaults;
26166
- const next = {};
26167
- for (const key of Object.keys(currentRecord)) if (ATOMIC_SETTINGS_KEYS.has(key)) {
26168
- if (!Equal.equals(currentRecord[key], defaultsRecord[key])) next[key] = currentRecord[key];
26169
- } else {
26170
- const stripped = stripDefaultServerSettings(currentRecord[key], defaultsRecord[key]);
26171
- if (stripped !== void 0) next[key] = stripped;
26172
- }
26173
- return Object.keys(next).length > 0 ? next : void 0;
26174
- }
26175
- return Object.is(current, defaults) ? void 0 : current;
26176
- }
26177
- const makeServerSettings = Effect.gen(function* () {
26178
- const { settingsPath } = yield* ServerConfig;
26179
- const fs = yield* FileSystem.FileSystem;
26180
- const pathService = yield* Path.Path;
26181
- const secretStore = yield* ServerSecretStore;
26182
- const writeSemaphore = yield* Semaphore$1.make(1);
26183
- const cacheKey = "settings";
26184
- const changesPubSub = yield* PubSub.unbounded();
26185
- const startedRef = yield* Ref.make(false);
26186
- const startedDeferred = yield* Deferred.make();
26187
- const watcherScope = yield* Scope.make("sequential");
26188
- yield* Effect.addFinalizer(() => Scope.close(watcherScope, Exit.void));
26189
- const emitChange = (settings) => PubSub.publish(changesPubSub, settings).pipe(Effect.asVoid);
26190
- const readConfigExists = fs.exists(settingsPath).pipe(Effect.mapError((cause) => new ServerSettingsError({
26191
- settingsPath,
26192
- detail: "failed to check settings file existence",
26193
- cause
26194
- })));
26195
- const readRawConfig = fs.readFileString(settingsPath).pipe(Effect.mapError((cause) => new ServerSettingsError({
26196
- settingsPath,
26197
- detail: "failed to read settings file",
26198
- cause
26199
- })));
26200
- const loadSettingsFromDisk = Effect.gen(function* () {
26201
- if (!(yield* readConfigExists)) return DEFAULT_SERVER_SETTINGS;
26202
- const raw = yield* readRawConfig;
26203
- const decoded = Schema.decodeUnknownExit(ServerSettingsJson)(raw);
26204
- if (decoded._tag === "Failure") {
26205
- yield* Effect.logWarning("failed to parse settings.json, using defaults", {
26206
- path: settingsPath,
26207
- issues: Cause.pretty(decoded.cause)
26208
- });
26209
- return DEFAULT_SERVER_SETTINGS;
26210
- }
26211
- return decoded.value;
26212
- });
26213
- const settingsCache = yield* Cache.make({
26214
- capacity: 1,
26215
- lookup: () => loadSettingsFromDisk
26216
- });
26217
- const getSettingsFromCache = Cache.get(settingsCache, cacheKey);
26218
- const toSettingsError = (detail, cause) => new ServerSettingsError({
26219
- settingsPath,
26220
- detail,
26221
- cause
26222
- });
26223
- const materializeProviderEnvironmentSecrets = (settings) => Effect.gen(function* () {
26224
- const providerInstances = { ...settings.providerInstances };
26225
- for (const [instanceId, instance] of Object.entries(settings.providerInstances)) {
26226
- if (!instance.environment) continue;
26227
- const environment = [];
26228
- for (const variable of instance.environment) {
26229
- if (!variable.sensitive || !variable.valueRedacted) {
26230
- environment.push(variable);
26231
- continue;
26232
- }
26233
- const secret = yield* secretStore.get(providerEnvironmentSecretName({
26234
- instanceId,
26235
- name: variable.name
26236
- })).pipe(Effect.mapError((cause) => toSettingsError(`failed to read sensitive environment variable ${variable.name}`, cause)));
26237
- environment.push({
26238
- ...variable,
26239
- value: secret ? textDecoder$1.decode(secret) : ""
26240
- });
26241
- }
26242
- providerInstances[instanceId] = {
26243
- ...instance,
26244
- environment
26245
- };
26246
- }
26247
- return {
26248
- ...settings,
26249
- providerInstances
26250
- };
26251
- });
26252
- const persistProviderEnvironmentSecrets = (current, next) => Effect.gen(function* () {
26253
- const providerInstances = { ...next.providerInstances };
26254
- const nextSecretKeys = /* @__PURE__ */ new Set();
26255
- for (const [instanceId, instance] of Object.entries(next.providerInstances)) {
26256
- if (!instance.environment) continue;
26257
- const environment = [];
26258
- for (const variable of instance.environment) {
26259
- const secretName = providerEnvironmentSecretName({
26260
- instanceId,
26261
- name: variable.name
26262
- });
26263
- if (!variable.sensitive) {
26264
- yield* secretStore.remove(secretName).pipe(Effect.mapError((cause) => toSettingsError(`failed to remove environment secret ${variable.name}`, cause)));
26265
- environment.push(redactProviderEnvironmentVariable(variable));
26266
- continue;
26267
- }
26268
- nextSecretKeys.add(secretName);
26269
- if (!variable.valueRedacted) {
26270
- if (variable.value.length > 0) {
26271
- yield* secretStore.set(secretName, textEncoder$1.encode(variable.value)).pipe(Effect.mapError((cause) => toSettingsError(`failed to persist environment secret ${variable.name}`, cause)));
26272
- environment.push({
26273
- ...variable,
26274
- value: "",
26275
- valueRedacted: true
26276
- });
26277
- } else {
26278
- yield* secretStore.remove(secretName).pipe(Effect.mapError((cause) => toSettingsError(`failed to remove environment secret ${variable.name}`, cause)));
26279
- const { valueRedacted: _omit, ...rest } = variable;
26280
- environment.push(rest);
26281
- }
26282
- continue;
26283
- }
26284
- environment.push(redactProviderEnvironmentVariable(variable));
26285
- }
26286
- providerInstances[instanceId] = {
26287
- ...instance,
26288
- environment
26289
- };
26290
- }
26291
- for (const [instanceId, instance] of Object.entries(current.providerInstances)) for (const variable of instance.environment ?? []) {
26292
- if (!variable.sensitive) continue;
26293
- const secretName = providerEnvironmentSecretName({
26294
- instanceId,
26295
- name: variable.name
26296
- });
26297
- if (nextSecretKeys.has(secretName)) continue;
26298
- yield* secretStore.remove(secretName).pipe(Effect.mapError((cause) => toSettingsError(`failed to remove stale environment secret ${variable.name}`, cause)));
26299
- }
26300
- return {
26301
- ...next,
26302
- providerInstances
26303
- };
26304
- });
26305
- const writeSettingsAtomically = (settings) => {
26306
- const sparseSettings = stripDefaultServerSettings(settings, DEFAULT_SERVER_SETTINGS) ?? {};
26307
- return writeFileStringAtomically({
26308
- filePath: settingsPath,
26309
- contents: `${JSON.stringify(sparseSettings, null, 2)}\n`
26310
- }).pipe(Effect.provideService(FileSystem.FileSystem, fs), Effect.provideService(Path.Path, pathService), Effect.mapError((cause) => new ServerSettingsError({
26311
- settingsPath,
26312
- detail: "failed to write settings file",
26313
- cause
26314
- })));
26315
- };
26316
- const revalidateAndEmit = writeSemaphore.withPermits(1)(Effect.gen(function* () {
26317
- yield* Cache.invalidate(settingsCache, cacheKey);
26318
- yield* emitChange(yield* getSettingsFromCache);
26319
- }));
26320
- const startWatcher = Effect.gen(function* () {
26321
- const settingsDir = pathService.dirname(settingsPath);
26322
- const settingsFile = pathService.basename(settingsPath);
26323
- const settingsPathResolved = pathService.resolve(settingsPath);
26324
- yield* fs.makeDirectory(settingsDir, { recursive: true }).pipe(Effect.mapError((cause) => new ServerSettingsError({
26325
- settingsPath,
26326
- detail: "failed to prepare settings directory",
26327
- cause
26328
- })));
26329
- const revalidateAndEmitSafely = revalidateAndEmit.pipe(Effect.ignoreCause({ log: true }));
26330
- const debouncedSettingsEvents = fs.watch(settingsDir).pipe(Stream.filter((event) => {
26331
- return event.path === settingsFile || event.path === settingsPath || pathService.resolve(settingsDir, event.path) === settingsPathResolved;
26332
- }), Stream.debounce(Duration.millis(100)));
26333
- yield* Stream.runForEach(debouncedSettingsEvents, () => revalidateAndEmitSafely).pipe(Effect.ignoreCause({ log: true }), Effect.forkIn(watcherScope), Effect.asVoid);
26334
- });
26335
- return {
26336
- start: Effect.gen(function* () {
26337
- if (!(yield* Ref.modify(startedRef, (started) => [!started, true]))) return yield* Deferred.await(startedDeferred);
26338
- const startup = Effect.gen(function* () {
26339
- yield* startWatcher;
26340
- yield* Cache.invalidate(settingsCache, cacheKey);
26341
- yield* getSettingsFromCache;
26342
- });
26343
- const startupExit = yield* Effect.exit(startup);
26344
- if (startupExit._tag === "Failure") {
26345
- yield* Deferred.failCause(startedDeferred, startupExit.cause).pipe(Effect.orDie);
26346
- return yield* Effect.failCause(startupExit.cause);
26347
- }
26348
- yield* Deferred.succeed(startedDeferred, void 0).pipe(Effect.orDie);
26349
- }),
26350
- ready: Deferred.await(startedDeferred),
26351
- getSettings: getSettingsFromCache.pipe(Effect.flatMap(materializeProviderEnvironmentSecrets), Effect.map(resolveTextGenerationProvider)),
26352
- updateSettings: (patch) => writeSemaphore.withPermits(1)(Effect.gen(function* () {
26353
- const current = yield* getSettingsFromCache;
26354
- const nextPersisted = yield* persistProviderEnvironmentSecrets(current, applyServerSettingsPatch(current, patch));
26355
- const next = yield* Schema.decodeEffect(ServerSettings)(nextPersisted).pipe(Effect.mapError((cause) => new ServerSettingsError({
26356
- settingsPath: "<memory>",
26357
- detail: `failed to normalize server settings: ${SchemaIssue.makeFormatterDefault()(cause.issue)}`,
26358
- cause
26359
- })));
26360
- yield* writeSettingsAtomically(next);
26361
- yield* Cache.set(settingsCache, cacheKey, next);
26362
- yield* emitChange(next);
26363
- return resolveTextGenerationProvider(yield* materializeProviderEnvironmentSecrets(next));
26364
- })),
26365
- get streamChanges() {
26366
- return Stream.fromPubSub(changesPubSub).pipe(Stream.mapEffect((settings) => materializeProviderEnvironmentSecrets(settings).pipe(Effect.catch((error) => Effect.logWarning("failed to materialize provider environment secrets", { detail: error.detail }).pipe(Effect.as(settings))))), Stream.map(resolveTextGenerationProvider));
26367
- }
26368
- };
26369
- });
26370
- const ServerSettingsLive = Layer.effect(ServerSettingsService, makeServerSettings).pipe(Layer.provide(ServerSecretStoreLive));
26371
- //#endregion
26372
26481
  //#region src/pathExpansion.ts
26373
26482
  /**
26374
26483
  * Expand a leading `~` (or `~/…`, `~\…`) in a user-supplied path to the
@@ -26689,7 +26798,7 @@ const BUILT_IN_DRIVERS = [
26689
26798
  configSchema: CodexSettings,
26690
26799
  defaultConfig: () => Schema.decodeSync(CodexSettings)({}),
26691
26800
  create: (input) => Effect.tryPromise({
26692
- try: () => import("./CodexDriver-BILrJG8o.mjs"),
26801
+ try: () => import("./CodexDriver-93-TmCrO.mjs"),
26693
26802
  catch: (cause) => driverImportError(codexDriverKind, input, cause)
26694
26803
  }).pipe(Effect.flatMap(({ CodexDriver }) => CodexDriver.create(input)))
26695
26804
  },
@@ -26702,7 +26811,7 @@ const BUILT_IN_DRIVERS = [
26702
26811
  configSchema: ClaudeSettings,
26703
26812
  defaultConfig: () => Schema.decodeSync(ClaudeSettings)({}),
26704
26813
  create: (input) => Effect.tryPromise({
26705
- try: () => import("./ClaudeDriver-D3nsxwH9.mjs"),
26814
+ try: () => import("./ClaudeDriver-WwWFTu61.mjs"),
26706
26815
  catch: (cause) => driverImportError(claudeDriverKind, input, cause)
26707
26816
  }).pipe(Effect.flatMap(({ ClaudeDriver }) => ClaudeDriver.create(input)))
26708
26817
  },
@@ -26715,7 +26824,7 @@ const BUILT_IN_DRIVERS = [
26715
26824
  configSchema: CopilotSettings,
26716
26825
  defaultConfig: () => Schema.decodeSync(CopilotSettings)({}),
26717
26826
  create: (input) => Effect.tryPromise({
26718
- try: () => import("./CopilotDriver-CmD3Ffyl.mjs"),
26827
+ try: () => import("./CopilotDriver-BASi8pJ0.mjs"),
26719
26828
  catch: (cause) => driverImportError(copilotDriverKind, input, cause)
26720
26829
  }).pipe(Effect.flatMap(({ CopilotDriver }) => CopilotDriver.create(input)))
26721
26830
  },
@@ -26728,7 +26837,7 @@ const BUILT_IN_DRIVERS = [
26728
26837
  configSchema: CursorSettings,
26729
26838
  defaultConfig: () => Schema.decodeSync(CursorSettings)({}),
26730
26839
  create: (input) => Effect.tryPromise({
26731
- try: () => import("./CursorDriver-CbeaIbdb.mjs"),
26840
+ try: () => import("./CursorDriver-D5LvIqUk.mjs"),
26732
26841
  catch: (cause) => driverImportError(cursorDriverKind, input, cause)
26733
26842
  }).pipe(Effect.flatMap(({ CursorDriver }) => CursorDriver.create(input)))
26734
26843
  },
@@ -26741,7 +26850,7 @@ const BUILT_IN_DRIVERS = [
26741
26850
  configSchema: OpenCodeSettings,
26742
26851
  defaultConfig: () => Schema.decodeSync(OpenCodeSettings)({}),
26743
26852
  create: (input) => Effect.tryPromise({
26744
- try: () => import("./OpenCodeDriver-ClWtCk0j.mjs"),
26853
+ try: () => import("./OpenCodeDriver-BhvLOmvn.mjs"),
26745
26854
  catch: (cause) => driverImportError(openCodeDriverKind, input, cause)
26746
26855
  }).pipe(Effect.flatMap(({ OpenCodeDriver }) => OpenCodeDriver.create(input)))
26747
26856
  }
@@ -27454,7 +27563,7 @@ const scopedSafeTeardown = (label) => (effect) => Effect.gen(function* () {
27454
27563
  });
27455
27564
  //#endregion
27456
27565
  //#region package.json
27457
- var version = "0.1.6";
27566
+ var version = "0.1.7";
27458
27567
  //#endregion
27459
27568
  //#region src/provider/Layers/CodexProvider.ts
27460
27569
  const PROVIDER_PROBE_TIMEOUT_MS = 8e3;
@@ -28491,6 +28600,387 @@ var OrchestrationEngineService = class extends Context.Service()("ryco/orchestra
28491
28600
  */
28492
28601
  var ProjectionSnapshotQuery = class extends Context.Service()("ryco/orchestration/Services/ProjectionSnapshotQuery") {};
28493
28602
  //#endregion
28603
+ //#region src/statistics/StatisticsQuery.ts
28604
+ /**
28605
+ * StatisticsQuery - usage analytics over the orchestration projection tables.
28606
+ *
28607
+ * Aggregates the existing read models (threads, sessions, token-usage
28608
+ * activities, turns/checkpoints, worktrees) into a {@link StatisticsSnapshot}
28609
+ * on demand. No dedicated statistics tables exist; everything is derived from
28610
+ * data already persisted by the projection pipeline.
28611
+ *
28612
+ * Token figures use a per-turn delta attribution: for each `(thread, turn)` we
28613
+ * read the final `context-window.updated` activity and sum its `last*` deltas,
28614
+ * bucketed by day/project/model. When deltas are absent (older data / providers
28615
+ * that only report cumulative totals) we fall back to attributing a thread's
28616
+ * cumulative total to its primary model and last-activity day.
28617
+ *
28618
+ * @module StatisticsQuery
28619
+ */
28620
+ /**
28621
+ * StatisticsQuery - service tag.
28622
+ */
28623
+ var StatisticsQuery = class extends Context.Service()("ryco/statistics/StatisticsQuery") {};
28624
+ function toPersistenceSqlOrDecodeError$7(sqlOperation, decodeOperation) {
28625
+ return (cause) => Schema.isSchemaError(cause) ? toPersistenceDecodeError(decodeOperation)(cause) : toPersistenceSqlError(sqlOperation)(cause);
28626
+ }
28627
+ const ThreadRow = Schema.Struct({
28628
+ threadId: Schema.String,
28629
+ projectId: ProjectId,
28630
+ model: Schema.NullOr(Schema.String),
28631
+ createdAt: Schema.String,
28632
+ providerName: Schema.NullOr(Schema.String)
28633
+ });
28634
+ const ProjectRow = Schema.Struct({
28635
+ projectId: ProjectId,
28636
+ title: Schema.String,
28637
+ deletedAt: Schema.NullOr(Schema.String)
28638
+ });
28639
+ const TokenActivityRow = Schema.Struct({
28640
+ threadId: Schema.String,
28641
+ turnId: Schema.NullOr(Schema.String),
28642
+ sequence: Schema.NullOr(Schema.Number),
28643
+ createdAt: Schema.String,
28644
+ payloadJson: Schema.String
28645
+ });
28646
+ const ToolUseRow = Schema.Struct({
28647
+ threadId: Schema.String,
28648
+ date: Schema.String,
28649
+ count: Schema.Number
28650
+ });
28651
+ const TurnRow = Schema.Struct({
28652
+ threadId: Schema.String,
28653
+ startedAt: Schema.NullOr(Schema.String),
28654
+ completedAt: Schema.NullOr(Schema.String),
28655
+ checkpointTurnCount: Schema.NullOr(Schema.Number),
28656
+ filesJson: Schema.String
28657
+ });
28658
+ const WorktreeRow = Schema.Struct({
28659
+ createdAt: Schema.String,
28660
+ archivedAt: Schema.NullOr(Schema.String),
28661
+ prNumber: Schema.NullOr(Schema.Number)
28662
+ });
28663
+ function num(value) {
28664
+ return typeof value === "number" && Number.isFinite(value) ? value : 0;
28665
+ }
28666
+ function dayOf(iso) {
28667
+ return iso.length >= 10 ? iso.slice(0, 10) : null;
28668
+ }
28669
+ const makeStatisticsQuery = Effect.gen(function* () {
28670
+ const sql = yield* SqlClient.SqlClient;
28671
+ const listThreadRows = SqlSchema.findAll({
28672
+ Request: Schema.Void,
28673
+ Result: ThreadRow,
28674
+ execute: () => sql`
28675
+ SELECT
28676
+ t.thread_id AS "threadId",
28677
+ t.project_id AS "projectId",
28678
+ json_extract(t.model_selection_json, '$.model') AS "model",
28679
+ t.created_at AS "createdAt",
28680
+ COALESCE(
28681
+ s.provider_name,
28682
+ json_extract(t.model_selection_json, '$.provider')
28683
+ ) AS "providerName"
28684
+ FROM projection_threads t
28685
+ LEFT JOIN projection_thread_sessions s ON s.thread_id = t.thread_id
28686
+ `
28687
+ });
28688
+ const listProjectRows = SqlSchema.findAll({
28689
+ Request: Schema.Void,
28690
+ Result: ProjectRow,
28691
+ execute: () => sql`
28692
+ SELECT
28693
+ project_id AS "projectId",
28694
+ title,
28695
+ deleted_at AS "deletedAt"
28696
+ FROM projection_projects
28697
+ `
28698
+ });
28699
+ const listTokenActivityRows = SqlSchema.findAll({
28700
+ Request: Schema.Void,
28701
+ Result: TokenActivityRow,
28702
+ execute: () => sql`
28703
+ SELECT
28704
+ thread_id AS "threadId",
28705
+ turn_id AS "turnId",
28706
+ sequence,
28707
+ created_at AS "createdAt",
28708
+ payload_json AS "payloadJson"
28709
+ FROM projection_thread_activities
28710
+ WHERE kind = 'context-window.updated'
28711
+ ORDER BY thread_id ASC, turn_id ASC, sequence ASC, created_at ASC, activity_id ASC
28712
+ `
28713
+ });
28714
+ const listToolUseRows = SqlSchema.findAll({
28715
+ Request: Schema.Void,
28716
+ Result: ToolUseRow,
28717
+ execute: () => sql`
28718
+ SELECT
28719
+ thread_id AS "threadId",
28720
+ substr(created_at, 1, 10) AS "date",
28721
+ COUNT(*) AS "count"
28722
+ FROM projection_thread_activities
28723
+ WHERE kind = 'tool.completed'
28724
+ GROUP BY thread_id, substr(created_at, 1, 10)
28725
+ `
28726
+ });
28727
+ const listTurnRows = SqlSchema.findAll({
28728
+ Request: Schema.Void,
28729
+ Result: TurnRow,
28730
+ execute: () => sql`
28731
+ SELECT
28732
+ thread_id AS "threadId",
28733
+ started_at AS "startedAt",
28734
+ completed_at AS "completedAt",
28735
+ checkpoint_turn_count AS "checkpointTurnCount",
28736
+ checkpoint_files_json AS "filesJson"
28737
+ FROM projection_turns
28738
+ `
28739
+ });
28740
+ const listWorktreeRows = SqlSchema.findAll({
28741
+ Request: Schema.Void,
28742
+ Result: WorktreeRow,
28743
+ execute: () => sql`
28744
+ SELECT
28745
+ created_at AS "createdAt",
28746
+ archived_at AS "archivedAt",
28747
+ pr_number AS "prNumber"
28748
+ FROM projection_worktrees
28749
+ `
28750
+ });
28751
+ const getStatistics = () => Effect.gen(function* () {
28752
+ const [threadRows, projectRows, tokenRows, toolRows, turnRows, worktreeRows] = yield* Effect.all([
28753
+ listThreadRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$7("StatisticsQuery.getStatistics:listThreads:query", "StatisticsQuery.getStatistics:listThreads:decodeRows"))),
28754
+ listProjectRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$7("StatisticsQuery.getStatistics:listProjects:query", "StatisticsQuery.getStatistics:listProjects:decodeRows"))),
28755
+ listTokenActivityRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$7("StatisticsQuery.getStatistics:listTokenActivities:query", "StatisticsQuery.getStatistics:listTokenActivities:decodeRows"))),
28756
+ listToolUseRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$7("StatisticsQuery.getStatistics:listToolUses:query", "StatisticsQuery.getStatistics:listToolUses:decodeRows"))),
28757
+ listTurnRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$7("StatisticsQuery.getStatistics:listTurns:query", "StatisticsQuery.getStatistics:listTurns:decodeRows"))),
28758
+ listWorktreeRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$7("StatisticsQuery.getStatistics:listWorktrees:query", "StatisticsQuery.getStatistics:listWorktrees:decodeRows")))
28759
+ ], { concurrency: "unbounded" });
28760
+ const threadMeta = /* @__PURE__ */ new Map();
28761
+ const modelProvider = /* @__PURE__ */ new Map();
28762
+ for (const row of threadRows) {
28763
+ const provider = row.providerName?.trim() || void 0;
28764
+ const model = (row.model ?? "").trim() || "unknown";
28765
+ threadMeta.set(row.threadId, {
28766
+ projectId: row.projectId,
28767
+ model,
28768
+ provider,
28769
+ createdAt: row.createdAt
28770
+ });
28771
+ if (!modelProvider.has(model) || modelProvider.get(model) === void 0 && provider) modelProvider.set(model, provider);
28772
+ }
28773
+ const buckets = /* @__PURE__ */ new Map();
28774
+ const getBucket = (date, projectId, model) => {
28775
+ const key = `${date}${projectId}${model}`;
28776
+ let bucket = buckets.get(key);
28777
+ if (!bucket) {
28778
+ bucket = {
28779
+ date,
28780
+ projectId,
28781
+ model,
28782
+ provider: modelProvider.get(model),
28783
+ inputTokens: 0,
28784
+ outputTokens: 0,
28785
+ cachedInputTokens: 0,
28786
+ reasoningTokens: 0,
28787
+ turns: 0,
28788
+ activeMs: 0,
28789
+ toolUses: 0,
28790
+ filesChanged: 0,
28791
+ additions: 0,
28792
+ deletions: 0,
28793
+ commits: 0,
28794
+ pushes: 0,
28795
+ threadsCreated: 0
28796
+ };
28797
+ buckets.set(key, bucket);
28798
+ }
28799
+ return bucket;
28800
+ };
28801
+ let earliest;
28802
+ const considerIso = (iso) => {
28803
+ if (iso && (earliest === void 0 || iso < earliest)) earliest = iso;
28804
+ };
28805
+ const lastPerTurn = /* @__PURE__ */ new Map();
28806
+ const lastPerThread = /* @__PURE__ */ new Map();
28807
+ const isLater = (a, b) => {
28808
+ if (a.createdAt !== b.createdAt) return a.createdAt > b.createdAt;
28809
+ return (a.sequence ?? -1) >= (b.sequence ?? -1);
28810
+ };
28811
+ for (const row of tokenRows) {
28812
+ considerIso(row.createdAt);
28813
+ lastPerTurn.set(`${row.threadId}${row.turnId ?? ""}`, row);
28814
+ const prevThread = lastPerThread.get(row.threadId);
28815
+ if (!prevThread || isLater(row, prevThread)) lastPerThread.set(row.threadId, row);
28816
+ }
28817
+ let perTurnDeltaSum = 0;
28818
+ for (const row of lastPerTurn.values()) {
28819
+ const payload = safeParse(row.payloadJson);
28820
+ perTurnDeltaSum += num(payload?.lastInputTokens) + num(payload?.lastOutputTokens) + num(payload?.lastCachedInputTokens) + num(payload?.lastReasoningOutputTokens);
28821
+ }
28822
+ let cumulativeSum = 0;
28823
+ for (const row of lastPerThread.values()) {
28824
+ const payload = safeParse(row.payloadJson);
28825
+ cumulativeSum += num(payload?.inputTokens) + num(payload?.outputTokens);
28826
+ }
28827
+ const attribution = perTurnDeltaSum === 0 && cumulativeSum > 0 ? "thread-cumulative" : "per-turn-delta";
28828
+ if (attribution === "per-turn-delta") for (const row of lastPerTurn.values()) {
28829
+ const meta = threadMeta.get(row.threadId);
28830
+ const date = dayOf(row.createdAt);
28831
+ if (!meta || !date) continue;
28832
+ const payload = safeParse(row.payloadJson);
28833
+ const bucket = getBucket(date, meta.projectId, meta.model);
28834
+ bucket.inputTokens += num(payload?.lastInputTokens);
28835
+ bucket.outputTokens += num(payload?.lastOutputTokens);
28836
+ bucket.cachedInputTokens += num(payload?.lastCachedInputTokens);
28837
+ bucket.reasoningTokens += num(payload?.lastReasoningOutputTokens);
28838
+ }
28839
+ else for (const row of lastPerThread.values()) {
28840
+ const meta = threadMeta.get(row.threadId);
28841
+ const date = dayOf(row.createdAt);
28842
+ if (!meta || !date) continue;
28843
+ const payload = safeParse(row.payloadJson);
28844
+ const bucket = getBucket(date, meta.projectId, meta.model);
28845
+ bucket.inputTokens += num(payload?.inputTokens);
28846
+ bucket.outputTokens += num(payload?.outputTokens);
28847
+ bucket.cachedInputTokens += num(payload?.cachedInputTokens);
28848
+ bucket.reasoningTokens += num(payload?.reasoningOutputTokens);
28849
+ }
28850
+ for (const row of turnRows) {
28851
+ const meta = threadMeta.get(row.threadId);
28852
+ if (!meta) continue;
28853
+ considerIso(row.startedAt);
28854
+ considerIso(row.completedAt);
28855
+ const anchor = row.completedAt ?? row.startedAt;
28856
+ const date = anchor ? dayOf(anchor) : null;
28857
+ if (!date) continue;
28858
+ const bucket = getBucket(date, meta.projectId, meta.model);
28859
+ if (row.completedAt) {
28860
+ bucket.turns += 1;
28861
+ if (row.startedAt) {
28862
+ const delta = Date.parse(row.completedAt) - Date.parse(row.startedAt);
28863
+ if (Number.isFinite(delta) && delta > 0) bucket.activeMs += delta;
28864
+ }
28865
+ }
28866
+ const files = safeParseArray(row.filesJson);
28867
+ if (files.length > 0) {
28868
+ bucket.filesChanged += files.length;
28869
+ for (const file of files) {
28870
+ bucket.additions += num(file?.additions);
28871
+ bucket.deletions += num(file?.deletions);
28872
+ }
28873
+ }
28874
+ }
28875
+ for (const row of toolRows) {
28876
+ const meta = threadMeta.get(row.threadId);
28877
+ if (!meta) continue;
28878
+ const bucket = getBucket(row.date, meta.projectId, meta.model);
28879
+ bucket.toolUses += num(row.count);
28880
+ }
28881
+ for (const meta of threadMeta.values()) {
28882
+ considerIso(meta.createdAt);
28883
+ const date = dayOf(meta.createdAt);
28884
+ if (!date) continue;
28885
+ getBucket(date, meta.projectId, meta.model).threadsCreated += 1;
28886
+ }
28887
+ let wtCreated = 0;
28888
+ let wtArchived = 0;
28889
+ let wtOpenPrs = 0;
28890
+ for (const row of worktreeRows) {
28891
+ considerIso(row.createdAt);
28892
+ wtCreated += 1;
28893
+ if (row.archivedAt) wtArchived += 1;
28894
+ else if (row.prNumber !== null) wtOpenPrs += 1;
28895
+ }
28896
+ const dailyBuckets = [];
28897
+ const totals = {
28898
+ inputTokens: 0,
28899
+ outputTokens: 0,
28900
+ cachedInputTokens: 0,
28901
+ reasoningTokens: 0,
28902
+ totalTokens: 0,
28903
+ turns: 0,
28904
+ activeMs: 0,
28905
+ toolUses: 0,
28906
+ filesChanged: 0,
28907
+ additions: 0,
28908
+ deletions: 0,
28909
+ commits: 0,
28910
+ pushes: 0,
28911
+ threads: threadMeta.size,
28912
+ projects: 0
28913
+ };
28914
+ for (const bucket of buckets.values()) {
28915
+ const { provider, ...rest } = bucket;
28916
+ dailyBuckets.push(provider ? {
28917
+ ...rest,
28918
+ provider
28919
+ } : rest);
28920
+ totals.inputTokens += bucket.inputTokens;
28921
+ totals.outputTokens += bucket.outputTokens;
28922
+ totals.cachedInputTokens += bucket.cachedInputTokens;
28923
+ totals.reasoningTokens += bucket.reasoningTokens;
28924
+ totals.turns += bucket.turns;
28925
+ totals.activeMs += bucket.activeMs;
28926
+ totals.toolUses += bucket.toolUses;
28927
+ totals.filesChanged += bucket.filesChanged;
28928
+ totals.additions += bucket.additions;
28929
+ totals.deletions += bucket.deletions;
28930
+ totals.commits += bucket.commits;
28931
+ totals.pushes += bucket.pushes;
28932
+ }
28933
+ totals.totalTokens = totals.inputTokens + totals.outputTokens;
28934
+ const projectTitle = /* @__PURE__ */ new Map();
28935
+ for (const row of projectRows) projectTitle.set(row.projectId, row.title);
28936
+ const projectIdsInData = /* @__PURE__ */ new Set();
28937
+ for (const meta of threadMeta.values()) projectIdsInData.add(meta.projectId);
28938
+ for (const bucket of buckets.values()) projectIdsInData.add(bucket.projectId);
28939
+ totals.projects = projectIdsInData.size;
28940
+ const projects = [...projectIdsInData].map((id) => ({
28941
+ id,
28942
+ title: projectTitle.get(id)?.trim() || id
28943
+ }));
28944
+ const models = [...modelProvider].map(([model, provider]) => provider ? {
28945
+ model,
28946
+ provider
28947
+ } : { model });
28948
+ return {
28949
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
28950
+ ...earliest ? { earliestActivityAt: earliest } : {},
28951
+ projects,
28952
+ models,
28953
+ dailyBuckets,
28954
+ worktrees: {
28955
+ created: wtCreated,
28956
+ archived: wtArchived,
28957
+ active: wtCreated - wtArchived,
28958
+ openPrs: wtOpenPrs
28959
+ },
28960
+ totals,
28961
+ tokenAttribution: attribution
28962
+ };
28963
+ });
28964
+ return { getStatistics };
28965
+ });
28966
+ function safeParse(json) {
28967
+ try {
28968
+ const parsed = JSON.parse(json);
28969
+ return parsed && typeof parsed === "object" ? parsed : null;
28970
+ } catch {
28971
+ return null;
28972
+ }
28973
+ }
28974
+ function safeParseArray(json) {
28975
+ try {
28976
+ const parsed = JSON.parse(json);
28977
+ return Array.isArray(parsed) ? parsed : [];
28978
+ } catch {
28979
+ return [];
28980
+ }
28981
+ }
28982
+ const StatisticsQueryLive = Layer.effect(StatisticsQuery, makeStatisticsQuery);
28983
+ //#endregion
28494
28984
  //#region src/serverLifecycleEvents.ts
28495
28985
  var ServerLifecycleEvents = class extends Context.Service()("ryco/serverLifecycleEvents") {};
28496
28986
  const ServerLifecycleEventsLive = Layer.effect(ServerLifecycleEvents, Effect.gen(function* () {
@@ -30380,7 +30870,8 @@ const makeGitManager = Effect.fn("makeGitManager")(function* () {
30380
30870
  isDefaultRef: details.isDefaultBranch,
30381
30871
  refName: details.branch,
30382
30872
  hasWorkingTreeChanges: details.hasWorkingTreeChanges,
30383
- workingTree: details.workingTree
30873
+ workingTree: details.workingTree,
30874
+ ...details.committed ? { committed: details.committed } : {}
30384
30875
  };
30385
30876
  });
30386
30877
  const localStatusResultCache = yield* Cache.makeWith(readLocalStatus, {
@@ -32514,6 +33005,8 @@ const layer = Layer.effect(JiraWorkItemService, make$5());
32514
33005
  //#region src/remote/Services/AdvertisedEndpointRegistry.ts
32515
33006
  var AdvertisedEndpointRegistry = class extends Context.Service()("ryco/remote/Services/AdvertisedEndpointRegistry") {};
32516
33007
  const ORCHESTRATION_REPLAY_PAGE_MAX_LIMIT = 1e3;
33008
+ const ORCHESTRATION_LEGACY_REPLAY_MAX_EVENTS = ORCHESTRATION_REPLAY_PAGE_MAX_LIMIT;
33009
+ const ORCHESTRATION_LIVE_QUEUE_MAX_EVENTS = 1e3;
32517
33010
  //#endregion
32518
33011
  //#region src/ws/context/gitErrors.ts
32519
33012
  function gitErrorText(error) {
@@ -32547,6 +33040,10 @@ const failGitWorkflow = (operation, detail, cause) => Effect.fail(toGitManagerEr
32547
33040
  const wsOrchestrationReplayDepth = Metric.gauge("t3_ws_orchestration_replay_depth", { description: "Current persisted orchestration event replay depth for a replayable WebSocket subscription." });
32548
33041
  const wsOrchestrationLiveBufferDepth = Metric.gauge("t3_ws_orchestration_live_buffer_depth", { description: "Current live orchestration event buffer depth for a replayable WebSocket subscription." });
32549
33042
  const wsOrchestrationLiveBufferHighWater = Metric.gauge("t3_ws_orchestration_live_buffer_high_water", { description: "Highest observed live orchestration event buffer depth for a replayable WebSocket subscription." });
33043
+ const wsOrchestrationLiveBufferOverflowsTotal = Metric.counter("t3_ws_orchestration_live_buffer_overflows_total", {
33044
+ description: "Total live orchestration event buffer overflows that forced replayable WebSocket subscription resync.",
33045
+ incremental: true
33046
+ });
32550
33047
  const wsOrchestrationReplayLag = Metric.gauge("t3_ws_orchestration_replay_lag", { description: "Sequence lag between the latest live event observed and the latest replay/live event drained by a replayable WebSocket subscription." });
32551
33048
  const normalizeSequence = (sequence) => Number.isFinite(sequence) ? Math.max(0, Math.floor(sequence)) : 0;
32552
33049
  const updateGauge$1 = (metric, attributes, value) => Metric.update(Metric.withAttributes(metric, attributes), value);
@@ -32584,6 +33081,18 @@ const makeWsReplayMetrics = (input) => Effect.gen(function* () {
32584
33081
  yield* recordLiveBuffer(yield* Ref.updateAndGet(liveBufferDepth, (current) => Math.max(0, current - 1)), yield* Ref.get(liveBufferHighWater));
32585
33082
  yield* markDrained(sequence);
32586
33083
  }),
33084
+ recordLiveOverflow: (sequence, capacity) => Effect.gen(function* () {
33085
+ const normalizedSequence = normalizeSequence(sequence);
33086
+ const normalizedCapacity = Math.max(0, Math.floor(capacity));
33087
+ yield* Ref.update(latestLiveSequence, (current) => Math.max(current, normalizedSequence));
33088
+ yield* Ref.set(liveBufferDepth, normalizedCapacity);
33089
+ const highWater = yield* Ref.updateAndGet(liveBufferHighWater, (current) => Math.max(current, normalizedCapacity));
33090
+ yield* Effect.all([
33091
+ recordLiveBuffer(normalizedCapacity, highWater),
33092
+ updateGauge$1(wsOrchestrationLiveBufferOverflowsTotal, attributes, 1),
33093
+ recordLag
33094
+ ], { discard: true });
33095
+ }),
32587
33096
  reset: Effect.all([
32588
33097
  updateGauge$1(wsOrchestrationReplayDepth, attributes, 0),
32589
33098
  updateGauge$1(wsOrchestrationLiveBufferDepth, attributes, 0),
@@ -32634,6 +33143,29 @@ const buildWorkItemBranchNameMessage = (input) => {
32634
33143
  };
32635
33144
  //#endregion
32636
33145
  //#region src/ws/context/orchestrationStreams.ts
33146
+ const makeLiveQueueOverflowError = (input) => new OrchestrationGetSnapshotError({
33147
+ message: `Orchestration ${input.stream} live event queue overflowed; reconnect to resynchronize`,
33148
+ cause: /* @__PURE__ */ new Error(`orchestration ${input.stream} live queue overflow at sequence ${input.sequence} with capacity ${input.capacity}`)
33149
+ });
33150
+ const offerOrchestrationLiveEventOrFail = (input) => Effect.gen(function* () {
33151
+ const capacity = input.capacity ?? 1e3;
33152
+ if (Queue.offerUnsafe(input.liveQueue, input.event)) {
33153
+ yield* input.replayMetrics.recordLiveEnqueued(input.event.sequence);
33154
+ return;
33155
+ }
33156
+ if (!(yield* Ref.modify(input.overflowedRef, (overflowed) => [!overflowed, true]))) return;
33157
+ yield* input.replayMetrics.recordLiveOverflow(input.event.sequence, capacity);
33158
+ yield* Effect.logWarning("orchestration live stream queue overflow; forcing resync", {
33159
+ stream: input.stream,
33160
+ sequence: input.event.sequence,
33161
+ capacity
33162
+ });
33163
+ yield* Queue.fail(input.liveQueue, makeLiveQueueOverflowError({
33164
+ stream: input.stream,
33165
+ sequence: input.event.sequence,
33166
+ capacity
33167
+ }));
33168
+ });
32637
33169
  const makeOrchestrationStreamHelpers = (deps) => {
32638
33170
  const { orchestrationEngine, projectionSnapshotQuery, repositoryIdentityResolver } = deps;
32639
33171
  const enrichProjectEvent = (event) => {
@@ -32753,8 +33285,9 @@ const makeOrchestrationStreamHelpers = (deps) => {
32753
33285
  const loadedSnapshot = yield* snapshot;
32754
33286
  const snapshotSequence = loadedSnapshot.snapshotSequence;
32755
33287
  const liveSubscription = yield* orchestrationEngine.subscribeDomainEvents;
32756
- const liveQueue = yield* Queue.unbounded();
33288
+ const liveQueue = yield* Queue.bounded(ORCHESTRATION_LIVE_QUEUE_MAX_EVENTS);
32757
33289
  const lastSequenceRef = yield* Ref.make(snapshotSequence);
33290
+ const overflowedRef = yield* Ref.make(false);
32758
33291
  const replayBoundary = yield* makeReplayBoundaryTracker(snapshotSequence);
32759
33292
  const replayMetrics = yield* makeWsReplayMetrics({
32760
33293
  stream: "shell",
@@ -32763,8 +33296,13 @@ const makeOrchestrationStreamHelpers = (deps) => {
32763
33296
  });
32764
33297
  yield* Stream.fromSubscription(liveSubscription).pipe(Stream.runForEach((event) => Effect.gen(function* () {
32765
33298
  yield* replayBoundary.recordLiveSequence(event.sequence);
32766
- yield* Queue.offer(liveQueue, event);
32767
- yield* replayMetrics.recordLiveEnqueued(event.sequence);
33299
+ yield* offerOrchestrationLiveEventOrFail({
33300
+ stream: "shell",
33301
+ event,
33302
+ liveQueue,
33303
+ overflowedRef,
33304
+ replayMetrics
33305
+ });
32768
33306
  })), Effect.ensuring(Queue.shutdown(liveQueue)), Effect.ignoreCause({ log: true }), Effect.forkScoped);
32769
33307
  const replayStream = makeBoundedReplayStream({
32770
33308
  snapshotSequence,
@@ -32782,8 +33320,9 @@ const makeOrchestrationStreamHelpers = (deps) => {
32782
33320
  const loadedSnapshot = yield* snapshot;
32783
33321
  const snapshotSequence = loadedSnapshot.snapshotSequence;
32784
33322
  const liveSubscription = yield* orchestrationEngine.subscribeDomainEvents;
32785
- const liveQueue = yield* Queue.unbounded();
33323
+ const liveQueue = yield* Queue.bounded(ORCHESTRATION_LIVE_QUEUE_MAX_EVENTS);
32786
33324
  const lastSequenceRef = yield* Ref.make(snapshotSequence);
33325
+ const overflowedRef = yield* Ref.make(false);
32787
33326
  const replayBoundary = yield* makeReplayBoundaryTracker(snapshotSequence);
32788
33327
  const replayMetrics = yield* makeWsReplayMetrics({
32789
33328
  stream: "thread",
@@ -32796,8 +33335,13 @@ const makeOrchestrationStreamHelpers = (deps) => {
32796
33335
  })));
32797
33336
  yield* Stream.fromSubscription(liveSubscription).pipe(Stream.runForEach((event) => Effect.gen(function* () {
32798
33337
  yield* replayBoundary.recordLiveSequence(event.sequence);
32799
- yield* Queue.offer(liveQueue, event);
32800
- yield* replayMetrics.recordLiveEnqueued(event.sequence);
33338
+ yield* offerOrchestrationLiveEventOrFail({
33339
+ stream: "thread",
33340
+ event,
33341
+ liveQueue,
33342
+ overflowedRef,
33343
+ replayMetrics
33344
+ });
32801
33345
  })), Effect.ensuring(Queue.shutdown(liveQueue)), Effect.ignoreCause({ log: true }), Effect.forkScoped);
32802
33346
  const replayStream = makeBoundedReplayStream({
32803
33347
  snapshotSequence,
@@ -33338,6 +33882,7 @@ function toDiagnosticsProviderProcess(provider) {
33338
33882
  const makeWsRpcContext = (session) => Effect.gen(function* () {
33339
33883
  const currentSessionId = session.sessionId;
33340
33884
  const projectionSnapshotQuery = yield* ProjectionSnapshotQuery;
33885
+ const statisticsQuery = yield* StatisticsQuery;
33341
33886
  const orchestrationEngine = yield* OrchestrationEngineService;
33342
33887
  const checkpointDiffQuery = yield* CheckpointDiffQuery;
33343
33888
  const keybindings = yield* Keybindings;
@@ -33661,6 +34206,7 @@ const makeWsRpcContext = (session) => Effect.gen(function* () {
33661
34206
  return {
33662
34207
  currentSessionId,
33663
34208
  projectionSnapshotQuery,
34209
+ statisticsQuery,
33664
34210
  orchestrationEngine,
33665
34211
  checkpointDiffQuery,
33666
34212
  keybindings,
@@ -33938,9 +34484,9 @@ function recordServerPerfPayload(label, value, record) {
33938
34484
  //#endregion
33939
34485
  //#region src/ws/orchestrationRpc.ts
33940
34486
  const makeOrchestrationHandlers = (ctx) => {
33941
- const { withAccess, ownerEffect, projectionSnapshotQuery, dispatchNormalizedCommand, dispatchWorktreeCommand, serverCommandId, terminalManager, checkpointDiffQuery, orchestrationEngine, enrichOrchestrationEvents, makeReplayableShellStream, makeReplayableThreadStream } = ctx;
34487
+ const { ownerEffect, projectionSnapshotQuery, dispatchNormalizedCommand, dispatchWorktreeCommand, serverCommandId, terminalManager, checkpointDiffQuery, orchestrationEngine, enrichOrchestrationEvents, makeReplayableShellStream, makeReplayableThreadStream } = ctx;
33942
34488
  return defineWsHandlers({
33943
- [ORCHESTRATION_WS_METHODS.dispatchCommand]: (command) => observeRpcEffect(ORCHESTRATION_WS_METHODS.dispatchCommand, withAccess("authenticated", ORCHESTRATION_WS_METHODS.dispatchCommand, Effect.gen(function* () {
34489
+ [ORCHESTRATION_WS_METHODS.dispatchCommand]: (command) => observeRpcEffect(ORCHESTRATION_WS_METHODS.dispatchCommand, ownerEffect(ORCHESTRATION_WS_METHODS.dispatchCommand, Effect.gen(function* () {
33944
34490
  const normalizedCommand = yield* normalizeDispatchCommand(command);
33945
34491
  const shouldStopSessionAfterArchive = normalizedCommand.type === "thread.archive" ? yield* projectionSnapshotQuery.getThreadShellById(normalizedCommand.threadId).pipe(Effect.map(Option.match({
33946
34492
  onNone: () => false,
@@ -33980,7 +34526,7 @@ const makeOrchestrationHandlers = (ctx) => {
33980
34526
  [ORCHESTRATION_WS_METHODS.replayEvents]: (input) => observeRpcEffect(ORCHESTRATION_WS_METHODS.replayEvents, Stream.runCollect(orchestrationEngine.readEvents(clamp(input.fromSequenceExclusive, {
33981
34527
  maximum: Number.MAX_SAFE_INTEGER,
33982
34528
  minimum: 0
33983
- }))).pipe(Effect.map((events) => Array.from(events)), Effect.flatMap(enrichOrchestrationEvents), Effect.mapError((cause) => new OrchestrationReplayEventsError({
34529
+ }), ORCHESTRATION_LEGACY_REPLAY_MAX_EVENTS)).pipe(Effect.map((events) => Array.from(events)), Effect.flatMap(enrichOrchestrationEvents), Effect.mapError((cause) => new OrchestrationReplayEventsError({
33984
34530
  message: "Failed to replay orchestration events",
33985
34531
  cause
33986
34532
  }))), { "rpc.aggregate": "orchestration" }),
@@ -34111,10 +34657,25 @@ const makeTerminalHandlers = (ctx) => {
34111
34657
  [WS_METHODS.terminalClear]: (input) => observeRpcEffect(WS_METHODS.terminalClear, ownerEffect(WS_METHODS.terminalClear, terminalManager.clear(input)), { "rpc.aggregate": "terminal" }),
34112
34658
  [WS_METHODS.terminalRestart]: (input) => observeRpcEffect(WS_METHODS.terminalRestart, ownerEffect(WS_METHODS.terminalRestart, terminalManager.restart(input)), { "rpc.aggregate": "terminal" }),
34113
34659
  [WS_METHODS.terminalClose]: (input) => observeRpcEffect(WS_METHODS.terminalClose, ownerEffect(WS_METHODS.terminalClose, terminalManager.close(input)), { "rpc.aggregate": "terminal" }),
34114
- [WS_METHODS.subscribeTerminalEvents]: (_input) => observeRpcStream(WS_METHODS.subscribeTerminalEvents, ownerStream(WS_METHODS.subscribeTerminalEvents, Stream.callback((queue) => Effect.acquireRelease(terminalManager.subscribe((event) => Effect.gen(function* () {
34115
- recordServerPerfPayload("server.ws.terminal.events", event);
34116
- yield* Queue.offer(queue, event);
34117
- })), (unsubscribe) => Effect.sync(unsubscribe)))), { "rpc.aggregate": "terminal" })
34660
+ [WS_METHODS.subscribeTerminalEvents]: (_input) => observeRpcStream(WS_METHODS.subscribeTerminalEvents, ownerStream(WS_METHODS.subscribeTerminalEvents, Stream.callback((queue) => Effect.acquireRelease(Effect.gen(function* () {
34661
+ const unsubscribe = yield* terminalManager.subscribe((event) => Effect.gen(function* () {
34662
+ recordServerPerfPayload("server.ws.terminal.events", event);
34663
+ yield* Queue.offer(queue, event);
34664
+ }));
34665
+ const snapshots = yield* terminalManager.listSessions;
34666
+ yield* Effect.forEach(snapshots.filter((snapshot) => snapshot.status === "running"), (snapshot) => {
34667
+ const event = {
34668
+ type: "started",
34669
+ threadId: snapshot.threadId,
34670
+ terminalId: snapshot.terminalId,
34671
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
34672
+ snapshot
34673
+ };
34674
+ recordServerPerfPayload("server.ws.terminal.events", event);
34675
+ return Queue.offer(queue, event);
34676
+ }, { discard: true });
34677
+ return unsubscribe;
34678
+ }), (unsubscribe) => Effect.sync(unsubscribe)))), { "rpc.aggregate": "terminal" })
34118
34679
  });
34119
34680
  };
34120
34681
  //#endregion
@@ -34209,7 +34770,7 @@ const makeSourceControlHandlers = (ctx) => {
34209
34770
  cwd,
34210
34771
  reason: "sourceControl.searchIssues"
34211
34772
  })))), { "rpc.aggregate": "source-control" }),
34212
- [WS_METHODS.sourceControlListChangeRequests]: ({ cwd, state, limit, query }) => observeRpcEffect(WS_METHODS.sourceControlListChangeRequests, sourceControlRegistry.resolve({ cwd }).pipe(Effect.flatMap((provider) => {
34773
+ [WS_METHODS.sourceControlListChangeRequests]: ({ cwd, state, limit, query }) => observeRpcEffect(WS_METHODS.sourceControlListChangeRequests, ownerEffect(WS_METHODS.sourceControlListChangeRequests, sourceControlRegistry.resolve({ cwd }).pipe(Effect.flatMap((provider) => {
34213
34774
  const trimmedQuery = query?.trim() ?? "";
34214
34775
  if (trimmedQuery.length > 0) return provider.searchChangeRequests({
34215
34776
  cwd,
@@ -34225,7 +34786,7 @@ const makeSourceControlHandlers = (ctx) => {
34225
34786
  }), Effect.tap(() => refreshLinkedWorktreeSourceControlStates({
34226
34787
  cwd,
34227
34788
  reason: "sourceControl.listChangeRequests"
34228
- }))), { "rpc.aggregate": "source-control" }),
34789
+ })))), { "rpc.aggregate": "source-control" }),
34229
34790
  [WS_METHODS.sourceControlSearchChangeRequests]: ({ cwd, query, limit }) => observeRpcEffect(WS_METHODS.sourceControlSearchChangeRequests, ownerEffect(WS_METHODS.sourceControlSearchChangeRequests, sourceControlRegistry.resolve({ cwd }).pipe(Effect.flatMap((provider) => provider.searchChangeRequests({
34230
34791
  cwd,
34231
34792
  query,
@@ -34975,12 +35536,19 @@ const makeProviderHandlers = (ctx) => {
34975
35536
  });
34976
35537
  };
34977
35538
  //#endregion
35539
+ //#region src/ws/statisticsRpc.ts
35540
+ const makeStatisticsHandlers = (ctx) => {
35541
+ const { statisticsQuery, ownerEffect } = ctx;
35542
+ return defineWsHandlers({ [WS_METHODS.serverGetStatistics]: (_input) => observeRpcEffect(WS_METHODS.serverGetStatistics, ownerEffect(WS_METHODS.serverGetStatistics, statisticsQuery.getStatistics().pipe(Effect.orDie)), { "rpc.aggregate": "server" }) });
35543
+ };
35544
+ //#endregion
34978
35545
  //#region src/ws/index.ts
34979
35546
  const makeWsRpcLayer = (session) => WsRpcGroup.toLayer(Effect.gen(function* () {
34980
35547
  const ctx = yield* makeWsRpcContext(session);
34981
35548
  return WsRpcGroup.of({
34982
35549
  ...makeOrchestrationHandlers(ctx),
34983
35550
  ...makeProviderHandlers(ctx),
35551
+ ...makeStatisticsHandlers(ctx),
34984
35552
  ...makeSourceControlHandlers(ctx),
34985
35553
  ...makeProjectHandlers(ctx),
34986
35554
  ...makeGitHandlers(ctx),
@@ -37398,6 +37966,8 @@ const DEFAULT_PERSIST_DEBOUNCE_MS = 40;
37398
37966
  const DEFAULT_SUBPROCESS_POLL_INTERVAL_MS = 1e3;
37399
37967
  const DEFAULT_PROCESS_KILL_GRACE_MS = 1e3;
37400
37968
  const DEFAULT_MAX_RETAINED_INACTIVE_SESSIONS = 128;
37969
+ const DEFAULT_MAX_PENDING_PROCESS_EVENTS = 2048;
37970
+ const DEFAULT_MAX_PENDING_PROCESS_OUTPUT_BYTES = 2 * 1024 * 1024;
37401
37971
  const DEFAULT_OPEN_COLS = 120;
37402
37972
  const DEFAULT_OPEN_ROWS = 30;
37403
37973
  const TERMINAL_ENV_BLOCKLIST = new Set([
@@ -37454,13 +38024,86 @@ function cleanupProcessHandles(session) {
37454
38024
  session.unsubscribeExit?.();
37455
38025
  session.unsubscribeExit = null;
37456
38026
  }
37457
- function enqueueProcessEvent(session, expectedPid, event) {
38027
+ function clearPendingProcessEvents(session) {
38028
+ session.pendingProcessEvents = [];
38029
+ session.pendingProcessEventIndex = 0;
38030
+ session.pendingProcessOutputBytes = 0;
38031
+ session.processEventDrainRunning = false;
38032
+ }
38033
+ function enqueueProcessEvent(session, expectedPid, event, limits) {
37458
38034
  if (!session.process || session.status !== "running" || session.pid !== expectedPid) return false;
38035
+ if (event.type === "output" && session.pendingProcessEvents.some((pendingEvent) => pendingEvent.type === "exit")) return false;
38036
+ compactPendingProcessEvents(session);
37459
38037
  session.pendingProcessEvents.push(event);
38038
+ if (event.type === "output") session.pendingProcessOutputBytes += event.byteLength;
38039
+ enforcePendingProcessEventLimits(session, limits);
37460
38040
  if (session.processEventDrainRunning) return false;
37461
38041
  session.processEventDrainRunning = true;
37462
38042
  return true;
37463
38043
  }
38044
+ function compactPendingProcessEvents(session) {
38045
+ if (session.pendingProcessEventIndex <= 0) return;
38046
+ session.pendingProcessEvents = session.pendingProcessEvents.slice(session.pendingProcessEventIndex);
38047
+ session.pendingProcessEventIndex = 0;
38048
+ }
38049
+ function coalesceOldestPendingOutputPair(session) {
38050
+ for (let index = 0; index < session.pendingProcessEvents.length - 1; index += 1) {
38051
+ const current = session.pendingProcessEvents[index];
38052
+ const next = session.pendingProcessEvents[index + 1];
38053
+ if (current?.type !== "output" || next?.type !== "output") continue;
38054
+ session.pendingProcessEvents.splice(index, 2, {
38055
+ type: "output",
38056
+ data: `${current.data}${next.data}`,
38057
+ byteLength: current.byteLength + next.byteLength
38058
+ });
38059
+ return true;
38060
+ }
38061
+ return false;
38062
+ }
38063
+ function trimOutputDataToApproxBytes(data, maxBytes) {
38064
+ if (maxBytes <= 0 || data.length === 0) return {
38065
+ data: "",
38066
+ byteLength: 0
38067
+ };
38068
+ let nextData = data;
38069
+ let byteLength = approximateTextBytes(nextData);
38070
+ while (byteLength > maxBytes && nextData.length > 0) {
38071
+ const excessBytes = byteLength - maxBytes;
38072
+ const sliceStart = Math.min(nextData.length, Math.max(1, excessBytes));
38073
+ nextData = nextData.slice(sliceStart);
38074
+ byteLength = approximateTextBytes(nextData);
38075
+ }
38076
+ return {
38077
+ data: nextData,
38078
+ byteLength
38079
+ };
38080
+ }
38081
+ function trimPendingOutputBytesToLimit(session, maxPendingProcessOutputBytes) {
38082
+ if (session.pendingProcessOutputBytes <= maxPendingProcessOutputBytes) return;
38083
+ for (let index = 0; index < session.pendingProcessEvents.length; index += 1) {
38084
+ if (session.pendingProcessOutputBytes <= maxPendingProcessOutputBytes) return;
38085
+ const event = session.pendingProcessEvents[index];
38086
+ if (event?.type !== "output") continue;
38087
+ const targetEventBytes = Math.max(0, event.byteLength - (session.pendingProcessOutputBytes - maxPendingProcessOutputBytes));
38088
+ if (targetEventBytes <= 0) {
38089
+ session.pendingProcessEvents.splice(index, 1);
38090
+ session.pendingProcessOutputBytes = Math.max(0, session.pendingProcessOutputBytes - event.byteLength);
38091
+ index -= 1;
38092
+ continue;
38093
+ }
38094
+ const trimmed = trimOutputDataToApproxBytes(event.data, targetEventBytes);
38095
+ session.pendingProcessEvents[index] = {
38096
+ type: "output",
38097
+ data: trimmed.data,
38098
+ byteLength: trimmed.byteLength
38099
+ };
38100
+ session.pendingProcessOutputBytes = Math.max(0, session.pendingProcessOutputBytes - (event.byteLength - trimmed.byteLength));
38101
+ }
38102
+ }
38103
+ function enforcePendingProcessEventLimits(session, limits) {
38104
+ while (session.pendingProcessEvents.length > limits.maxPendingProcessEvents && coalesceOldestPendingOutputPair(session));
38105
+ trimPendingOutputBytesToLimit(session, limits.maxPendingProcessOutputBytes);
38106
+ }
37464
38107
  function defaultShellResolver(platform = process.platform, env = process.env) {
37465
38108
  if (platform === "win32") return "pwsh.exe";
37466
38109
  return env.SHELL ?? "bash";
@@ -37827,6 +38470,10 @@ const makeTerminalManagerWithOptions = Effect.fn("makeTerminalManagerWithOptions
37827
38470
  const subprocessPollIntervalMs = options.subprocessPollIntervalMs ?? DEFAULT_SUBPROCESS_POLL_INTERVAL_MS;
37828
38471
  const processKillGraceMs = options.processKillGraceMs ?? DEFAULT_PROCESS_KILL_GRACE_MS;
37829
38472
  const maxRetainedInactiveSessions = options.maxRetainedInactiveSessions ?? DEFAULT_MAX_RETAINED_INACTIVE_SESSIONS;
38473
+ const pendingProcessEventLimits = {
38474
+ maxPendingProcessEvents: Math.max(1, options.maxPendingProcessEvents ?? DEFAULT_MAX_PENDING_PROCESS_EVENTS),
38475
+ maxPendingProcessOutputBytes: Math.max(1, options.maxPendingProcessOutputBytes ?? DEFAULT_MAX_PENDING_PROCESS_OUTPUT_BYTES)
38476
+ };
37830
38477
  yield* fileSystem.makeDirectory(logsDir, { recursive: true }).pipe(Effect.orDie);
37831
38478
  const managerStateRef = yield* SynchronizedRef.make({
37832
38479
  sessions: /* @__PURE__ */ new Map(),
@@ -38063,16 +38710,12 @@ const makeTerminalManagerWithOptions = Effect.fn("makeTerminalManagerWithOptions
38063
38710
  while (true) {
38064
38711
  const action = yield* Effect.sync(() => {
38065
38712
  if (session.pid !== expectedPid || !session.process || session.status !== "running") {
38066
- session.pendingProcessEvents = [];
38067
- session.pendingProcessEventIndex = 0;
38068
- session.processEventDrainRunning = false;
38713
+ clearPendingProcessEvents(session);
38069
38714
  return { type: "idle" };
38070
38715
  }
38071
38716
  const nextEvent = session.pendingProcessEvents[session.pendingProcessEventIndex];
38072
38717
  if (!nextEvent) {
38073
- session.pendingProcessEvents = [];
38074
- session.pendingProcessEventIndex = 0;
38075
- session.processEventDrainRunning = false;
38718
+ clearPendingProcessEvents(session);
38076
38719
  return { type: "idle" };
38077
38720
  }
38078
38721
  session.pendingProcessEventIndex += 1;
@@ -38081,6 +38724,7 @@ const makeTerminalManagerWithOptions = Effect.fn("makeTerminalManagerWithOptions
38081
38724
  session.pendingProcessEventIndex = 0;
38082
38725
  }
38083
38726
  if (nextEvent.type === "output") {
38727
+ session.pendingProcessOutputBytes = Math.max(0, session.pendingProcessOutputBytes - nextEvent.byteLength);
38084
38728
  const sanitized = sanitizeTerminalHistoryChunk(session.pendingHistoryControlSequence, nextEvent.data);
38085
38729
  session.pendingHistoryControlSequence = sanitized.pendingControlSequence;
38086
38730
  if (sanitized.visibleText.length > 0) session.history = capHistory(`${session.history}${sanitized.visibleText}`, historyLineLimit);
@@ -38100,9 +38744,7 @@ const makeTerminalManagerWithOptions = Effect.fn("makeTerminalManagerWithOptions
38100
38744
  session.hasRunningSubprocess = false;
38101
38745
  session.status = "exited";
38102
38746
  session.pendingHistoryControlSequence = "";
38103
- session.pendingProcessEvents = [];
38104
- session.pendingProcessEventIndex = 0;
38105
- session.processEventDrainRunning = false;
38747
+ clearPendingProcessEvents(session);
38106
38748
  session.exitCode = Number.isInteger(nextEvent.event.exitCode) ? nextEvent.event.exitCode : null;
38107
38749
  session.exitSignal = Number.isInteger(nextEvent.event.signal) ? nextEvent.event.signal : null;
38108
38750
  session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -38150,9 +38792,7 @@ const makeTerminalManagerWithOptions = Effect.fn("makeTerminalManagerWithOptions
38150
38792
  session.hasRunningSubprocess = false;
38151
38793
  session.status = "exited";
38152
38794
  session.pendingHistoryControlSequence = "";
38153
- session.pendingProcessEvents = [];
38154
- session.pendingProcessEventIndex = 0;
38155
- session.processEventDrainRunning = false;
38795
+ clearPendingProcessEvents(session);
38156
38796
  session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
38157
38797
  return [void 0, state];
38158
38798
  });
@@ -38204,9 +38844,7 @@ const makeTerminalManagerWithOptions = Effect.fn("makeTerminalManagerWithOptions
38204
38844
  session.exitCode = null;
38205
38845
  session.exitSignal = null;
38206
38846
  session.hasRunningSubprocess = false;
38207
- session.pendingProcessEvents = [];
38208
- session.pendingProcessEventIndex = 0;
38209
- session.processEventDrainRunning = false;
38847
+ clearPendingProcessEvents(session);
38210
38848
  session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
38211
38849
  return [void 0, state];
38212
38850
  });
@@ -38220,15 +38858,16 @@ const makeTerminalManagerWithOptions = Effect.fn("makeTerminalManagerWithOptions
38220
38858
  const unsubscribeData = ptyProcess.onData((data) => {
38221
38859
  if (!enqueueProcessEvent(session, processPid, {
38222
38860
  type: "output",
38223
- data
38224
- })) return;
38861
+ data,
38862
+ byteLength: approximateTextBytes(data)
38863
+ }, pendingProcessEventLimits)) return;
38225
38864
  runFork(drainProcessEvents(session, processPid));
38226
38865
  });
38227
38866
  const unsubscribeExit = ptyProcess.onExit((event) => {
38228
38867
  if (!enqueueProcessEvent(session, processPid, {
38229
38868
  type: "exit",
38230
38869
  event
38231
- })) return;
38870
+ }, pendingProcessEventLimits)) return;
38232
38871
  runFork(drainProcessEvents(session, processPid));
38233
38872
  });
38234
38873
  yield* modifyManagerState((state) => {
@@ -38260,9 +38899,7 @@ const makeTerminalManagerWithOptions = Effect.fn("makeTerminalManagerWithOptions
38260
38899
  session.unsubscribeData = null;
38261
38900
  session.unsubscribeExit = null;
38262
38901
  session.hasRunningSubprocess = false;
38263
- session.pendingProcessEvents = [];
38264
- session.pendingProcessEventIndex = 0;
38265
- session.processEventDrainRunning = false;
38902
+ clearPendingProcessEvents(session);
38266
38903
  session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
38267
38904
  return [void 0, state];
38268
38905
  });
@@ -38372,6 +39009,7 @@ const makeTerminalManagerWithOptions = Effect.fn("makeTerminalManagerWithOptions
38372
39009
  pendingHistoryControlSequence: "",
38373
39010
  pendingProcessEvents: [],
38374
39011
  pendingProcessEventIndex: 0,
39012
+ pendingProcessOutputBytes: 0,
38375
39013
  processEventDrainRunning: false,
38376
39014
  exitCode: null,
38377
39015
  exitSignal: null,
@@ -38418,18 +39056,14 @@ const makeTerminalManagerWithOptions = Effect.fn("makeTerminalManagerWithOptions
38418
39056
  liveSession.runtimeEnv = nextRuntimeEnv;
38419
39057
  liveSession.history = "";
38420
39058
  liveSession.pendingHistoryControlSequence = "";
38421
- liveSession.pendingProcessEvents = [];
38422
- liveSession.pendingProcessEventIndex = 0;
38423
- liveSession.processEventDrainRunning = false;
39059
+ clearPendingProcessEvents(liveSession);
38424
39060
  yield* persistHistory(liveSession.threadId, liveSession.terminalId, liveSession.history);
38425
39061
  } else if (liveSession.status === "exited" || liveSession.status === "error") {
38426
39062
  liveSession.runtimeEnv = nextRuntimeEnv;
38427
39063
  liveSession.worktreePath = input.worktreePath ?? null;
38428
39064
  liveSession.history = "";
38429
39065
  liveSession.pendingHistoryControlSequence = "";
38430
- liveSession.pendingProcessEvents = [];
38431
- liveSession.pendingProcessEventIndex = 0;
38432
- liveSession.processEventDrainRunning = false;
39066
+ clearPendingProcessEvents(liveSession);
38433
39067
  yield* persistHistory(liveSession.threadId, liveSession.terminalId, liveSession.history);
38434
39068
  }
38435
39069
  if (!liveSession.process) {
@@ -38483,9 +39117,7 @@ const makeTerminalManagerWithOptions = Effect.fn("makeTerminalManagerWithOptions
38483
39117
  const session = yield* requireSession(input.threadId, terminalId);
38484
39118
  session.history = "";
38485
39119
  session.pendingHistoryControlSequence = "";
38486
- session.pendingProcessEvents = [];
38487
- session.pendingProcessEventIndex = 0;
38488
- session.processEventDrainRunning = false;
39120
+ clearPendingProcessEvents(session);
38489
39121
  session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
38490
39122
  yield* persistHistory(input.threadId, terminalId, session.history);
38491
39123
  yield* publishEvent({
@@ -38516,6 +39148,7 @@ const makeTerminalManagerWithOptions = Effect.fn("makeTerminalManagerWithOptions
38516
39148
  pendingHistoryControlSequence: "",
38517
39149
  pendingProcessEvents: [],
38518
39150
  pendingProcessEventIndex: 0,
39151
+ pendingProcessOutputBytes: 0,
38519
39152
  processEventDrainRunning: false,
38520
39153
  exitCode: null,
38521
39154
  exitSignal: null,
@@ -38549,9 +39182,7 @@ const makeTerminalManagerWithOptions = Effect.fn("makeTerminalManagerWithOptions
38549
39182
  const rows = input.rows ?? session.rows;
38550
39183
  session.history = "";
38551
39184
  session.pendingHistoryControlSequence = "";
38552
- session.pendingProcessEvents = [];
38553
- session.pendingProcessEventIndex = 0;
38554
- session.processEventDrainRunning = false;
39185
+ clearPendingProcessEvents(session);
38555
39186
  yield* persistHistory(input.threadId, terminalId, session.history);
38556
39187
  yield* startSession(session, {
38557
39188
  threadId: input.threadId,
@@ -38573,6 +39204,7 @@ const makeTerminalManagerWithOptions = Effect.fn("makeTerminalManagerWithOptions
38573
39204
  yield* Effect.forEach(threadSessions, (session) => closeSession(input.threadId, session.terminalId, false), { discard: true });
38574
39205
  if (input.deleteHistory) yield* deleteAllHistoryForThread(input.threadId);
38575
39206
  }));
39207
+ const listSessions = SynchronizedRef.get(managerStateRef).pipe(Effect.map((state) => [...state.sessions.values()].map(snapshot).toSorted((left, right) => right.updatedAt.localeCompare(left.updatedAt))));
38576
39208
  return {
38577
39209
  open,
38578
39210
  write,
@@ -38581,6 +39213,7 @@ const makeTerminalManagerWithOptions = Effect.fn("makeTerminalManagerWithOptions
38581
39213
  restart,
38582
39214
  close,
38583
39215
  listDiagnostics: SynchronizedRef.get(managerStateRef).pipe(Effect.map((state) => [...state.sessions.values()].map(diagnosticsSnapshot).toSorted((left, right) => right.updatedAt.localeCompare(left.updatedAt)))),
39216
+ listSessions,
38584
39217
  subscribe: (listener) => Effect.sync(() => {
38585
39218
  terminalEventListeners.add(listener);
38586
39219
  return () => {
@@ -39076,7 +39709,7 @@ function isGitRepository(cwd) {
39076
39709
  //#endregion
39077
39710
  //#region src/orchestration/Layers/ProviderRuntimeIngestion.ts
39078
39711
  const providerTurnKey = (threadId, turnId) => `${threadId}:${turnId}`;
39079
- const providerCommandId = (event, tag) => CommandId.make(`provider:${event.eventId}:${tag}:${crypto.randomUUID()}`);
39712
+ const providerCommandId = (event, tag, discriminator) => CommandId.make(discriminator === void 0 ? `provider:${event.eventId}:${tag}` : `provider:${event.eventId}:${tag}:${discriminator}`);
39080
39713
  const liveAssistantDeltaBufferKey = (threadId, messageId) => `${threadId}:${messageId}`;
39081
39714
  const TURN_MESSAGE_IDS_BY_TURN_CACHE_CAPACITY = 1e4;
39082
39715
  const TURN_MESSAGE_IDS_BY_TURN_TTL = Duration.minutes(120);
@@ -39150,6 +39783,7 @@ function rawPayloadThreadId(event) {
39150
39783
  return asTrimmedString(asRecord(event.raw?.payload)?.threadId);
39151
39784
  }
39152
39785
  function collabReceiverThreadIdsFromRuntimeEvent(event) {
39786
+ if (event.type === "subagent.started" || event.type === "subagent.updated" || event.type === "subagent.completed") return event.payload.subagent.providerThreadId ? [event.payload.subagent.providerThreadId] : [];
39153
39787
  if (event.type !== "item.started" && event.type !== "item.updated" && event.type !== "item.completed") return [];
39154
39788
  if (event.payload.itemType !== "collab_agent_tool_call") return [];
39155
39789
  const item = asRecord(asRecord(event.payload.data)?.item);
@@ -39207,6 +39841,9 @@ function normalizeRuntimeTurnState(value) {
39207
39841
  default: return "completed";
39208
39842
  }
39209
39843
  }
39844
+ function isTerminalProjectionTurnState(state) {
39845
+ return state === "completed" || state === "error" || state === "interrupted";
39846
+ }
39210
39847
  function orchestrationSessionStatusFromRuntimeState(state) {
39211
39848
  switch (state) {
39212
39849
  case "starting": return "starting";
@@ -39394,6 +40031,53 @@ function runtimeEventToActivities(event) {
39394
40031
  turnId: toTurnId$1(event.turnId) ?? null,
39395
40032
  ...maybeSequence
39396
40033
  }];
40034
+ case "subagent.started": return [{
40035
+ id: event.eventId,
40036
+ createdAt: event.createdAt,
40037
+ tone: "tool",
40038
+ kind: "subagent.started",
40039
+ summary: `${event.payload.subagent.label ?? "Subagent"} started`,
40040
+ payload: {
40041
+ itemType: "collab_agent_tool_call",
40042
+ status: "running",
40043
+ subagent: event.payload.subagent
40044
+ },
40045
+ turnId: toTurnId$1(event.turnId) ?? null,
40046
+ ...maybeSequence
40047
+ }];
40048
+ case "subagent.updated": return [{
40049
+ id: event.eventId,
40050
+ createdAt: event.createdAt,
40051
+ tone: "tool",
40052
+ kind: "subagent.updated",
40053
+ summary: event.payload.summary ?? `${event.payload.subagent.label ?? "Subagent"} updated`,
40054
+ payload: {
40055
+ itemType: "collab_agent_tool_call",
40056
+ ...event.payload.status ? { status: event.payload.status } : {},
40057
+ subagent: event.payload.subagent,
40058
+ ...event.payload.detail ? { detail: truncateDetail(event.payload.detail) } : {},
40059
+ ...event.payload.summary ? { summary: truncateDetail(event.payload.summary) } : {},
40060
+ ...event.payload.usage !== void 0 ? { usage: event.payload.usage } : {}
40061
+ },
40062
+ turnId: toTurnId$1(event.turnId) ?? null,
40063
+ ...maybeSequence
40064
+ }];
40065
+ case "subagent.completed": return [{
40066
+ id: event.eventId,
40067
+ createdAt: event.createdAt,
40068
+ tone: event.payload.status === "failed" ? "error" : "tool",
40069
+ kind: "subagent.completed",
40070
+ summary: event.payload.status === "failed" ? `${event.payload.subagent.label ?? "Subagent"} failed` : event.payload.status === "stopped" ? `${event.payload.subagent.label ?? "Subagent"} stopped` : `${event.payload.subagent.label ?? "Subagent"} completed`,
40071
+ payload: {
40072
+ itemType: "collab_agent_tool_call",
40073
+ status: event.payload.status,
40074
+ subagent: event.payload.subagent,
40075
+ ...event.payload.summary ? { detail: truncateDetail(event.payload.summary) } : {},
40076
+ ...event.payload.usage !== void 0 ? { usage: event.payload.usage } : {}
40077
+ },
40078
+ turnId: toTurnId$1(event.turnId) ?? null,
40079
+ ...maybeSequence
40080
+ }];
39397
40081
  case "thread.state.changed":
39398
40082
  if (event.payload.state !== "compacted") return [];
39399
40083
  return [{
@@ -39586,7 +40270,7 @@ const make$3 = Effect.gen(function* () {
39586
40270
  }
39587
40271
  yield* orchestrationEngine.dispatch({
39588
40272
  type: "thread.message.assistant.delta",
39589
- commandId: providerCommandId(buffer.event, input.commandTag),
40273
+ commandId: providerCommandId(buffer.event, input.commandTag, String(buffer.messageId)),
39590
40274
  threadId: buffer.threadId,
39591
40275
  messageId: buffer.messageId,
39592
40276
  delta: buffer.text,
@@ -39665,9 +40349,10 @@ const make$3 = Effect.gen(function* () {
39665
40349
  };
39666
40350
  const upsertSubagentMessageActivity = (input) => Effect.gen(function* () {
39667
40351
  const sessionSequence = input.event.sessionSequence;
40352
+ const commandKey = `${input.providerThreadId}:${input.providerItemId}`;
39668
40353
  yield* orchestrationEngine.dispatch({
39669
40354
  type: "thread.activity.append",
39670
- commandId: providerCommandId(input.event, "subagent-message-upsert"),
40355
+ commandId: providerCommandId(input.event, "subagent-message-upsert", commandKey),
39671
40356
  threadId: input.threadId,
39672
40357
  activity: {
39673
40358
  id: subagentMessageActivityId({
@@ -39685,6 +40370,7 @@ const make$3 = Effect.gen(function* () {
39685
40370
  streaming: input.streaming,
39686
40371
  providerThreadId: input.providerThreadId,
39687
40372
  providerItemId: input.providerItemId,
40373
+ ...input.subagentId ? { subagentId: input.subagentId } : {},
39688
40374
  ...input.event.providerRefs ? { providerRefs: input.event.providerRefs } : {}
39689
40375
  },
39690
40376
  turnId: toTurnId$1(input.event.turnId) ?? null,
@@ -39724,6 +40410,16 @@ const make$3 = Effect.gen(function* () {
39724
40410
  streaming: false
39725
40411
  });
39726
40412
  });
40413
+ const bufferedSubagentProviderItemIds = (input) => {
40414
+ const prefix = subagentMessageBufferKey({
40415
+ threadId: input.threadId,
40416
+ providerThreadId: input.providerThreadId,
40417
+ providerItemId: ""
40418
+ });
40419
+ const providerItemIds = /* @__PURE__ */ new Set();
40420
+ for (const key of subagentMessageTextByKey.keys()) if (key.startsWith(prefix)) providerItemIds.add(key.slice(prefix.length));
40421
+ return [...providerItemIds];
40422
+ };
39727
40423
  const clearSubagentMessageBuffersForThread = (threadId) => Effect.sync(() => {
39728
40424
  const prefix = `${threadId}:`;
39729
40425
  for (const key of subagentMessageTextByKey.keys()) if (key.startsWith(prefix)) subagentMessageTextByKey.delete(key);
@@ -39757,7 +40453,7 @@ const make$3 = Effect.gen(function* () {
39757
40453
  if (!hasRenderableAssistantText(bufferedText)) return false;
39758
40454
  yield* orchestrationEngine.dispatch({
39759
40455
  type: "thread.message.assistant.delta",
39760
- commandId: providerCommandId(input.event, input.commandTag),
40456
+ commandId: providerCommandId(input.event, input.commandTag, String(input.messageId)),
39761
40457
  threadId: input.threadId,
39762
40458
  messageId: input.messageId,
39763
40459
  delta: bufferedText,
@@ -39785,7 +40481,7 @@ const make$3 = Effect.gen(function* () {
39785
40481
  const hasRenderableText = hasRenderableAssistantText(text);
39786
40482
  if (hasRenderableText) yield* orchestrationEngine.dispatch({
39787
40483
  type: "thread.message.assistant.delta",
39788
- commandId: providerCommandId(input.event, input.finalDeltaCommandTag),
40484
+ commandId: providerCommandId(input.event, input.finalDeltaCommandTag, String(input.messageId)),
39789
40485
  threadId: input.threadId,
39790
40486
  messageId: input.messageId,
39791
40487
  delta: text,
@@ -39794,7 +40490,7 @@ const make$3 = Effect.gen(function* () {
39794
40490
  });
39795
40491
  if (input.hasProjectedMessage || hasRenderableText) yield* orchestrationEngine.dispatch({
39796
40492
  type: "thread.message.assistant.complete",
39797
- commandId: providerCommandId(input.event, input.commandTag),
40493
+ commandId: providerCommandId(input.event, input.commandTag, String(input.messageId)),
39798
40494
  threadId: input.threadId,
39799
40495
  messageId: input.messageId,
39800
40496
  ...input.turnId ? { turnId: input.turnId } : {},
@@ -39828,7 +40524,7 @@ const make$3 = Effect.gen(function* () {
39828
40524
  const existingPlan = findProposedPlanById(input.threadProposedPlans, input.planId);
39829
40525
  yield* orchestrationEngine.dispatch({
39830
40526
  type: "thread.proposed-plan.upsert",
39831
- commandId: providerCommandId(input.event, "proposed-plan-upsert"),
40527
+ commandId: providerCommandId(input.event, "proposed-plan-upsert", input.planId),
39832
40528
  threadId: input.threadId,
39833
40529
  proposedPlan: {
39834
40530
  id: input.planId,
@@ -39895,13 +40591,13 @@ const make$3 = Effect.gen(function* () {
39895
40591
  if (!sameId$1(yield* getExpectedProviderTurnIdForThread(threadId), eventTurnId)) return null;
39896
40592
  return yield* getSourceProposedPlanReferenceForPendingTurnStart(threadId);
39897
40593
  });
39898
- const markSourceProposedPlanImplemented = Effect.fn("markSourceProposedPlanImplemented")(function* (sourceThreadId, sourcePlanId, implementationThreadId, implementedAt) {
40594
+ const markSourceProposedPlanImplemented = Effect.fn("markSourceProposedPlanImplemented")(function* (event, sourceThreadId, sourcePlanId, implementationThreadId, implementedAt) {
39899
40595
  const sourceThread = yield* resolveThreadDetail(sourceThreadId);
39900
40596
  const sourcePlan = sourceThread?.proposedPlans.find((entry) => entry.id === sourcePlanId);
39901
40597
  if (!sourceThread || !sourcePlan || sourcePlan.implementedAt !== null) return;
39902
40598
  yield* orchestrationEngine.dispatch({
39903
40599
  type: "thread.proposed-plan.upsert",
39904
- commandId: CommandId.make(`provider:source-proposed-plan-implemented:${implementationThreadId}:${crypto.randomUUID()}`),
40600
+ commandId: providerCommandId(event, "source-proposed-plan-implemented", `${sourceThreadId}:${sourcePlanId}:${implementationThreadId}`),
39905
40601
  threadId: sourceThread.id,
39906
40602
  proposedPlan: {
39907
40603
  ...sourcePlan,
@@ -39926,6 +40622,12 @@ const make$3 = Effect.gen(function* () {
39926
40622
  const activeTurnId = thread.session?.activeTurnId ?? null;
39927
40623
  const conflictsWithActiveTurn = activeTurnId !== null && eventTurnId !== void 0 && !sameId$1(activeTurnId, eventTurnId);
39928
40624
  const missingTurnForActiveTurn = activeTurnId !== null && eventTurnId === void 0;
40625
+ const existingEventTurn = event.type === "turn.started" && eventTurnId !== void 0 ? yield* projectionTurnRepository.getByTurnId({
40626
+ threadId: thread.id,
40627
+ turnId: eventTurnId
40628
+ }) : Option.none();
40629
+ const eventTurnAlreadyTerminal = Option.isSome(existingEventTurn) && isTerminalProjectionTurnState(existingEventTurn.value.state);
40630
+ const eventTurnAlreadyProjectedWithoutActiveSession = activeTurnId === null && Option.isSome(existingEventTurn);
39929
40631
  if (!isAssistantTextDeltaEvent(event)) yield* flushLiveAssistantDeltaBuffersSafely({ commandTag: "assistant-delta-flush-before-runtime-event" });
39930
40632
  yield* rememberSubagentProviderThreadIds(thread.id, event);
39931
40633
  const eventProviderThreadId = rawPayloadThreadId(event);
@@ -39936,8 +40638,9 @@ const make$3 = Effect.gen(function* () {
39936
40638
  case "session.exited": return true;
39937
40639
  case "session.started":
39938
40640
  case "thread.started": return true;
39939
- case "turn.started": return !conflictsWithActiveTurn;
40641
+ case "turn.started": return !conflictsWithActiveTurn && !eventTurnAlreadyTerminal && !eventTurnAlreadyProjectedWithoutActiveSession;
39940
40642
  case "turn.completed":
40643
+ case "turn.aborted":
39941
40644
  if (conflictsWithActiveTurn || missingTurnForActiveTurn) return false;
39942
40645
  if (activeTurnId !== null && eventTurnId !== void 0) return sameId$1(activeTurnId, eventTurnId);
39943
40646
  return true;
@@ -39945,21 +40648,22 @@ const make$3 = Effect.gen(function* () {
39945
40648
  }
39946
40649
  })();
39947
40650
  const acceptedTurnStartedSourcePlan = event.type === "turn.started" && shouldApplyThreadLifecycle ? yield* getSourceProposedPlanReferenceForAcceptedTurnStart(thread.id, eventTurnId) : null;
39948
- if (event.type === "session.started" || event.type === "session.state.changed" || event.type === "session.exited" || event.type === "thread.started" || event.type === "turn.started" || event.type === "turn.completed") {
39949
- const nextActiveTurnId = event.type === "turn.started" ? eventTurnId ?? null : event.type === "turn.completed" || event.type === "session.exited" ? null : activeTurnId;
40651
+ if (event.type === "session.started" || event.type === "session.state.changed" || event.type === "session.exited" || event.type === "thread.started" || event.type === "turn.started" || event.type === "turn.completed" || event.type === "turn.aborted") {
40652
+ const nextActiveTurnId = event.type === "turn.started" ? eventTurnId ?? null : event.type === "turn.completed" || event.type === "turn.aborted" || event.type === "session.exited" ? null : activeTurnId;
39950
40653
  const status = (() => {
39951
40654
  switch (event.type) {
39952
40655
  case "session.state.changed": return orchestrationSessionStatusFromRuntimeState(event.payload.state);
39953
40656
  case "turn.started": return "running";
39954
40657
  case "session.exited": return "stopped";
39955
40658
  case "turn.completed": return normalizeRuntimeTurnState(event.payload.state) === "failed" ? "error" : "ready";
40659
+ case "turn.aborted": return "ready";
39956
40660
  case "session.started":
39957
40661
  case "thread.started": return activeTurnId !== null ? "running" : "ready";
39958
40662
  }
39959
40663
  })();
39960
40664
  const lastError = event.type === "session.state.changed" && event.payload.state === "error" ? event.payload.reason ?? thread.session?.lastError ?? "Provider session error" : event.type === "turn.completed" && normalizeRuntimeTurnState(event.payload.state) === "failed" ? event.payload.errorMessage ?? thread.session?.lastError ?? "Turn failed" : status === "ready" ? null : thread.session?.lastError ?? null;
39961
40665
  if (shouldApplyThreadLifecycle) {
39962
- if (event.type === "turn.started" && acceptedTurnStartedSourcePlan !== null) yield* markSourceProposedPlanImplemented(acceptedTurnStartedSourcePlan.sourceThreadId, acceptedTurnStartedSourcePlan.sourcePlanId, thread.id, now).pipe(Effect.catchCause((cause) => Effect.logWarning("provider runtime ingestion failed to mark source proposed plan", {
40666
+ if (event.type === "turn.started" && acceptedTurnStartedSourcePlan !== null) yield* markSourceProposedPlanImplemented(event, acceptedTurnStartedSourcePlan.sourceThreadId, acceptedTurnStartedSourcePlan.sourcePlanId, thread.id, now).pipe(Effect.catchCause((cause) => Effect.logWarning("provider runtime ingestion failed to mark source proposed plan", {
39963
40667
  eventId: event.eventId,
39964
40668
  eventType: event.type,
39965
40669
  cause: Cause.pretty(cause)
@@ -39981,11 +40685,30 @@ const make$3 = Effect.gen(function* () {
39981
40685
  },
39982
40686
  createdAt: now
39983
40687
  });
40688
+ if (event.type === "turn.aborted" && eventTurnId !== void 0) yield* orchestrationEngine.dispatch({
40689
+ type: "thread.turn.interrupt",
40690
+ commandId: providerCommandId(event, "thread-turn-interrupt", String(eventTurnId)),
40691
+ threadId: thread.id,
40692
+ turnId: eventTurnId,
40693
+ createdAt: now
40694
+ });
39984
40695
  }
39985
40696
  }
39986
40697
  const assistantDelta = isAssistantTextDeltaEvent(event) ? event.payload.delta : void 0;
40698
+ const subagentDelta = event.type === "subagent.message.delta" ? event.payload.delta : void 0;
39987
40699
  const proposedPlanDelta = event.type === "turn.proposed.delta" ? event.payload.delta : void 0;
39988
- if (assistantDelta && assistantDelta.length > 0 && isSubagentProviderThread && eventProviderThreadId) yield* appendSubagentMessageDelta({
40700
+ if (event.type === "subagent.message.delta" && subagentDelta && subagentDelta.length > 0) {
40701
+ const subagentPayload = event.payload;
40702
+ yield* appendSubagentMessageDelta({
40703
+ event,
40704
+ threadId: thread.id,
40705
+ subagentId: String(subagentPayload.subagentId),
40706
+ providerThreadId: subagentPayload.providerThreadId ?? String(subagentPayload.subagentId),
40707
+ providerItemId: subagentPayload.providerMessageId ?? String(subagentPayload.subagentId),
40708
+ delta: subagentDelta,
40709
+ createdAt: now
40710
+ });
40711
+ } else if (assistantDelta && assistantDelta.length > 0 && isSubagentProviderThread && eventProviderThreadId) yield* appendSubagentMessageDelta({
39989
40712
  event,
39990
40713
  threadId: thread.id,
39991
40714
  providerThreadId: eventProviderThreadId,
@@ -40005,7 +40728,7 @@ const make$3 = Effect.gen(function* () {
40005
40728
  const spillChunk = yield* appendBufferedAssistantText(assistantMessageId, assistantDelta);
40006
40729
  if (spillChunk.length > 0) yield* orchestrationEngine.dispatch({
40007
40730
  type: "thread.message.assistant.delta",
40008
- commandId: providerCommandId(event, "assistant-delta-buffer-spill"),
40731
+ commandId: providerCommandId(event, "assistant-delta-buffer-spill", String(assistantMessageId)),
40009
40732
  threadId: thread.id,
40010
40733
  messageId: assistantMessageId,
40011
40734
  delta: spillChunk,
@@ -40090,6 +40813,26 @@ const make$3 = Effect.gen(function* () {
40090
40813
  ...subagentMessageCompletion.fallbackText !== void 0 ? { fallbackText: subagentMessageCompletion.fallbackText } : {},
40091
40814
  createdAt: now
40092
40815
  });
40816
+ if (event.type === "subagent.completed") {
40817
+ const subagentId = String(event.payload.subagent.subagentId);
40818
+ const providerThreadId = event.payload.subagent.providerThreadId ?? subagentId;
40819
+ const providerItemIds = bufferedSubagentProviderItemIds({
40820
+ threadId: thread.id,
40821
+ providerThreadId
40822
+ });
40823
+ yield* Effect.forEach(providerItemIds.length > 0 ? providerItemIds : [subagentId], (providerItemId) => completeSubagentMessage({
40824
+ event,
40825
+ threadId: thread.id,
40826
+ subagentId,
40827
+ providerThreadId,
40828
+ providerItemId,
40829
+ ...event.payload.summary !== void 0 ? { fallbackText: event.payload.summary } : {},
40830
+ createdAt: now
40831
+ }), {
40832
+ concurrency: 1,
40833
+ discard: true
40834
+ });
40835
+ }
40093
40836
  if (proposedPlanCompletion) {
40094
40837
  const detailedThread = yield* getLoadedThreadDetail();
40095
40838
  yield* finalizeBufferedProposedPlan({
@@ -40102,7 +40845,7 @@ const make$3 = Effect.gen(function* () {
40102
40845
  updatedAt: now
40103
40846
  });
40104
40847
  }
40105
- if (event.type === "turn.completed") {
40848
+ if (event.type === "turn.completed" || event.type === "turn.aborted") {
40106
40849
  const detailedThread = yield* getLoadedThreadDetail();
40107
40850
  const messages = detailedThread?.messages ?? [];
40108
40851
  const proposedPlans = detailedThread?.proposedPlans ?? [];
@@ -40172,7 +40915,7 @@ const make$3 = Effect.gen(function* () {
40172
40915
  const assistantMessageId = MessageId.make(`assistant:${event.itemId ?? event.turnId ?? event.eventId}`);
40173
40916
  yield* orchestrationEngine.dispatch({
40174
40917
  type: "thread.turn.diff.complete",
40175
- commandId: providerCommandId(event, "thread-turn-diff-complete"),
40918
+ commandId: providerCommandId(event, "thread-turn-diff-complete", String(turnId)),
40176
40919
  threadId: thread.id,
40177
40920
  turnId,
40178
40921
  completedAt: now,
@@ -40188,7 +40931,7 @@ const make$3 = Effect.gen(function* () {
40188
40931
  const activities = runtimeEventToActivities(event);
40189
40932
  yield* Effect.forEach(activities, (activity) => orchestrationEngine.dispatch({
40190
40933
  type: "thread.activity.append",
40191
- commandId: providerCommandId(event, "thread-activity-append"),
40934
+ commandId: providerCommandId(event, "thread-activity-append", String(activity.id)),
40192
40935
  threadId: thread.id,
40193
40936
  activity,
40194
40937
  createdAt: activity.createdAt
@@ -40252,6 +40995,7 @@ function mapProviderSessionStatusToOrchestrationStatus(status) {
40252
40995
  }
40253
40996
  const turnStartKeyForEvent = (event) => event.commandId !== null ? `command:${event.commandId}` : `event:${event.eventId}`;
40254
40997
  const serverCommandId$1 = (tag) => CommandId.make(`server:${tag}:${crypto.randomUUID()}`);
40998
+ const isProviderOriginatedCommandId = (commandId) => commandId !== null && String(commandId).startsWith("provider:");
40255
40999
  const HANDLED_TURN_START_KEY_MAX = 1e4;
40256
41000
  const HANDLED_TURN_START_KEY_TTL = Duration.minutes(30);
40257
41001
  const DEFAULT_RUNTIME_MODE = "full-access";
@@ -40603,6 +41347,17 @@ const make$2 = Effect.gen(function* () {
40603
41347
  if (yield* hasHandledTurnStartRecently(turnStartKeyForEvent(event))) return;
40604
41348
  const thread = yield* resolveThread(event.payload.threadId);
40605
41349
  if (!thread) return;
41350
+ if (thread.session?.status === "running" && thread.session.activeTurnId !== null) {
41351
+ yield* appendProviderFailureActivity({
41352
+ threadId: event.payload.threadId,
41353
+ kind: "provider.turn.start.failed",
41354
+ summary: "Provider turn start rejected",
41355
+ detail: `Thread already has active turn '${thread.session.activeTurnId}'. Queuing overlapping turns is not supported; wait for the active turn to finish before starting another.`,
41356
+ turnId: null,
41357
+ createdAt: event.payload.createdAt
41358
+ });
41359
+ return;
41360
+ }
40606
41361
  const message = thread.messages.find((entry) => entry.id === event.payload.messageId);
40607
41362
  if (!message || message.role !== "user") {
40608
41363
  yield* appendProviderFailureActivity({
@@ -40673,6 +41428,7 @@ const make$2 = Effect.gen(function* () {
40673
41428
  yield* providerService.sendTurn(sendTurnRequest.value).pipe(Effect.catchCause(recoverTurnStartFailure), Effect.forkScoped);
40674
41429
  });
40675
41430
  const processTurnInterruptRequested = Effect.fn("processTurnInterruptRequested")(function* (event) {
41431
+ if (isProviderOriginatedCommandId(event.commandId)) return;
40676
41432
  const thread = yield* resolveThread(event.payload.threadId);
40677
41433
  if (!thread) return;
40678
41434
  if (!(thread.session && thread.session.status !== "stopped")) return yield* appendProviderFailureActivity({
@@ -46969,6 +47725,10 @@ const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand")(funct
46969
47725
  command,
46970
47726
  threadId: command.threadId
46971
47727
  });
47728
+ if (targetThread.session?.status === "running" && targetThread.session.activeTurnId !== null) return yield* new OrchestrationCommandInvariantError({
47729
+ commandType: command.type,
47730
+ detail: `Thread '${command.threadId}' already has active turn '${targetThread.session.activeTurnId}' and cannot start another turn until it finishes.`
47731
+ });
46972
47732
  const sourceProposedPlan = command.sourceProposedPlan;
46973
47733
  const sourceThread = sourceProposedPlan ? yield* requireThread({
46974
47734
  readModel,
@@ -50926,7 +51686,7 @@ const OrchestrationProjectionSnapshotQueryLive = Layer.effect(ProjectionSnapshot
50926
51686
  //#region src/orchestration/runtimeLayer.ts
50927
51687
  const OrchestrationEventInfrastructureLayerLive = Layer.mergeAll(OrchestrationEventStoreLive, OrchestrationCommandReceiptRepositoryLive);
50928
51688
  const OrchestrationProjectionPipelineLayerLive = OrchestrationProjectionPipelineLive.pipe(Layer.provide(OrchestrationEventStoreLive));
50929
- const OrchestrationInfrastructureLayerLive = Layer.mergeAll(OrchestrationProjectionSnapshotQueryLive, OrchestrationEventInfrastructureLayerLive, OrchestrationProjectionPipelineLayerLive);
51689
+ const OrchestrationInfrastructureLayerLive = Layer.mergeAll(OrchestrationProjectionSnapshotQueryLive, StatisticsQueryLive, OrchestrationEventInfrastructureLayerLive, OrchestrationProjectionPipelineLayerLive);
50930
51690
  const OrchestrationLayerLive = Layer.mergeAll(OrchestrationInfrastructureLayerLive, OrchestrationEngineLive.pipe(Layer.provide(OrchestrationInfrastructureLayerLive)));
50931
51691
  //#endregion
50932
51692
  //#region src/serverRuntimeState.ts
@@ -51702,4 +52462,4 @@ const CliRuntimeLayer = Layer$1.mergeAll(NodeServices.layer, NetService.layer);
51702
52462
  const program = Command.run(cli, { version }).pipe(Effect$1.scoped, Effect$1.provide(CliRuntimeLayer));
51703
52463
  NodeRuntime.runMain(program);
51704
52464
  //#endregion
51705
- export { ServerRequest__CommandExecutionRequestApprovalParams as $, makeProviderMaintenanceCapabilities as $t, nonEmptyTrimmed as A, V2ThreadStatusChangedNotification as At, codexContinuationIdentity as B, GitLabCli as Bt, DEFAULT_TIMEOUT_MS as C, V2ThreadNameUpdatedNotification as Ct, collectStreamAsString as D, V2ThreadRealtimeOutputAudioDeltaNotification as Dt, buildServerProvider as E, V2ThreadRealtimeItemAddedNotification as Et, ProviderAdapterRequestError as F, V2TurnStartParams as Ft, layerChildProcess as G, withoutStatusCheckRollupJsonField as Gt, resolveCodexHomeLayout as H, GitHubCli as Ht, ProviderAdapterSessionClosedError as I, V2TurnStartParams__CollaborationMode as It, CodexAppServerRequestError as J, BitbucketApi as Jt, CodexAppServerProcessExitedError as K, decodeGitHubPullRequestListJson as Kt, ProviderAdapterSessionNotFoundError as L, V2TurnStartResponse as Lt, providerModelsFromSettings as M, V2TurnCompletedNotification as Mt, spawnAndCollect as N, V2TurnDiffUpdatedNotification as Nt, detailFromResult as O, V2ThreadRealtimeStartedNotification as Ot, ProviderAdapterProcessError as P, V2TurnPlanUpdatedNotification as Pt, ServerRequest__ApplyPatchApprovalParams as Q, makePackageManagedProviderMaintenanceResolver as Qt, ProviderAdapterValidationError as R, V2WindowsSandboxSetupCompletedNotification as Rt, makePendingCodexProvider as S, V2ServerRequestResolvedNotification as St, buildSelectOptionDescriptor as T, V2ThreadRealtimeErrorNotification as Tt, expandHomePath$3 as U, formatGitHubJsonFields as Ut, materializeCodexShadowHome as V, GITHUB_PULL_REQUEST_LIST_JSON_FIELDS as Vt, CodexAppServerClient as W, isStatusCheckRollupAccessError as Wt, CodexAppServerTransportError as X, enrichProviderSnapshotWithVersionAdvisory as Xt, CodexAppServerSpawnError as Y, AzureDevOpsCli as Yt, SERVER_NOTIFICATION_METHODS as Z, makeManualOnlyProviderMaintenanceCapabilities as Zt, buildTokenReductionInstructions as _, V2McpToolCallProgressNotification as _t, OpenCodeRuntime as a, resolveCommandPath as an, ToolRequestUserInputResponse as at, buildCodexInitializeParams as b, V2ReasoningSummaryTextDeltaNotification as bt, openCodeQuestionId as c, getModelSelectionBooleanOptionValue as cn, V2AgentMessageDeltaNotification as ct, runOpenCodeSdk as d, getProviderOptionCurrentValue as dn, V2DeprecationNoticeNotification as dt, makeStaticProviderMaintenanceResolver as en, ServerRequest__DynamicToolCallParams as et, toOpenCodeFileParts as f, getProviderOptionDescriptors as fn, V2ErrorNotification as ft, makeEventNdjsonLogger as g, V2McpServerOauthLoginCompletedNotification as gt, ProviderEventLoggers as h, resolvePromptInjectedEffort as hn, V2ItemStartedNotification as ht, PtySpawnError as i, resolveAttachmentPath as in, ToolRequestUserInputParams as it, parseGenericCliVersion as j, V2ThreadTokenUsageUpdatedNotification as jt, isCommandMissingCause as k, V2ThreadStartedNotification as kt, openCodeRuntimeErrorDetail as l, getModelSelectionStringOptionValue as ln, V2CommandExecutionOutputDeltaNotification as lt, toOpenCodeQuestionAnswers as m, normalizeModelSlug as mn, V2ItemCompletedNotification as mt, ignoreProviderBackgroundCause as n, resolveProviderMaintenanceCapabilitiesEffect as nn, ServerRequest__FileChangeRequestApprovalParams as nt, OpenCodeRuntimeError as o, applyClaudePromptEffortPrefix as on, V2AccountRateLimitsUpdatedNotification as ot, toOpenCodePermissionReply as p, getProviderOptionStringSelectionValue as pn, V2FileChangeOutputDeltaNotification as pt, CodexAppServerProtocolParseError as q, ForgejoApi as qt, PtyAdapter as r, compareCliVersions as rn, ServerRequest__ToolRequestUserInputParams as rt, buildOpenCodePermissionRules as s, createModelCapabilities as sn, V2AccountUpdatedNotification as st, makeServerQueueMetrics as t, normalizeCommandPath as tn, ServerRequest__ExecCommandApprovalParams as tt, parseOpenCodeModelSlug as u, getProviderOptionBooleanSelectionValue as un, V2ConfigWarningNotification as ut, checkRtkAvailability as v, V2ModelReroutedNotification as vt, buildBooleanOptionDescriptor as w, V2ThreadRealtimeClosedNotification as wt, checkCodexProviderStatus as x, V2ReasoningTextDeltaNotification as xt, mergeProviderInstanceEnvironment as y, V2PlanDeltaNotification as yt, ProviderDriverError as z, V2WindowsWorldWritableWarningNotification as zt };
52465
+ export { ServerRequest__CommandExecutionRequestApprovalParams as $, makeProviderMaintenanceCapabilities as $t, nonEmptyTrimmed as A, V2ThreadStatusChangedNotification as At, codexContinuationIdentity as B, GitLabCli as Bt, DEFAULT_TIMEOUT_MS as C, V2ThreadNameUpdatedNotification as Ct, collectStreamAsString as D, V2ThreadRealtimeOutputAudioDeltaNotification as Dt, buildServerProvider as E, V2ThreadRealtimeItemAddedNotification as Et, ProviderAdapterRequestError as F, V2TurnStartParams as Ft, layerChildProcess as G, withoutStatusCheckRollupJsonField as Gt, resolveCodexHomeLayout as H, GitHubCli as Ht, ProviderAdapterSessionClosedError as I, V2TurnStartParams__CollaborationMode as It, CodexAppServerRequestError as J, BitbucketApi as Jt, CodexAppServerProcessExitedError as K, decodeGitHubPullRequestListJson as Kt, ProviderAdapterSessionNotFoundError as L, V2TurnStartResponse as Lt, providerModelsFromSettings as M, V2TurnCompletedNotification as Mt, spawnAndCollect as N, V2TurnDiffUpdatedNotification as Nt, detailFromResult as O, V2ThreadRealtimeStartedNotification as Ot, ProviderAdapterProcessError as P, V2TurnPlanUpdatedNotification as Pt, ServerRequest__ApplyPatchApprovalParams as Q, makePackageManagedProviderMaintenanceResolver as Qt, ProviderAdapterValidationError as R, V2WindowsSandboxSetupCompletedNotification as Rt, makePendingCodexProvider as S, V2ServerRequestResolvedNotification as St, buildSelectOptionDescriptor as T, V2ThreadRealtimeErrorNotification as Tt, expandHomePath$3 as U, formatGitHubJsonFields as Ut, materializeCodexShadowHome as V, GITHUB_PULL_REQUEST_LIST_JSON_FIELDS as Vt, CodexAppServerClient as W, isStatusCheckRollupAccessError as Wt, CodexAppServerTransportError as X, enrichProviderSnapshotWithVersionAdvisory as Xt, CodexAppServerSpawnError as Y, AzureDevOpsCli as Yt, SERVER_NOTIFICATION_METHODS as Z, makeManualOnlyProviderMaintenanceCapabilities as Zt, buildTokenReductionInstructions as _, V2McpToolCallProgressNotification as _t, OpenCodeRuntime as a, resolveAttachmentPath as an, ToolRequestUserInputResponse as at, buildCodexInitializeParams as b, V2ReasoningSummaryTextDeltaNotification as bt, openCodeQuestionId as c, createModelCapabilities as cn, V2AgentMessageDeltaNotification as ct, runOpenCodeSdk as d, getProviderOptionBooleanSelectionValue as dn, V2DeprecationNoticeNotification as dt, makeStaticProviderMaintenanceResolver as en, ServerRequest__DynamicToolCallParams as et, toOpenCodeFileParts as f, getProviderOptionCurrentValue as fn, V2ErrorNotification as ft, makeEventNdjsonLogger as g, resolvePromptInjectedEffort as gn, V2McpServerOauthLoginCompletedNotification as gt, ProviderEventLoggers as h, normalizeModelSlug as hn, V2ItemStartedNotification as ht, PtySpawnError as i, ServerSettingsService as in, ToolRequestUserInputParams as it, parseGenericCliVersion as j, V2ThreadTokenUsageUpdatedNotification as jt, isCommandMissingCause as k, V2ThreadStartedNotification as kt, openCodeRuntimeErrorDetail as l, getModelSelectionBooleanOptionValue as ln, V2CommandExecutionOutputDeltaNotification as lt, toOpenCodeQuestionAnswers as m, getProviderOptionStringSelectionValue as mn, V2ItemCompletedNotification as mt, ignoreProviderBackgroundCause as n, resolveProviderMaintenanceCapabilitiesEffect as nn, ServerRequest__FileChangeRequestApprovalParams as nt, OpenCodeRuntimeError as o, resolveCommandPath as on, V2AccountRateLimitsUpdatedNotification as ot, toOpenCodePermissionReply as p, getProviderOptionDescriptors as pn, V2FileChangeOutputDeltaNotification as pt, CodexAppServerProtocolParseError as q, ForgejoApi as qt, PtyAdapter as r, compareCliVersions as rn, ServerRequest__ToolRequestUserInputParams as rt, buildOpenCodePermissionRules as s, applyClaudePromptEffortPrefix as sn, V2AccountUpdatedNotification as st, makeServerQueueMetrics as t, normalizeCommandPath as tn, ServerRequest__ExecCommandApprovalParams as tt, parseOpenCodeModelSlug as u, getModelSelectionStringOptionValue as un, V2ConfigWarningNotification as ut, checkRtkAvailability as v, V2ModelReroutedNotification as vt, buildBooleanOptionDescriptor as w, V2ThreadRealtimeClosedNotification as wt, checkCodexProviderStatus as x, V2ReasoningTextDeltaNotification as xt, mergeProviderInstanceEnvironment as y, V2PlanDeltaNotification as yt, ProviderDriverError as z, V2WindowsWorldWritableWarningNotification as zt };