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.
- package/dist/{AzureDevOpsSourceControlProvider-6holYS_D.cjs → AzureDevOpsSourceControlProvider-5exivY-1.cjs} +2 -2
- package/dist/{AzureDevOpsSourceControlProvider-CC2_COxP.mjs → AzureDevOpsSourceControlProvider-CF5LuCHp.mjs} +2 -2
- package/dist/{BitbucketSourceControlProvider-a0IsNFyG.cjs → BitbucketSourceControlProvider-1GWENqcl.cjs} +2 -2
- package/dist/{BitbucketSourceControlProvider-CYR_BD1d.mjs → BitbucketSourceControlProvider-CKH09tfT.mjs} +2 -2
- package/dist/{ClaudeDriver-C6tQNEWO.cjs → ClaudeDriver-BXLdjrht.cjs} +177 -4
- package/dist/{ClaudeDriver-D3nsxwH9.mjs → ClaudeDriver-WwWFTu61.mjs} +178 -5
- package/dist/{CodexDriver-BILrJG8o.mjs → CodexDriver-93-TmCrO.mjs} +6 -5
- package/dist/{CodexDriver-ms_YgFD7.cjs → CodexDriver-BboMT9uk.cjs} +5 -4
- package/dist/{CodexTextGeneration-CHEgoANm.cjs → CodexTextGeneration-0pRbJji3.cjs} +2 -2
- package/dist/{CodexTextGeneration-BIKHl7E3.mjs → CodexTextGeneration-BU9Myn87.mjs} +3 -3
- package/dist/{CopilotDriver-CmD3Ffyl.mjs → CopilotDriver-BASi8pJ0.mjs} +4 -4
- package/dist/{CopilotDriver-B0--ZwIK.cjs → CopilotDriver-DCsv-17W.cjs} +3 -3
- package/dist/{CursorDriver-DTVPXZ-R.cjs → CursorDriver-BTSiM3A8.cjs} +161 -14
- package/dist/{CursorDriver-CbeaIbdb.mjs → CursorDriver-D5LvIqUk.mjs} +162 -15
- package/dist/{ForgejoSourceControlProvider-DwAog76b.cjs → ForgejoSourceControlProvider-BTXRDCGB.cjs} +2 -2
- package/dist/{ForgejoSourceControlProvider-DX6d9gvz.mjs → ForgejoSourceControlProvider-e-4hvvZ_.mjs} +2 -2
- package/dist/{GitHubSourceControlProvider-C-LGwho3.mjs → GitHubSourceControlProvider-26IofDAO.mjs} +2 -2
- package/dist/{GitHubSourceControlProvider-9lJFzjsu.cjs → GitHubSourceControlProvider-DWmwkA_y.cjs} +2 -2
- package/dist/{GitLabSourceControlProvider-CvKA74lg.cjs → GitLabSourceControlProvider-D-YHnxRe.cjs} +2 -2
- package/dist/{GitLabSourceControlProvider-CkeT2aEx.mjs → GitLabSourceControlProvider-DePct78W.mjs} +2 -2
- package/dist/{OpenCodeDriver-ClWtCk0j.mjs → OpenCodeDriver-BhvLOmvn.mjs} +325 -38
- package/dist/{OpenCodeDriver-CXUsnl5o.cjs → OpenCodeDriver-CVeZ4n9-.cjs} +324 -37
- package/dist/{SourceControlProviderDiscoveryCatalog-_rg0mc1o.cjs → SourceControlProviderDiscoveryCatalog-DeFR5xH3.cjs} +1 -64
- package/dist/{SourceControlProviderDiscoveryCatalog-yMDer_Yh.mjs → SourceControlProviderDiscoveryCatalog-mJV_Xitr.mjs} +3 -48
- package/dist/bin.cjs +1280 -519
- package/dist/bin.mjs +1234 -474
- package/dist/client/assets/{AnimatedHeight-DgItDSis.js → AnimatedHeight-BSU0lzYs.js} +1 -1
- package/dist/client/assets/AppearanceSettings-D7q0ujGK.js +1 -0
- package/dist/client/assets/{BranchToolbar.logic-C_xHEt9C.js → BranchToolbar.logic-CZIFSvhd.js} +1 -1
- package/dist/client/assets/ChatRightPanel-CWHOIuiQ.js +188 -0
- package/dist/client/assets/{ChatThreadRouteView-CV6ETYG5.js → ChatThreadRouteView-bA7xWXzc.js} +1 -1
- package/dist/client/assets/{CommandPaletteDialog-C_H7R8S5.js → CommandPaletteDialog-DNYaVOZO.js} +1 -1
- package/dist/client/assets/CompositeRoot-B_KEfCUE.js +1 -0
- package/dist/client/assets/ConnectionsSettings-CLZPbx_K.js +1 -0
- package/dist/client/assets/{DiagnosticsSettings-B340S_mq.js → DiagnosticsSettings-DtzPCb6N.js} +1 -1
- package/dist/client/assets/{DialogHandle-BJY7cHCV.js → DialogHandle-DuHnmWoE.js} +1 -1
- package/dist/client/assets/{DialogRoot-Ej1FVk-_.js → DialogRoot-BV25qAcA.js} +1 -1
- package/dist/client/assets/DialogTitle-DQsi-RTa.js +1 -0
- package/dist/client/assets/DialogTrigger-D0fA01C6.js +1 -0
- package/dist/client/assets/{DialogViewport-DvjAl76K.js → DialogViewport-CMV_BePU.js} +1 -1
- package/dist/client/assets/{DraftChatThreadRouteView-pOkyeKPS.js → DraftChatThreadRouteView-BoiKnrii.js} +1 -1
- package/dist/client/assets/{JetBrainsIcons-DTTF47I0.js → JetBrainsIcons-BcPxJlMf.js} +1 -1
- package/dist/client/assets/{KeybindingsSettings-CW3RRi-7.js → KeybindingsSettings-LuI98pdF.js} +1 -1
- package/dist/client/assets/McpServersSettings-BFMuWYVV.js +6 -0
- package/dist/client/assets/{NoActiveThreadState-DVHwrkCp.js → NoActiveThreadState-C2q_O1kP.js} +1 -1
- package/dist/client/assets/{OpinionatedPluginsSettings-Cjj23Fs4.js → OpinionatedPluginsSettings-Bqwct37O.js} +1 -1
- package/dist/client/assets/{ProjectFavicon-TDP7HRfn.js → ProjectFavicon-D2imiJ8M.js} +1 -1
- package/dist/client/assets/{ProviderUpdateLaunchNotification.logic-6TpFsmiI.js → ProviderUpdateLaunchNotification.logic-CJgA--nK.js} +1 -1
- package/dist/client/assets/ProvidersSettingsPanel-B97vbeu6.js +1 -0
- package/dist/client/assets/{RedactedSensitiveText-BfoVjPsE.js → RedactedSensitiveText-B2GFTyfq.js} +1 -1
- package/dist/client/assets/RootAppShell-C1xTR98P.js +12 -0
- package/dist/client/assets/SettingsDialog-Q0Q8O5oH.js +2 -0
- package/dist/client/assets/SourceControlSettings-KAvoPTNi.js +1 -0
- package/dist/client/assets/StatisticsPanel-BzsQ444K.js +64 -0
- package/dist/client/assets/{ThreadStatusIndicators-B0leIJGD.js → ThreadStatusIndicators-Cw_jLVQf.js} +1 -1
- package/dist/client/assets/{ThreadTerminalDrawer-COq2Fk17.js → ThreadTerminalDrawer-D1WnSemH.js} +17 -17
- package/dist/client/assets/ThreadWorkspacePanel-L4qCPTOA.js +166 -0
- package/dist/client/assets/{alert-dialog-lMfKpG2t.js → alert-dialog-CNmKa0BK.js} +1 -1
- package/dist/client/assets/chart-column-BWSKYZ_a.js +1 -0
- package/dist/client/assets/{chatThreadActions-PPyTj_x0.js → chatThreadActions-TtDsiwDC.js} +1 -1
- package/dist/client/assets/chevron-up-zopJ_99l.js +1 -0
- package/dist/client/assets/{clamp-JiD4IZ0Z.js → clamp-Ds6WJu8j.js} +1 -1
- package/dist/client/assets/{clipboard-copy-CYBLSG2q.js → clipboard-copy-BoJGpdmJ.js} +1 -1
- package/dist/client/assets/clock-CzUHThzk.js +1 -0
- package/dist/client/assets/{commandPaletteStore-uVfCD7zE.js → commandPaletteStore-KebG835b.js} +1 -1
- package/dist/client/assets/composerDraftStore-DpPEQ6BN.js +21 -0
- package/dist/client/assets/{desktopUpdateAtoms-X6uM5SoD.js → desktopUpdateAtoms-BQ0GGEfM.js} +1 -1
- package/dist/client/assets/{download-DLBlpp4h.js → download-CUiRE0N9.js} +1 -1
- package/dist/client/assets/{draft-input-dLlVMl5P.js → draft-input-CwpGDtoT.js} +1 -1
- package/dist/client/assets/editorPreferences-jN7DKbyt.js +1 -0
- package/dist/client/assets/{empty-DlLY-Hhj.js → empty-CBuXePtg.js} +1 -1
- package/dist/client/assets/{group-zDBPF7rR.js → group-BpZvxjG5.js} +1 -1
- package/dist/client/assets/{index-Dq8sT2lF.js → index-BKzXTNJ_.js} +2 -2
- package/dist/client/assets/{input-B9-RWT56.js → input-CgDawd6k.js} +1 -1
- package/dist/client/assets/kbd-QYSL97CK.js +1 -0
- package/dist/client/assets/{keybindings-Dx4Nc1vY.js → keybindings-CUTRYI_A.js} +1 -1
- package/dist/client/assets/{keyboard-DDTWQkr0.js → keyboard-DFFiI7JY.js} +1 -1
- package/dist/client/assets/{keyedQuery-Ds4OGhX2.js → keyedQuery-DiOCbGH0.js} +0 -0
- package/dist/client/assets/{main-DxfpmoKJ.js → main-BgFGju3e.js} +3 -3
- package/dist/client/assets/main-D0UFdwts.css +2 -0
- package/dist/client/assets/{palette-BQcz-ZYV.js → palette-BXCL909c.js} +1 -1
- package/dist/client/assets/{play-QloDGe4R.js → play-DI2LZohg.js} +1 -1
- package/dist/client/assets/plus-DzgIfHUF.js +1 -0
- package/dist/client/assets/projectAtoms-DXXpuERK.js +1 -0
- package/dist/client/assets/providerDriverMeta-CRNNp0q3.js +1 -0
- package/dist/client/assets/providerIconUtils-D-DFhem2.js +47 -0
- package/dist/client/assets/radio-group-_PPYg3YY.js +1 -0
- package/dist/client/assets/{refresh-cw-DkBMGllm.js → refresh-cw-BsQTNBXl.js} +1 -1
- package/dist/client/assets/{resolveAriaLabelledBy-DDfIbj05.js → resolveAriaLabelledBy-CRHo_s16.js} +1 -1
- package/dist/client/assets/{rightPanelRouteSearch-DfuWVvXN.js → rightPanelRouteSearch-CfmZ7osj.js} +1 -1
- package/dist/client/assets/{scale-BActunFu.js → scale-DDEJ-tvn.js} +1 -1
- package/dist/client/assets/{scroll-area-D-YOUG02.js → scroll-area-HgsI-ErG.js} +1 -1
- package/dist/client/assets/{separator-TInKeIDo.js → separator-ClnL4mUB.js} +1 -1
- package/dist/client/assets/{server-BtEG3NAw.js → server-Bbs3L-6_.js} +1 -1
- package/dist/client/assets/{session-logic-DNf1aXq_.js → session-logic-CKQkgIwo.js} +1 -1
- package/dist/client/assets/settingsDialogStore-SG-W1q0A.js +1 -0
- package/dist/client/assets/{settingsLayout-D22Mm0u3.js → settingsLayout-G5xVm-ZT.js} +1 -1
- package/dist/client/assets/sidebar-_u7SGgmC.js +1 -0
- package/dist/client/assets/sidebarStatusText-BTYnwflG.js +1 -0
- package/dist/client/assets/{skeleton-DWaac_qp.js → skeleton-CmUvhZGP.js} +1 -1
- package/dist/client/assets/{storeSelectors-Cx1IYPA4.js → storeSelectors-DhJRpdiw.js} +1 -1
- package/dist/client/assets/threadSelectionStore-ygmA4DNA.js +1 -0
- package/dist/client/assets/toast-DmA_ziPT.js +1 -0
- package/dist/client/assets/toggle-DGS7tKuj.js +1 -0
- package/dist/client/assets/{toggle-group-CnLjaHSL.js → toggle-group-Dtv1ZUFW.js} +1 -1
- package/dist/client/assets/{tokenModePresentation-BSYdIvBm.js → tokenModePresentation-Dor1DnBx.js} +1 -1
- package/dist/client/assets/{trash-2-BI5xcbsm.js → trash-2-C2G3VGoV.js} +1 -1
- package/dist/client/assets/{triangle-alert-DJef_Uvh.js → triangle-alert-Bpz3xGu5.js} +1 -1
- package/dist/client/assets/{undo-2-DeZ2cMGS.js → undo-2-C3rtxuqZ.js} +1 -1
- package/dist/client/assets/{useHandleNewThread-XB82O6SA.js → useHandleNewThread-ypSbzG0P.js} +1 -1
- package/dist/client/assets/useLabelableId-Bc7KEnHU.js +1 -0
- package/dist/client/assets/{useNavigate-B2tgshhW.js → useNavigate-_4hWGSey.js} +1 -1
- package/dist/client/assets/useTheme-HcKmBfpF.js +1 -0
- package/dist/client/assets/{vscode-icons-DM9qFoEr.js → vscode-icons-DdSTtxYd.js} +1 -1
- package/dist/client/assets/{wrench-je4QOyG-.js → wrench-C4jdis40.js} +1 -1
- package/dist/client/assets/x-CG2WU63t.js +1 -0
- package/dist/client/index.html +1 -1
- package/dist/{collectUint8StreamText-C2z5Y8tF.mjs → collectUint8StreamText-Lv4GGI79.mjs} +269 -14
- package/dist/{collectUint8StreamText-TCG6xW_P.cjs → collectUint8StreamText-uNXVRHOf.cjs} +291 -12
- package/dist/{makeManagedServerProvider-DPFw9gV_.cjs → makeManagedServerProvider-3SD-Q5xh.cjs} +1 -1
- package/dist/{makeManagedServerProvider-BXO8QvzC.mjs → makeManagedServerProvider-CkPEptun.mjs} +1 -1
- package/package.json +1 -1
- package/dist/client/assets/AppearanceSettings-BlsMFBvJ.js +0 -1
- package/dist/client/assets/ChatRightPanel-CThudBb1.js +0 -188
- package/dist/client/assets/CompositeRoot-DjnzUIwC.js +0 -1
- package/dist/client/assets/ConnectionsSettings-hArR4Oe3.js +0 -1
- package/dist/client/assets/DialogTitle-H1yIMmA9.js +0 -1
- package/dist/client/assets/DialogTrigger-BHMq_K2G.js +0 -1
- package/dist/client/assets/McpServersSettings-dQ3BzOWY.js +0 -6
- package/dist/client/assets/ProvidersSettingsPanel-D15EeWAq.js +0 -1
- package/dist/client/assets/RootAppShell-CWBPSA2w.js +0 -12
- package/dist/client/assets/SettingsDialog-oJCE5foT.js +0 -2
- package/dist/client/assets/SourceControlSettings-CPnlMxNm.js +0 -1
- package/dist/client/assets/ThreadWorkspacePanel-qF9y6QT9.js +0 -166
- package/dist/client/assets/composerDraftStore-D12lUSfh.js +0 -21
- package/dist/client/assets/editorPreferences-BLeEBSD_.js +0 -1
- package/dist/client/assets/folder-open-DMjz0lpx.js +0 -1
- package/dist/client/assets/kbd-aeSsjiPI.js +0 -1
- package/dist/client/assets/main-C57RhHZ_.css +0 -2
- package/dist/client/assets/plus-4Oy56d-3.js +0 -1
- package/dist/client/assets/projectAtoms-DUEBb7Zz.js +0 -1
- package/dist/client/assets/providerDriverMeta-Dwi6Zqgd.js +0 -1
- package/dist/client/assets/providerIconUtils-uhWb4bdg.js +0 -47
- package/dist/client/assets/radio-group-DHyQlLeX.js +0 -1
- package/dist/client/assets/settingsDialogStore-BINi7pdD.js +0 -1
- package/dist/client/assets/sidebar-DHwNQmWp.js +0 -1
- package/dist/client/assets/threadSelectionStore-C0ig4405.js +0 -1
- package/dist/client/assets/toast-DE7a4wkW.js +0 -1
- package/dist/client/assets/toggle-BIW4AyPY.js +0 -1
- package/dist/client/assets/useLabelableId-DBAgv9qQ.js +0 -1
- package/dist/client/assets/useTheme-Dv42Z8uy.js +0 -1
- 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
|
|
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
|
-
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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.
|
|
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.
|
|
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*
|
|
32767
|
-
|
|
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.
|
|
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*
|
|
32800
|
-
|
|
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 {
|
|
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,
|
|
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(
|
|
34115
|
-
|
|
34116
|
-
|
|
34117
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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}:${
|
|
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:
|
|
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 (
|
|
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,
|
|
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 };
|