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.cjs
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
4
4
|
const require_chunk = require("./chunk-jM1PLTSZ.cjs");
|
|
5
|
-
const require_collectUint8StreamText = require("./collectUint8StreamText-
|
|
6
|
-
const require_SourceControlProviderDiscoveryCatalog = require("./SourceControlProviderDiscoveryCatalog-_rg0mc1o.cjs");
|
|
5
|
+
const require_collectUint8StreamText = require("./collectUint8StreamText-uNXVRHOf.cjs");
|
|
7
6
|
const require_Metrics = require("./Metrics-CIW1QH7M.cjs");
|
|
7
|
+
const require_SourceControlProviderDiscoveryCatalog = require("./SourceControlProviderDiscoveryCatalog-DeFR5xH3.cjs");
|
|
8
8
|
const require_sourceControl = require("./sourceControl-x2t62T8h.cjs");
|
|
9
9
|
let _effect_platform_node_NodeRuntime = require("@effect/platform-node/NodeRuntime");
|
|
10
10
|
_effect_platform_node_NodeRuntime = require_chunk.__toESM(_effect_platform_node_NodeRuntime, 1);
|
|
@@ -44,13 +44,13 @@ let effect_unstable_rpc = require("effect/unstable/rpc");
|
|
|
44
44
|
let effect_unstable_process = require("effect/unstable/process");
|
|
45
45
|
let effect_Semaphore = require("effect/Semaphore");
|
|
46
46
|
effect_Semaphore = require_chunk.__toESM(effect_Semaphore, 1);
|
|
47
|
+
let effect_Random = require("effect/Random");
|
|
48
|
+
effect_Random = require_chunk.__toESM(effect_Random, 1);
|
|
47
49
|
require("effect/PlatformError");
|
|
48
50
|
let effect_unstable_sql_SqlClient = require("effect/unstable/sql/SqlClient");
|
|
49
51
|
effect_unstable_sql_SqlClient = require_chunk.__toESM(effect_unstable_sql_SqlClient, 1);
|
|
50
52
|
let effect_unstable_sql_Migrator = require("effect/unstable/sql/Migrator");
|
|
51
53
|
effect_unstable_sql_Migrator = require_chunk.__toESM(effect_unstable_sql_Migrator, 1);
|
|
52
|
-
let effect_Random = require("effect/Random");
|
|
53
|
-
effect_Random = require_chunk.__toESM(effect_Random, 1);
|
|
54
54
|
let node_fs_promises = require("node:fs/promises");
|
|
55
55
|
node_fs_promises = require_chunk.__toESM(node_fs_promises, 1);
|
|
56
56
|
let effect_Context = require("effect/Context");
|
|
@@ -72,9 +72,9 @@ let effect_SchemaIssue = require("effect/SchemaIssue");
|
|
|
72
72
|
effect_SchemaIssue = require_chunk.__toESM(effect_SchemaIssue, 1);
|
|
73
73
|
let effect_Sink = require("effect/Sink");
|
|
74
74
|
effect_Sink = require_chunk.__toESM(effect_Sink, 1);
|
|
75
|
-
let effect_Number = require("effect/Number");
|
|
76
75
|
let effect_unstable_sql_SqlSchema = require("effect/unstable/sql/SqlSchema");
|
|
77
76
|
effect_unstable_sql_SqlSchema = require_chunk.__toESM(effect_unstable_sql_SqlSchema, 1);
|
|
77
|
+
let effect_Number = require("effect/Number");
|
|
78
78
|
let node_url = require("node:url");
|
|
79
79
|
let _pierre_diffs = require("@pierre/diffs");
|
|
80
80
|
let node_perf_hooks = require("node:perf_hooks");
|
|
@@ -336,7 +336,7 @@ function applyClaudePromptEffortPrefix(text, effort) {
|
|
|
336
336
|
}
|
|
337
337
|
//#endregion
|
|
338
338
|
//#region ../../packages/shared/src/serverSettings.ts
|
|
339
|
-
const ServerSettingsJson$1 =
|
|
339
|
+
const ServerSettingsJson$1 = require_collectUint8StreamText.fromLenientJson(require_collectUint8StreamText.ServerSettings);
|
|
340
340
|
function normalizePersistedServerSettingString(value) {
|
|
341
341
|
const trimmed = value?.trim();
|
|
342
342
|
return trimmed && trimmed.length > 0 ? trimmed : void 0;
|
|
@@ -424,7 +424,7 @@ const readBootstrapEnvelope = effect.Effect.fn("readBootstrapEnvelope")(function
|
|
|
424
424
|
})));
|
|
425
425
|
};
|
|
426
426
|
const handleLine = (line) => {
|
|
427
|
-
const parsed =
|
|
427
|
+
const parsed = require_collectUint8StreamText.decodeJsonResult(schema)(line);
|
|
428
428
|
if (effect.Result.isSuccess(parsed)) resume(effect.Effect.succeedSome(parsed.success));
|
|
429
429
|
else resume(effect.Effect.fail(new BootstrapError({
|
|
430
430
|
message: "Failed to decode bootstrap envelope.",
|
|
@@ -1657,6 +1657,388 @@ const makeProviderMaintenanceCommandCoordinator = effect.Effect.fn("makeProvider
|
|
|
1657
1657
|
return { withCommandLock };
|
|
1658
1658
|
});
|
|
1659
1659
|
//#endregion
|
|
1660
|
+
//#region src/atomicWrite.ts
|
|
1661
|
+
const writeFileStringAtomically = (input) => effect.Effect.scoped(effect.Effect.gen(function* () {
|
|
1662
|
+
const fs = yield* effect.FileSystem.FileSystem;
|
|
1663
|
+
const path = yield* effect.Path.Path;
|
|
1664
|
+
const tempFileId = yield* effect_Random.nextUUIDv4;
|
|
1665
|
+
const targetDirectory = path.dirname(input.filePath);
|
|
1666
|
+
yield* fs.makeDirectory(targetDirectory, { recursive: true });
|
|
1667
|
+
const tempDirectory = yield* fs.makeTempDirectoryScoped({
|
|
1668
|
+
directory: targetDirectory,
|
|
1669
|
+
prefix: `${path.basename(input.filePath)}.`
|
|
1670
|
+
});
|
|
1671
|
+
const tempPath = path.join(tempDirectory, `${tempFileId}.tmp`);
|
|
1672
|
+
yield* fs.writeFileString(tempPath, input.contents);
|
|
1673
|
+
yield* fs.rename(tempPath, input.filePath);
|
|
1674
|
+
}));
|
|
1675
|
+
//#endregion
|
|
1676
|
+
//#region src/auth/Services/ServerSecretStore.ts
|
|
1677
|
+
var SecretStoreError = class extends effect.Data.TaggedError("SecretStoreError") {};
|
|
1678
|
+
var ServerSecretStore = class extends effect.Context.Service()("ryco/auth/Services/ServerSecretStore") {};
|
|
1679
|
+
//#endregion
|
|
1680
|
+
//#region src/auth/Layers/ServerSecretStore.ts
|
|
1681
|
+
const makeServerSecretStore = effect.Effect.gen(function* () {
|
|
1682
|
+
const fileSystem = yield* effect.FileSystem.FileSystem;
|
|
1683
|
+
const path = yield* effect.Path.Path;
|
|
1684
|
+
const serverConfig = yield* require_Metrics.ServerConfig;
|
|
1685
|
+
yield* fileSystem.makeDirectory(serverConfig.secretsDir, { recursive: true });
|
|
1686
|
+
yield* fileSystem.chmod(serverConfig.secretsDir, 448).pipe(effect.Effect.mapError((cause) => new SecretStoreError({
|
|
1687
|
+
message: `Failed to secure secrets directory ${serverConfig.secretsDir}.`,
|
|
1688
|
+
cause
|
|
1689
|
+
})));
|
|
1690
|
+
const resolveSecretPath = (name) => path.join(serverConfig.secretsDir, `${name}.bin`);
|
|
1691
|
+
const ensureSecretDirectory = (secretPath) => {
|
|
1692
|
+
const directory = path.dirname(secretPath);
|
|
1693
|
+
return fileSystem.makeDirectory(directory, { recursive: true }).pipe(effect.Effect.flatMap(() => fileSystem.chmod(directory, 448)));
|
|
1694
|
+
};
|
|
1695
|
+
const isPlatformError = (u) => effect.Predicate.isTagged(u, "PlatformError");
|
|
1696
|
+
const get = (name) => fileSystem.readFile(resolveSecretPath(name)).pipe(effect.Effect.map((bytes) => Uint8Array.from(bytes)), effect.Effect.catch((cause) => cause.reason._tag === "NotFound" ? effect.Effect.succeed(null) : effect.Effect.fail(new SecretStoreError({
|
|
1697
|
+
message: `Failed to read secret ${name}.`,
|
|
1698
|
+
cause
|
|
1699
|
+
}))));
|
|
1700
|
+
const set = (name, value) => {
|
|
1701
|
+
const secretPath = resolveSecretPath(name);
|
|
1702
|
+
const tempPath = `${secretPath}.${node_crypto.randomUUID()}.tmp`;
|
|
1703
|
+
return effect.Effect.gen(function* () {
|
|
1704
|
+
yield* ensureSecretDirectory(secretPath);
|
|
1705
|
+
yield* fileSystem.writeFile(tempPath, value);
|
|
1706
|
+
yield* fileSystem.chmod(tempPath, 384);
|
|
1707
|
+
yield* fileSystem.rename(tempPath, secretPath);
|
|
1708
|
+
yield* fileSystem.chmod(secretPath, 384);
|
|
1709
|
+
}).pipe(effect.Effect.catch((cause) => fileSystem.remove(tempPath).pipe(effect.Effect.ignore, effect.Effect.flatMap(() => effect.Effect.fail(new SecretStoreError({
|
|
1710
|
+
message: `Failed to persist secret ${name}.`,
|
|
1711
|
+
cause
|
|
1712
|
+
}))))));
|
|
1713
|
+
};
|
|
1714
|
+
const create = (name, value) => {
|
|
1715
|
+
const secretPath = resolveSecretPath(name);
|
|
1716
|
+
return effect.Effect.scoped(effect.Effect.gen(function* () {
|
|
1717
|
+
yield* ensureSecretDirectory(secretPath);
|
|
1718
|
+
const file = yield* fileSystem.open(secretPath, {
|
|
1719
|
+
flag: "wx",
|
|
1720
|
+
mode: 384
|
|
1721
|
+
});
|
|
1722
|
+
yield* file.writeAll(value);
|
|
1723
|
+
yield* file.sync;
|
|
1724
|
+
yield* fileSystem.chmod(secretPath, 384);
|
|
1725
|
+
})).pipe(effect.Effect.mapError((cause) => new SecretStoreError({
|
|
1726
|
+
message: `Failed to persist secret ${name}.`,
|
|
1727
|
+
cause
|
|
1728
|
+
})));
|
|
1729
|
+
};
|
|
1730
|
+
const getOrCreateRandom = (name, bytes) => get(name).pipe(effect.Effect.flatMap((existing) => {
|
|
1731
|
+
if (existing) return effect.Effect.succeed(existing);
|
|
1732
|
+
const generated = node_crypto.randomBytes(bytes);
|
|
1733
|
+
return create(name, generated).pipe(effect.Effect.as(Uint8Array.from(generated)), effect.Effect.catchTag("SecretStoreError", (error) => isPlatformError(error.cause) && error.cause.reason._tag === "AlreadyExists" ? get(name).pipe(effect.Effect.flatMap((created) => created !== null ? effect.Effect.succeed(created) : effect.Effect.fail(new SecretStoreError({ message: `Failed to read secret ${name} after concurrent creation.` })))) : effect.Effect.fail(error)));
|
|
1734
|
+
}));
|
|
1735
|
+
const remove = (name) => fileSystem.remove(resolveSecretPath(name)).pipe(effect.Effect.catch((cause) => cause.reason._tag === "NotFound" ? effect.Effect.void : effect.Effect.fail(new SecretStoreError({
|
|
1736
|
+
message: `Failed to remove secret ${name}.`,
|
|
1737
|
+
cause
|
|
1738
|
+
}))));
|
|
1739
|
+
return {
|
|
1740
|
+
get,
|
|
1741
|
+
set,
|
|
1742
|
+
getOrCreateRandom,
|
|
1743
|
+
remove
|
|
1744
|
+
};
|
|
1745
|
+
});
|
|
1746
|
+
const ServerSecretStoreLive = effect.Layer.effect(ServerSecretStore, makeServerSecretStore);
|
|
1747
|
+
//#endregion
|
|
1748
|
+
//#region src/serverSettings.ts
|
|
1749
|
+
/**
|
|
1750
|
+
* ServerSettings - Server-authoritative settings service.
|
|
1751
|
+
*
|
|
1752
|
+
* Owns persistence, validation, and change notification of settings that affect
|
|
1753
|
+
* server-side behavior (binary paths, streaming mode, env mode, custom models,
|
|
1754
|
+
* text generation model selection).
|
|
1755
|
+
*
|
|
1756
|
+
* Follows the same pattern as `keybindings.ts`: JSON file + Cache + PubSub +
|
|
1757
|
+
* Semaphore + FileSystem.watch for concurrency and external edit detection.
|
|
1758
|
+
*
|
|
1759
|
+
* @module ServerSettings
|
|
1760
|
+
*/
|
|
1761
|
+
const textEncoder$2 = new TextEncoder();
|
|
1762
|
+
const textDecoder$2 = new TextDecoder();
|
|
1763
|
+
function providerEnvironmentSecretName(input) {
|
|
1764
|
+
return `provider-env-${Buffer.from(input.instanceId, "utf8").toString("base64url")}-${Buffer.from(input.name, "utf8").toString("base64url")}`;
|
|
1765
|
+
}
|
|
1766
|
+
function redactProviderEnvironmentVariable(variable) {
|
|
1767
|
+
if (!variable.sensitive) {
|
|
1768
|
+
const { valueRedacted: _omit, ...rest } = variable;
|
|
1769
|
+
return rest;
|
|
1770
|
+
}
|
|
1771
|
+
return {
|
|
1772
|
+
...variable,
|
|
1773
|
+
value: "",
|
|
1774
|
+
...variable.value.length > 0 || variable.valueRedacted ? { valueRedacted: true } : {}
|
|
1775
|
+
};
|
|
1776
|
+
}
|
|
1777
|
+
function redactServerSettingsForClient(settings) {
|
|
1778
|
+
const providerInstances = Object.fromEntries(Object.entries(settings.providerInstances).map(([instanceId, instance]) => [instanceId, instance.environment ? {
|
|
1779
|
+
...instance,
|
|
1780
|
+
environment: instance.environment.map(redactProviderEnvironmentVariable)
|
|
1781
|
+
} : instance]));
|
|
1782
|
+
return {
|
|
1783
|
+
...settings,
|
|
1784
|
+
providerInstances
|
|
1785
|
+
};
|
|
1786
|
+
}
|
|
1787
|
+
var ServerSettingsService = class ServerSettingsService extends effect.Context.Service()("ryco/serverSettings/ServerSettingsService") {
|
|
1788
|
+
static layerTest = (overrides = {}) => effect.Layer.effect(ServerSettingsService, effect.Effect.gen(function* () {
|
|
1789
|
+
const currentSettingsRef = yield* effect.Ref.make(deepMerge(require_collectUint8StreamText.DEFAULT_SERVER_SETTINGS, overrides));
|
|
1790
|
+
return {
|
|
1791
|
+
start: effect.Effect.void,
|
|
1792
|
+
ready: effect.Effect.void,
|
|
1793
|
+
getSettings: effect.Ref.get(currentSettingsRef),
|
|
1794
|
+
updateSettings: (patch) => effect.Ref.get(currentSettingsRef).pipe(effect.Effect.flatMap((currentSettings) => effect.Schema.decodeEffect(require_collectUint8StreamText.ServerSettings)(applyServerSettingsPatch(currentSettings, patch)).pipe(effect.Effect.mapError((cause) => new require_collectUint8StreamText.ServerSettingsError({
|
|
1795
|
+
settingsPath: "<memory>",
|
|
1796
|
+
detail: `failed to normalize server settings: ${effect.SchemaIssue.makeFormatterDefault()(cause.issue)}`,
|
|
1797
|
+
cause
|
|
1798
|
+
})))), effect.Effect.tap((nextSettings) => effect.Ref.set(currentSettingsRef, nextSettings))),
|
|
1799
|
+
streamChanges: effect.Stream.empty
|
|
1800
|
+
};
|
|
1801
|
+
}));
|
|
1802
|
+
};
|
|
1803
|
+
const ServerSettingsJson = require_collectUint8StreamText.fromLenientJson(require_collectUint8StreamText.ServerSettings);
|
|
1804
|
+
const getLegacyProviderSettings = (settings, provider) => settings.providers[provider];
|
|
1805
|
+
/**
|
|
1806
|
+
* Ensure the `textGenerationModelSelection` points to an enabled provider.
|
|
1807
|
+
* If the selected provider is disabled, fall back to the first enabled
|
|
1808
|
+
* provider with its default model. This is applied at read-time so the
|
|
1809
|
+
* persisted preference is preserved for when a provider is re-enabled.
|
|
1810
|
+
*/
|
|
1811
|
+
function resolveTextGenerationProvider(settings) {
|
|
1812
|
+
const selection = settings.textGenerationModelSelection;
|
|
1813
|
+
const instanceConfig = settings.providerInstances[selection.instanceId];
|
|
1814
|
+
if (instanceConfig !== void 0) return instanceConfig.enabled ?? true ? settings : fallbackTextGenerationProvider(settings);
|
|
1815
|
+
if (require_collectUint8StreamText.isProviderDriverKind(selection.instanceId) && getLegacyProviderSettings(settings, selection.instanceId)?.enabled) return settings;
|
|
1816
|
+
return fallbackTextGenerationProvider(settings);
|
|
1817
|
+
}
|
|
1818
|
+
function fallbackTextGenerationProvider(settings) {
|
|
1819
|
+
const fallbackEntry = Object.entries(settings.providers).find(([, provider]) => provider.enabled);
|
|
1820
|
+
const fallback = fallbackEntry ? require_collectUint8StreamText.ProviderDriverKind.make(fallbackEntry[0]) : void 0;
|
|
1821
|
+
if (!fallback) return settings;
|
|
1822
|
+
return {
|
|
1823
|
+
...settings,
|
|
1824
|
+
textGenerationModelSelection: {
|
|
1825
|
+
instanceId: require_collectUint8StreamText.ProviderInstanceId.make(fallback),
|
|
1826
|
+
model: require_collectUint8StreamText.DEFAULT_GIT_TEXT_GENERATION_MODEL_BY_PROVIDER[fallback] ?? "gpt-5.4-mini"
|
|
1827
|
+
}
|
|
1828
|
+
};
|
|
1829
|
+
}
|
|
1830
|
+
const ATOMIC_SETTINGS_KEYS = new Set(["textGenerationModelSelection"]);
|
|
1831
|
+
function stripDefaultServerSettings(current, defaults) {
|
|
1832
|
+
if (Array.isArray(current) || Array.isArray(defaults)) return effect.Equal.equals(current, defaults) ? void 0 : current;
|
|
1833
|
+
if (current !== null && defaults !== null && typeof current === "object" && typeof defaults === "object") {
|
|
1834
|
+
const currentRecord = current;
|
|
1835
|
+
const defaultsRecord = defaults;
|
|
1836
|
+
const next = {};
|
|
1837
|
+
for (const key of Object.keys(currentRecord)) if (ATOMIC_SETTINGS_KEYS.has(key)) {
|
|
1838
|
+
if (!effect.Equal.equals(currentRecord[key], defaultsRecord[key])) next[key] = currentRecord[key];
|
|
1839
|
+
} else {
|
|
1840
|
+
const stripped = stripDefaultServerSettings(currentRecord[key], defaultsRecord[key]);
|
|
1841
|
+
if (stripped !== void 0) next[key] = stripped;
|
|
1842
|
+
}
|
|
1843
|
+
return Object.keys(next).length > 0 ? next : void 0;
|
|
1844
|
+
}
|
|
1845
|
+
return Object.is(current, defaults) ? void 0 : current;
|
|
1846
|
+
}
|
|
1847
|
+
const makeServerSettings = effect.Effect.gen(function* () {
|
|
1848
|
+
const { settingsPath } = yield* require_Metrics.ServerConfig;
|
|
1849
|
+
const fs = yield* effect.FileSystem.FileSystem;
|
|
1850
|
+
const pathService = yield* effect.Path.Path;
|
|
1851
|
+
const secretStore = yield* ServerSecretStore;
|
|
1852
|
+
const writeSemaphore = yield* effect_Semaphore.make(1);
|
|
1853
|
+
const cacheKey = "settings";
|
|
1854
|
+
const changesPubSub = yield* effect.PubSub.unbounded();
|
|
1855
|
+
const startedRef = yield* effect.Ref.make(false);
|
|
1856
|
+
const startedDeferred = yield* effect.Deferred.make();
|
|
1857
|
+
const watcherScope = yield* effect.Scope.make("sequential");
|
|
1858
|
+
yield* effect.Effect.addFinalizer(() => effect.Scope.close(watcherScope, effect.Exit.void));
|
|
1859
|
+
const emitChange = (settings) => effect.PubSub.publish(changesPubSub, settings).pipe(effect.Effect.asVoid);
|
|
1860
|
+
const readConfigExists = fs.exists(settingsPath).pipe(effect.Effect.mapError((cause) => new require_collectUint8StreamText.ServerSettingsError({
|
|
1861
|
+
settingsPath,
|
|
1862
|
+
detail: "failed to check settings file existence",
|
|
1863
|
+
cause
|
|
1864
|
+
})));
|
|
1865
|
+
const readRawConfig = fs.readFileString(settingsPath).pipe(effect.Effect.mapError((cause) => new require_collectUint8StreamText.ServerSettingsError({
|
|
1866
|
+
settingsPath,
|
|
1867
|
+
detail: "failed to read settings file",
|
|
1868
|
+
cause
|
|
1869
|
+
})));
|
|
1870
|
+
const loadSettingsFromDisk = effect.Effect.gen(function* () {
|
|
1871
|
+
if (!(yield* readConfigExists)) return require_collectUint8StreamText.DEFAULT_SERVER_SETTINGS;
|
|
1872
|
+
const raw = yield* readRawConfig;
|
|
1873
|
+
const decoded = effect.Schema.decodeUnknownExit(ServerSettingsJson)(raw);
|
|
1874
|
+
if (decoded._tag === "Failure") {
|
|
1875
|
+
yield* effect.Effect.logWarning("failed to parse settings.json, using defaults", {
|
|
1876
|
+
path: settingsPath,
|
|
1877
|
+
issues: effect.Cause.pretty(decoded.cause)
|
|
1878
|
+
});
|
|
1879
|
+
return require_collectUint8StreamText.DEFAULT_SERVER_SETTINGS;
|
|
1880
|
+
}
|
|
1881
|
+
return decoded.value;
|
|
1882
|
+
});
|
|
1883
|
+
const settingsCache = yield* effect.Cache.make({
|
|
1884
|
+
capacity: 1,
|
|
1885
|
+
lookup: () => loadSettingsFromDisk
|
|
1886
|
+
});
|
|
1887
|
+
const getSettingsFromCache = effect.Cache.get(settingsCache, cacheKey);
|
|
1888
|
+
const toSettingsError = (detail, cause) => new require_collectUint8StreamText.ServerSettingsError({
|
|
1889
|
+
settingsPath,
|
|
1890
|
+
detail,
|
|
1891
|
+
cause
|
|
1892
|
+
});
|
|
1893
|
+
const materializeProviderEnvironmentSecrets = (settings) => effect.Effect.gen(function* () {
|
|
1894
|
+
const providerInstances = { ...settings.providerInstances };
|
|
1895
|
+
for (const [instanceId, instance] of Object.entries(settings.providerInstances)) {
|
|
1896
|
+
if (!instance.environment) continue;
|
|
1897
|
+
const environment = [];
|
|
1898
|
+
for (const variable of instance.environment) {
|
|
1899
|
+
if (!variable.sensitive || !variable.valueRedacted) {
|
|
1900
|
+
environment.push(variable);
|
|
1901
|
+
continue;
|
|
1902
|
+
}
|
|
1903
|
+
const secret = yield* secretStore.get(providerEnvironmentSecretName({
|
|
1904
|
+
instanceId,
|
|
1905
|
+
name: variable.name
|
|
1906
|
+
})).pipe(effect.Effect.mapError((cause) => toSettingsError(`failed to read sensitive environment variable ${variable.name}`, cause)));
|
|
1907
|
+
environment.push({
|
|
1908
|
+
...variable,
|
|
1909
|
+
value: secret ? textDecoder$2.decode(secret) : ""
|
|
1910
|
+
});
|
|
1911
|
+
}
|
|
1912
|
+
providerInstances[instanceId] = {
|
|
1913
|
+
...instance,
|
|
1914
|
+
environment
|
|
1915
|
+
};
|
|
1916
|
+
}
|
|
1917
|
+
return {
|
|
1918
|
+
...settings,
|
|
1919
|
+
providerInstances
|
|
1920
|
+
};
|
|
1921
|
+
});
|
|
1922
|
+
const persistProviderEnvironmentSecrets = (current, next) => effect.Effect.gen(function* () {
|
|
1923
|
+
const providerInstances = { ...next.providerInstances };
|
|
1924
|
+
const nextSecretKeys = /* @__PURE__ */ new Set();
|
|
1925
|
+
for (const [instanceId, instance] of Object.entries(next.providerInstances)) {
|
|
1926
|
+
if (!instance.environment) continue;
|
|
1927
|
+
const environment = [];
|
|
1928
|
+
for (const variable of instance.environment) {
|
|
1929
|
+
const secretName = providerEnvironmentSecretName({
|
|
1930
|
+
instanceId,
|
|
1931
|
+
name: variable.name
|
|
1932
|
+
});
|
|
1933
|
+
if (!variable.sensitive) {
|
|
1934
|
+
yield* secretStore.remove(secretName).pipe(effect.Effect.mapError((cause) => toSettingsError(`failed to remove environment secret ${variable.name}`, cause)));
|
|
1935
|
+
environment.push(redactProviderEnvironmentVariable(variable));
|
|
1936
|
+
continue;
|
|
1937
|
+
}
|
|
1938
|
+
nextSecretKeys.add(secretName);
|
|
1939
|
+
if (!variable.valueRedacted) {
|
|
1940
|
+
if (variable.value.length > 0) {
|
|
1941
|
+
yield* secretStore.set(secretName, textEncoder$2.encode(variable.value)).pipe(effect.Effect.mapError((cause) => toSettingsError(`failed to persist environment secret ${variable.name}`, cause)));
|
|
1942
|
+
environment.push({
|
|
1943
|
+
...variable,
|
|
1944
|
+
value: "",
|
|
1945
|
+
valueRedacted: true
|
|
1946
|
+
});
|
|
1947
|
+
} else {
|
|
1948
|
+
yield* secretStore.remove(secretName).pipe(effect.Effect.mapError((cause) => toSettingsError(`failed to remove environment secret ${variable.name}`, cause)));
|
|
1949
|
+
const { valueRedacted: _omit, ...rest } = variable;
|
|
1950
|
+
environment.push(rest);
|
|
1951
|
+
}
|
|
1952
|
+
continue;
|
|
1953
|
+
}
|
|
1954
|
+
environment.push(redactProviderEnvironmentVariable(variable));
|
|
1955
|
+
}
|
|
1956
|
+
providerInstances[instanceId] = {
|
|
1957
|
+
...instance,
|
|
1958
|
+
environment
|
|
1959
|
+
};
|
|
1960
|
+
}
|
|
1961
|
+
for (const [instanceId, instance] of Object.entries(current.providerInstances)) for (const variable of instance.environment ?? []) {
|
|
1962
|
+
if (!variable.sensitive) continue;
|
|
1963
|
+
const secretName = providerEnvironmentSecretName({
|
|
1964
|
+
instanceId,
|
|
1965
|
+
name: variable.name
|
|
1966
|
+
});
|
|
1967
|
+
if (nextSecretKeys.has(secretName)) continue;
|
|
1968
|
+
yield* secretStore.remove(secretName).pipe(effect.Effect.mapError((cause) => toSettingsError(`failed to remove stale environment secret ${variable.name}`, cause)));
|
|
1969
|
+
}
|
|
1970
|
+
return {
|
|
1971
|
+
...next,
|
|
1972
|
+
providerInstances
|
|
1973
|
+
};
|
|
1974
|
+
});
|
|
1975
|
+
const writeSettingsAtomically = (settings) => {
|
|
1976
|
+
const sparseSettings = stripDefaultServerSettings(settings, require_collectUint8StreamText.DEFAULT_SERVER_SETTINGS) ?? {};
|
|
1977
|
+
return writeFileStringAtomically({
|
|
1978
|
+
filePath: settingsPath,
|
|
1979
|
+
contents: `${JSON.stringify(sparseSettings, null, 2)}\n`
|
|
1980
|
+
}).pipe(effect.Effect.provideService(effect.FileSystem.FileSystem, fs), effect.Effect.provideService(effect.Path.Path, pathService), effect.Effect.mapError((cause) => new require_collectUint8StreamText.ServerSettingsError({
|
|
1981
|
+
settingsPath,
|
|
1982
|
+
detail: "failed to write settings file",
|
|
1983
|
+
cause
|
|
1984
|
+
})));
|
|
1985
|
+
};
|
|
1986
|
+
const revalidateAndEmit = writeSemaphore.withPermits(1)(effect.Effect.gen(function* () {
|
|
1987
|
+
yield* effect.Cache.invalidate(settingsCache, cacheKey);
|
|
1988
|
+
yield* emitChange(yield* getSettingsFromCache);
|
|
1989
|
+
}));
|
|
1990
|
+
const startWatcher = effect.Effect.gen(function* () {
|
|
1991
|
+
const settingsDir = pathService.dirname(settingsPath);
|
|
1992
|
+
const settingsFile = pathService.basename(settingsPath);
|
|
1993
|
+
const settingsPathResolved = pathService.resolve(settingsPath);
|
|
1994
|
+
yield* fs.makeDirectory(settingsDir, { recursive: true }).pipe(effect.Effect.mapError((cause) => new require_collectUint8StreamText.ServerSettingsError({
|
|
1995
|
+
settingsPath,
|
|
1996
|
+
detail: "failed to prepare settings directory",
|
|
1997
|
+
cause
|
|
1998
|
+
})));
|
|
1999
|
+
const revalidateAndEmitSafely = revalidateAndEmit.pipe(effect.Effect.ignoreCause({ log: true }));
|
|
2000
|
+
const debouncedSettingsEvents = fs.watch(settingsDir).pipe(effect.Stream.filter((event) => {
|
|
2001
|
+
return event.path === settingsFile || event.path === settingsPath || pathService.resolve(settingsDir, event.path) === settingsPathResolved;
|
|
2002
|
+
}), effect.Stream.debounce(effect.Duration.millis(100)));
|
|
2003
|
+
yield* effect.Stream.runForEach(debouncedSettingsEvents, () => revalidateAndEmitSafely).pipe(effect.Effect.ignoreCause({ log: true }), effect.Effect.forkIn(watcherScope), effect.Effect.asVoid);
|
|
2004
|
+
});
|
|
2005
|
+
return {
|
|
2006
|
+
start: effect.Effect.gen(function* () {
|
|
2007
|
+
if (!(yield* effect.Ref.modify(startedRef, (started) => [!started, true]))) return yield* effect.Deferred.await(startedDeferred);
|
|
2008
|
+
const startup = effect.Effect.gen(function* () {
|
|
2009
|
+
yield* startWatcher;
|
|
2010
|
+
yield* effect.Cache.invalidate(settingsCache, cacheKey);
|
|
2011
|
+
yield* getSettingsFromCache;
|
|
2012
|
+
});
|
|
2013
|
+
const startupExit = yield* effect.Effect.exit(startup);
|
|
2014
|
+
if (startupExit._tag === "Failure") {
|
|
2015
|
+
yield* effect.Deferred.failCause(startedDeferred, startupExit.cause).pipe(effect.Effect.orDie);
|
|
2016
|
+
return yield* effect.Effect.failCause(startupExit.cause);
|
|
2017
|
+
}
|
|
2018
|
+
yield* effect.Deferred.succeed(startedDeferred, void 0).pipe(effect.Effect.orDie);
|
|
2019
|
+
}),
|
|
2020
|
+
ready: effect.Deferred.await(startedDeferred),
|
|
2021
|
+
getSettings: getSettingsFromCache.pipe(effect.Effect.flatMap(materializeProviderEnvironmentSecrets), effect.Effect.map(resolveTextGenerationProvider)),
|
|
2022
|
+
updateSettings: (patch) => writeSemaphore.withPermits(1)(effect.Effect.gen(function* () {
|
|
2023
|
+
const current = yield* getSettingsFromCache;
|
|
2024
|
+
const nextPersisted = yield* persistProviderEnvironmentSecrets(current, applyServerSettingsPatch(current, patch));
|
|
2025
|
+
const next = yield* effect.Schema.decodeEffect(require_collectUint8StreamText.ServerSettings)(nextPersisted).pipe(effect.Effect.mapError((cause) => new require_collectUint8StreamText.ServerSettingsError({
|
|
2026
|
+
settingsPath: "<memory>",
|
|
2027
|
+
detail: `failed to normalize server settings: ${effect.SchemaIssue.makeFormatterDefault()(cause.issue)}`,
|
|
2028
|
+
cause
|
|
2029
|
+
})));
|
|
2030
|
+
yield* writeSettingsAtomically(next);
|
|
2031
|
+
yield* effect.Cache.set(settingsCache, cacheKey, next);
|
|
2032
|
+
yield* emitChange(next);
|
|
2033
|
+
return resolveTextGenerationProvider(yield* materializeProviderEnvironmentSecrets(next));
|
|
2034
|
+
})),
|
|
2035
|
+
get streamChanges() {
|
|
2036
|
+
return effect.Stream.fromPubSub(changesPubSub).pipe(effect.Stream.mapEffect((settings) => materializeProviderEnvironmentSecrets(settings).pipe(effect.Effect.catch((error) => effect.Effect.logWarning("failed to materialize provider environment secrets", { detail: error.detail }).pipe(effect.Effect.as(settings))))), effect.Stream.map(resolveTextGenerationProvider));
|
|
2037
|
+
}
|
|
2038
|
+
};
|
|
2039
|
+
});
|
|
2040
|
+
const ServerSettingsLive = effect.Layer.effect(ServerSettingsService, makeServerSettings).pipe(effect.Layer.provide(ServerSecretStoreLive));
|
|
2041
|
+
//#endregion
|
|
1660
2042
|
//#region src/provider/cliVersion.ts
|
|
1661
2043
|
const CLI_VERSION_NUMBER_SEGMENT = /^\d+$/;
|
|
1662
2044
|
function normalizeCliVersion(version) {
|
|
@@ -1957,7 +2339,8 @@ const resolveLatestProviderVersion = effect.Effect.fn("resolveLatestProviderVers
|
|
|
1957
2339
|
});
|
|
1958
2340
|
const enrichProviderSnapshotWithVersionAdvisory = effect.Effect.fn("enrichProviderSnapshotWithVersionAdvisory")(function* (snapshot, maintenanceCapabilities) {
|
|
1959
2341
|
const capabilities = maintenanceCapabilities ?? makeManualProviderMaintenanceCapabilities$1(snapshot.driver);
|
|
1960
|
-
|
|
2342
|
+
const { enableProviderUpdateChecks } = yield* (yield* ServerSettingsService).getSettings.pipe(effect.Effect.orElseSucceed(() => require_collectUint8StreamText.DEFAULT_SERVER_SETTINGS));
|
|
2343
|
+
if (!enableProviderUpdateChecks || !snapshot.enabled || !snapshot.installed || !snapshot.version) return {
|
|
1961
2344
|
...snapshot,
|
|
1962
2345
|
versionAdvisory: createProviderVersionAdvisory({
|
|
1963
2346
|
driver: snapshot.driver,
|
|
@@ -2052,6 +2435,7 @@ const make$21 = effect.Effect.fn("ProviderMaintenanceRunner.make")(function* ()
|
|
|
2052
2435
|
const providerRegistry = yield* ProviderRegistry;
|
|
2053
2436
|
const spawner = yield* effect_unstable_process.ChildProcessSpawner.ChildProcessSpawner;
|
|
2054
2437
|
const httpClient = yield* effect_unstable_http.HttpClient.HttpClient;
|
|
2438
|
+
const serverSettings = yield* ServerSettingsService;
|
|
2055
2439
|
const runMaintenanceCommand = (command, args) => runProviderMaintenanceCommandWithSpawner({
|
|
2056
2440
|
spawner,
|
|
2057
2441
|
command,
|
|
@@ -2070,7 +2454,7 @@ const make$21 = effect.Effect.fn("ProviderMaintenanceRunner.make")(function* ()
|
|
|
2070
2454
|
providers,
|
|
2071
2455
|
verifiedProviders: []
|
|
2072
2456
|
});
|
|
2073
|
-
return effect.Effect.forEach(refreshedProviders, (refreshedProvider) => enrichProviderSnapshotWithVersionAdvisory(refreshedProvider, maintenanceCapabilities).pipe(effect.Effect.provideService(effect_unstable_http.HttpClient.HttpClient, httpClient)), { concurrency: "unbounded" }).pipe(effect.Effect.map((verifiedProviders) => ({
|
|
2457
|
+
return effect.Effect.forEach(refreshedProviders, (refreshedProvider) => enrichProviderSnapshotWithVersionAdvisory(refreshedProvider, maintenanceCapabilities).pipe(effect.Effect.provideService(effect_unstable_http.HttpClient.HttpClient, httpClient), effect.Effect.provideService(ServerSettingsService, serverSettings)), { concurrency: "unbounded" }).pipe(effect.Effect.map((verifiedProviders) => ({
|
|
2074
2458
|
providers,
|
|
2075
2459
|
verifiedProviders
|
|
2076
2460
|
})), effect.Effect.catchCause((cause) => effect.Effect.logWarning("Provider post-update version verification failed", {
|
|
@@ -2160,78 +2544,6 @@ const make$21 = effect.Effect.fn("ProviderMaintenanceRunner.make")(function* ()
|
|
|
2160
2544
|
});
|
|
2161
2545
|
const layer$18 = effect.Layer.effect(ProviderMaintenanceRunner, make$21());
|
|
2162
2546
|
//#endregion
|
|
2163
|
-
//#region src/auth/Services/ServerSecretStore.ts
|
|
2164
|
-
var SecretStoreError = class extends effect.Data.TaggedError("SecretStoreError") {};
|
|
2165
|
-
var ServerSecretStore = class extends effect.Context.Service()("ryco/auth/Services/ServerSecretStore") {};
|
|
2166
|
-
//#endregion
|
|
2167
|
-
//#region src/auth/Layers/ServerSecretStore.ts
|
|
2168
|
-
const makeServerSecretStore = effect.Effect.gen(function* () {
|
|
2169
|
-
const fileSystem = yield* effect.FileSystem.FileSystem;
|
|
2170
|
-
const path = yield* effect.Path.Path;
|
|
2171
|
-
const serverConfig = yield* require_Metrics.ServerConfig;
|
|
2172
|
-
yield* fileSystem.makeDirectory(serverConfig.secretsDir, { recursive: true });
|
|
2173
|
-
yield* fileSystem.chmod(serverConfig.secretsDir, 448).pipe(effect.Effect.mapError((cause) => new SecretStoreError({
|
|
2174
|
-
message: `Failed to secure secrets directory ${serverConfig.secretsDir}.`,
|
|
2175
|
-
cause
|
|
2176
|
-
})));
|
|
2177
|
-
const resolveSecretPath = (name) => path.join(serverConfig.secretsDir, `${name}.bin`);
|
|
2178
|
-
const ensureSecretDirectory = (secretPath) => {
|
|
2179
|
-
const directory = path.dirname(secretPath);
|
|
2180
|
-
return fileSystem.makeDirectory(directory, { recursive: true }).pipe(effect.Effect.flatMap(() => fileSystem.chmod(directory, 448)));
|
|
2181
|
-
};
|
|
2182
|
-
const isPlatformError = (u) => effect.Predicate.isTagged(u, "PlatformError");
|
|
2183
|
-
const get = (name) => fileSystem.readFile(resolveSecretPath(name)).pipe(effect.Effect.map((bytes) => Uint8Array.from(bytes)), effect.Effect.catch((cause) => cause.reason._tag === "NotFound" ? effect.Effect.succeed(null) : effect.Effect.fail(new SecretStoreError({
|
|
2184
|
-
message: `Failed to read secret ${name}.`,
|
|
2185
|
-
cause
|
|
2186
|
-
}))));
|
|
2187
|
-
const set = (name, value) => {
|
|
2188
|
-
const secretPath = resolveSecretPath(name);
|
|
2189
|
-
const tempPath = `${secretPath}.${node_crypto.randomUUID()}.tmp`;
|
|
2190
|
-
return effect.Effect.gen(function* () {
|
|
2191
|
-
yield* ensureSecretDirectory(secretPath);
|
|
2192
|
-
yield* fileSystem.writeFile(tempPath, value);
|
|
2193
|
-
yield* fileSystem.chmod(tempPath, 384);
|
|
2194
|
-
yield* fileSystem.rename(tempPath, secretPath);
|
|
2195
|
-
yield* fileSystem.chmod(secretPath, 384);
|
|
2196
|
-
}).pipe(effect.Effect.catch((cause) => fileSystem.remove(tempPath).pipe(effect.Effect.ignore, effect.Effect.flatMap(() => effect.Effect.fail(new SecretStoreError({
|
|
2197
|
-
message: `Failed to persist secret ${name}.`,
|
|
2198
|
-
cause
|
|
2199
|
-
}))))));
|
|
2200
|
-
};
|
|
2201
|
-
const create = (name, value) => {
|
|
2202
|
-
const secretPath = resolveSecretPath(name);
|
|
2203
|
-
return effect.Effect.scoped(effect.Effect.gen(function* () {
|
|
2204
|
-
yield* ensureSecretDirectory(secretPath);
|
|
2205
|
-
const file = yield* fileSystem.open(secretPath, {
|
|
2206
|
-
flag: "wx",
|
|
2207
|
-
mode: 384
|
|
2208
|
-
});
|
|
2209
|
-
yield* file.writeAll(value);
|
|
2210
|
-
yield* file.sync;
|
|
2211
|
-
yield* fileSystem.chmod(secretPath, 384);
|
|
2212
|
-
})).pipe(effect.Effect.mapError((cause) => new SecretStoreError({
|
|
2213
|
-
message: `Failed to persist secret ${name}.`,
|
|
2214
|
-
cause
|
|
2215
|
-
})));
|
|
2216
|
-
};
|
|
2217
|
-
const getOrCreateRandom = (name, bytes) => get(name).pipe(effect.Effect.flatMap((existing) => {
|
|
2218
|
-
if (existing) return effect.Effect.succeed(existing);
|
|
2219
|
-
const generated = node_crypto.randomBytes(bytes);
|
|
2220
|
-
return create(name, generated).pipe(effect.Effect.as(Uint8Array.from(generated)), effect.Effect.catchTag("SecretStoreError", (error) => isPlatformError(error.cause) && error.cause.reason._tag === "AlreadyExists" ? get(name).pipe(effect.Effect.flatMap((created) => created !== null ? effect.Effect.succeed(created) : effect.Effect.fail(new SecretStoreError({ message: `Failed to read secret ${name} after concurrent creation.` })))) : effect.Effect.fail(error)));
|
|
2221
|
-
}));
|
|
2222
|
-
const remove = (name) => fileSystem.remove(resolveSecretPath(name)).pipe(effect.Effect.catch((cause) => cause.reason._tag === "NotFound" ? effect.Effect.void : effect.Effect.fail(new SecretStoreError({
|
|
2223
|
-
message: `Failed to remove secret ${name}.`,
|
|
2224
|
-
cause
|
|
2225
|
-
}))));
|
|
2226
|
-
return {
|
|
2227
|
-
get,
|
|
2228
|
-
set,
|
|
2229
|
-
getOrCreateRandom,
|
|
2230
|
-
remove
|
|
2231
|
-
};
|
|
2232
|
-
});
|
|
2233
|
-
const ServerSecretStoreLive = effect.Layer.effect(ServerSecretStore, makeServerSecretStore);
|
|
2234
|
-
//#endregion
|
|
2235
2547
|
//#region src/persistence/Errors.ts
|
|
2236
2548
|
var PersistenceSqlError = class extends effect.Schema.TaggedErrorClass()("PersistenceSqlError", {
|
|
2237
2549
|
operation: effect.Schema.String,
|
|
@@ -3925,6 +4237,35 @@ var _040_ProjectionThreadsProjectUpdatedAtIndex_default = effect_Effect.gen(func
|
|
|
3925
4237
|
`;
|
|
3926
4238
|
});
|
|
3927
4239
|
//#endregion
|
|
4240
|
+
//#region src/persistence/Migrations/041_ProjectionThreadsSubagentNesting.ts
|
|
4241
|
+
var _041_ProjectionThreadsSubagentNesting_default = effect_Effect.gen(function* () {
|
|
4242
|
+
const sql = yield* effect_unstable_sql_SqlClient.SqlClient;
|
|
4243
|
+
const columns = yield* sql`
|
|
4244
|
+
PRAGMA table_info(projection_threads)
|
|
4245
|
+
`;
|
|
4246
|
+
const columnNames = new Set(columns.map((column) => column.name));
|
|
4247
|
+
if (!columnNames.has("thread_kind")) yield* sql`
|
|
4248
|
+
ALTER TABLE projection_threads
|
|
4249
|
+
ADD COLUMN thread_kind TEXT NOT NULL DEFAULT 'normal'
|
|
4250
|
+
`;
|
|
4251
|
+
if (!columnNames.has("visibility")) yield* sql`
|
|
4252
|
+
ALTER TABLE projection_threads
|
|
4253
|
+
ADD COLUMN visibility TEXT NOT NULL DEFAULT 'normal'
|
|
4254
|
+
`;
|
|
4255
|
+
if (!columnNames.has("parent_thread_id")) yield* sql`
|
|
4256
|
+
ALTER TABLE projection_threads
|
|
4257
|
+
ADD COLUMN parent_thread_id TEXT
|
|
4258
|
+
`;
|
|
4259
|
+
if (!columnNames.has("parent_subagent_id")) yield* sql`
|
|
4260
|
+
ALTER TABLE projection_threads
|
|
4261
|
+
ADD COLUMN parent_subagent_id TEXT
|
|
4262
|
+
`;
|
|
4263
|
+
yield* sql`
|
|
4264
|
+
CREATE INDEX IF NOT EXISTS idx_projection_threads_parent_thread
|
|
4265
|
+
ON projection_threads(parent_thread_id, created_at, thread_id)
|
|
4266
|
+
`;
|
|
4267
|
+
});
|
|
4268
|
+
//#endregion
|
|
3928
4269
|
//#region src/persistence/Migrations.ts
|
|
3929
4270
|
/**
|
|
3930
4271
|
* MigrationsLive - Migration runner with inline loader
|
|
@@ -4145,6 +4486,11 @@ const migrationEntries = [
|
|
|
4145
4486
|
40,
|
|
4146
4487
|
"ProjectionThreadsProjectUpdatedAtIndex",
|
|
4147
4488
|
_040_ProjectionThreadsProjectUpdatedAtIndex_default
|
|
4489
|
+
],
|
|
4490
|
+
[
|
|
4491
|
+
41,
|
|
4492
|
+
"ProjectionThreadsSubagentNesting",
|
|
4493
|
+
_041_ProjectionThreadsSubagentNesting_default
|
|
4148
4494
|
]
|
|
4149
4495
|
];
|
|
4150
4496
|
const makeMigrationLoader = (throughId) => effect_unstable_sql_Migrator.fromRecord(Object.fromEntries(migrationEntries.filter(([id]) => throughId === void 0 || id <= throughId).map(([id, name, migration]) => [`${id}_${name}`, migration])));
|
|
@@ -4214,6 +4560,45 @@ const repairProjectionTokenModeColumns = effect_Effect.fn("repairProjectionToken
|
|
|
4214
4560
|
yield* effect_Effect.log("Repaired projection_thread_sessions.token_mode column");
|
|
4215
4561
|
}
|
|
4216
4562
|
});
|
|
4563
|
+
const repairProjectionThreadSubagentNestingColumns = effect_Effect.fn("repairProjectionThreadSubagentNestingColumns")(function* () {
|
|
4564
|
+
const sql = yield* effect_unstable_sql_SqlClient.SqlClient;
|
|
4565
|
+
if ((yield* sql`
|
|
4566
|
+
SELECT name FROM sqlite_master
|
|
4567
|
+
WHERE type = 'table' AND name = 'projection_threads'
|
|
4568
|
+
`).length === 0) return;
|
|
4569
|
+
const columns = yield* sql`
|
|
4570
|
+
PRAGMA table_info(projection_threads)
|
|
4571
|
+
`;
|
|
4572
|
+
const columnNames = new Set(columns.map((column) => column.name));
|
|
4573
|
+
if (!columnNames.has("thread_kind")) {
|
|
4574
|
+
yield* sql`
|
|
4575
|
+
ALTER TABLE projection_threads
|
|
4576
|
+
ADD COLUMN thread_kind TEXT NOT NULL DEFAULT 'normal'
|
|
4577
|
+
`;
|
|
4578
|
+
yield* effect_Effect.log("Repaired projection_threads.thread_kind column");
|
|
4579
|
+
}
|
|
4580
|
+
if (!columnNames.has("visibility")) {
|
|
4581
|
+
yield* sql`
|
|
4582
|
+
ALTER TABLE projection_threads
|
|
4583
|
+
ADD COLUMN visibility TEXT NOT NULL DEFAULT 'normal'
|
|
4584
|
+
`;
|
|
4585
|
+
yield* effect_Effect.log("Repaired projection_threads.visibility column");
|
|
4586
|
+
}
|
|
4587
|
+
if (!columnNames.has("parent_thread_id")) {
|
|
4588
|
+
yield* sql`
|
|
4589
|
+
ALTER TABLE projection_threads
|
|
4590
|
+
ADD COLUMN parent_thread_id TEXT
|
|
4591
|
+
`;
|
|
4592
|
+
yield* effect_Effect.log("Repaired projection_threads.parent_thread_id column");
|
|
4593
|
+
}
|
|
4594
|
+
if (!columnNames.has("parent_subagent_id")) {
|
|
4595
|
+
yield* sql`
|
|
4596
|
+
ALTER TABLE projection_threads
|
|
4597
|
+
ADD COLUMN parent_subagent_id TEXT
|
|
4598
|
+
`;
|
|
4599
|
+
yield* effect_Effect.log("Repaired projection_threads.parent_subagent_id column");
|
|
4600
|
+
}
|
|
4601
|
+
});
|
|
4217
4602
|
/**
|
|
4218
4603
|
* Run all pending migrations.
|
|
4219
4604
|
*
|
|
@@ -4230,6 +4615,7 @@ const runMigrations = effect_Effect.fn("runMigrations")(function* ({ toMigration
|
|
|
4230
4615
|
if (toMigrationInclusive === void 0 || toMigrationInclusive >= 31) yield* repairProjectionWorktreeTitleColumn();
|
|
4231
4616
|
if (toMigrationInclusive === void 0 || toMigrationInclusive >= 34) yield* repairProjectionProjectAvatarColumns();
|
|
4232
4617
|
if (toMigrationInclusive === void 0 || toMigrationInclusive >= 35) yield* repairProjectionTokenModeColumns();
|
|
4618
|
+
if (toMigrationInclusive === void 0 || toMigrationInclusive >= 41) yield* repairProjectionThreadSubagentNestingColumns();
|
|
4233
4619
|
yield* effect_Effect.log("Migrations ran successfully").pipe(effect_Effect.annotateLogs({ migrations: executedMigrations.map(([id, name]) => `${id}_${name}`) }));
|
|
4234
4620
|
return executedMigrations;
|
|
4235
4621
|
});
|
|
@@ -4304,10 +4690,10 @@ function normalizeAzureDevOpsPullRequestRecord(raw) {
|
|
|
4304
4690
|
updatedAt: (raw.closedDate ?? effect.Option.none()).pipe(effect.Option.orElse(() => raw.creationDate ?? effect.Option.none()))
|
|
4305
4691
|
};
|
|
4306
4692
|
}
|
|
4307
|
-
const decodeAzureDevOpsPullRequestList =
|
|
4308
|
-
const decodeAzureDevOpsPullRequest =
|
|
4693
|
+
const decodeAzureDevOpsPullRequestList = require_collectUint8StreamText.decodeJsonResult(effect.Schema.Array(effect.Schema.Unknown));
|
|
4694
|
+
const decodeAzureDevOpsPullRequest = require_collectUint8StreamText.decodeJsonResult(AzureDevOpsPullRequestSchema);
|
|
4309
4695
|
const decodeAzureDevOpsPullRequestEntry = effect.Schema.decodeUnknownExit(AzureDevOpsPullRequestSchema);
|
|
4310
|
-
const formatAzureDevOpsJsonDecodeError =
|
|
4696
|
+
const formatAzureDevOpsJsonDecodeError = require_collectUint8StreamText.formatSchemaError;
|
|
4311
4697
|
function decodeAzureDevOpsPullRequestListJson(raw) {
|
|
4312
4698
|
const result = decodeAzureDevOpsPullRequestList(raw);
|
|
4313
4699
|
if (effect.Result.isSuccess(result)) {
|
|
@@ -4345,7 +4731,7 @@ function flattenThreadComments(threads) {
|
|
|
4345
4731
|
createdAt: c.publishedDate ?? ""
|
|
4346
4732
|
}));
|
|
4347
4733
|
}
|
|
4348
|
-
const decodeAzurePullRequestDetail =
|
|
4734
|
+
const decodeAzurePullRequestDetail = require_collectUint8StreamText.decodeJsonResult(effect.Schema.Struct({
|
|
4349
4735
|
...AzureDevOpsPullRequestSchema.fields,
|
|
4350
4736
|
description: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
|
|
4351
4737
|
threads: effect.Schema.optional(effect.Schema.Array(AzureThreadSchema))
|
|
@@ -4360,7 +4746,7 @@ function decodeAzureDevOpsPullRequestDetailJson(raw) {
|
|
|
4360
4746
|
comments: flattenThreadComments(result.success.threads ?? [])
|
|
4361
4747
|
});
|
|
4362
4748
|
}
|
|
4363
|
-
const decodeThreadList =
|
|
4749
|
+
const decodeThreadList = require_collectUint8StreamText.decodeJsonResult(effect.Schema.Array(AzureThreadSchema));
|
|
4364
4750
|
function decodeAzureDevOpsPullRequestThreadsJson(raw) {
|
|
4365
4751
|
if (raw.length === 0) return effect.Result.succeed([]);
|
|
4366
4752
|
const result = decodeThreadList(raw);
|
|
@@ -4434,10 +4820,10 @@ function normalize(raw) {
|
|
|
4434
4820
|
labels: labelsFromTags(raw.fields["System.Tags"])
|
|
4435
4821
|
};
|
|
4436
4822
|
}
|
|
4437
|
-
const decodeWorkItemList =
|
|
4823
|
+
const decodeWorkItemList = require_collectUint8StreamText.decodeJsonResult(effect.Schema.Array(effect.Schema.Unknown));
|
|
4438
4824
|
const decodeWorkItemEntry = effect.Schema.decodeUnknownExit(AzureWorkItemSchema);
|
|
4439
|
-
const decodeWorkItemDetail =
|
|
4440
|
-
const formatAzureDevOpsWorkItemDecodeError =
|
|
4825
|
+
const decodeWorkItemDetail = require_collectUint8StreamText.decodeJsonResult(AzureWorkItemSchema);
|
|
4826
|
+
const formatAzureDevOpsWorkItemDecodeError = require_collectUint8StreamText.formatSchemaError;
|
|
4441
4827
|
function decodeAzureDevOpsWorkItemListJson(raw) {
|
|
4442
4828
|
const result = decodeWorkItemList(raw);
|
|
4443
4829
|
if (!effect.Result.isSuccess(result)) return effect.Result.fail(result.failure);
|
|
@@ -4855,9 +5241,9 @@ function normalizeBitbucketCommentList(decoded) {
|
|
|
4855
5241
|
createdAt: c.created_on
|
|
4856
5242
|
}));
|
|
4857
5243
|
}
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
5244
|
+
require_collectUint8StreamText.decodeJsonResult(BitbucketIssueListSchema);
|
|
5245
|
+
require_collectUint8StreamText.decodeJsonResult(BitbucketIssueSchema);
|
|
5246
|
+
require_collectUint8StreamText.decodeJsonResult(BitbucketCommentListSchema);
|
|
4861
5247
|
//#endregion
|
|
4862
5248
|
//#region src/sourceControl/bitbucketPullRequests.ts
|
|
4863
5249
|
const BitbucketRepositoryRefSchema = effect.Schema.Struct({
|
|
@@ -4940,7 +5326,7 @@ const BitbucketPullRequestDetailSchema = effect.Schema.Struct({
|
|
|
4940
5326
|
...BitbucketPullRequestSchema.fields,
|
|
4941
5327
|
summary: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.Struct({ raw: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)) })))
|
|
4942
5328
|
});
|
|
4943
|
-
|
|
5329
|
+
require_collectUint8StreamText.decodeJsonResult(BitbucketPullRequestDetailSchema);
|
|
4944
5330
|
const WORK_ITEM_KEY_PATTERN = /\b([A-Z][A-Z0-9]{1,9})-(\d+)\b/giu;
|
|
4945
5331
|
function extractWorkItemKeys(input) {
|
|
4946
5332
|
const keys = /* @__PURE__ */ new Set();
|
|
@@ -5023,7 +5409,7 @@ effect.Schema.Struct({
|
|
|
5023
5409
|
var ProjectAtlassianLinkRepository = class extends effect.Context.Service()("ryco/persistence/Services/ProjectAtlassianLinks/ProjectAtlassianLinkRepository") {};
|
|
5024
5410
|
//#endregion
|
|
5025
5411
|
//#region src/atlassian/AtlassianConnectionService.ts
|
|
5026
|
-
const textEncoder$
|
|
5412
|
+
const textEncoder$1 = new TextEncoder();
|
|
5027
5413
|
var AtlassianConnectionService = class extends effect.Context.Service()("ryco/atlassian/AtlassianConnectionService") {};
|
|
5028
5414
|
function atlassianError(operation, detail, cause) {
|
|
5029
5415
|
return new require_collectUint8StreamText.AtlassianConnectionError({
|
|
@@ -5151,7 +5537,7 @@ const make$19 = effect.Effect.fn("makeAtlassianConnectionService")(function* ()
|
|
|
5151
5537
|
createdAt,
|
|
5152
5538
|
updatedAt: createdAt
|
|
5153
5539
|
};
|
|
5154
|
-
return secretStore.set(manualBitbucketTokenSecretName(connectionId), textEncoder$
|
|
5540
|
+
return secretStore.set(manualBitbucketTokenSecretName(connectionId), textEncoder$1.encode(input.token)).pipe(effect.Effect.flatMap(() => connections.upsert(record)), cleanupSecretOnFailure(manualBitbucketTokenSecretName(connectionId)), effect.Effect.as(toSummary(record)), effect.Effect.mapError(mapError$1("atlassian.saveManualBitbucketToken", "Failed to save the Bitbucket token.")));
|
|
5155
5541
|
},
|
|
5156
5542
|
saveManualJiraToken: (input) => {
|
|
5157
5543
|
const createdAt = nowIso$2();
|
|
@@ -5187,7 +5573,7 @@ const make$19 = effect.Effect.fn("makeAtlassianConnectionService")(function* ()
|
|
|
5187
5573
|
avatarUrl: null,
|
|
5188
5574
|
updatedAt: createdAt
|
|
5189
5575
|
};
|
|
5190
|
-
return secretStore.set(manualJiraTokenSecretName(connectionId), textEncoder$
|
|
5576
|
+
return secretStore.set(manualJiraTokenSecretName(connectionId), textEncoder$1.encode(input.token)).pipe(effect.Effect.flatMap(() => connections.upsert(record)), effect.Effect.flatMap(() => resources.upsertForConnection({
|
|
5191
5577
|
connectionId,
|
|
5192
5578
|
resources: [resource]
|
|
5193
5579
|
})), cleanupSecretOnFailure(manualJiraTokenSecretName(connectionId)), effect.Effect.as(toSummary(record)), effect.Effect.mapError(mapError$1("atlassian.saveManualJiraToken", "Failed to save the Jira API token.")));
|
|
@@ -5303,6 +5689,11 @@ const NON_REPOSITORY_STATUS_DETAILS = Object.freeze({
|
|
|
5303
5689
|
behindCount: 0,
|
|
5304
5690
|
aheadOfDefaultCount: 0
|
|
5305
5691
|
});
|
|
5692
|
+
const emptyDiffTotals = () => ({
|
|
5693
|
+
files: [],
|
|
5694
|
+
insertions: 0,
|
|
5695
|
+
deletions: 0
|
|
5696
|
+
});
|
|
5306
5697
|
var StatusRemoteRefreshCacheKey = class extends effect.Data.Class {};
|
|
5307
5698
|
function parseBranchAb(value) {
|
|
5308
5699
|
const match = value.match(/^\+(\d+)\s+-(\d+)$/);
|
|
@@ -5502,7 +5893,7 @@ const createTrace2Monitor = effect.Effect.fn("createTrace2Monitor")(function* (i
|
|
|
5502
5893
|
const handleTraceLine = effect.Effect.fn("handleTraceLine")(function* (line) {
|
|
5503
5894
|
const trimmedLine = line.trim();
|
|
5504
5895
|
if (trimmedLine.length === 0) return;
|
|
5505
|
-
const traceRecord =
|
|
5896
|
+
const traceRecord = require_collectUint8StreamText.decodeJsonResult(Trace2Record)(trimmedLine);
|
|
5506
5897
|
if (effect.Result.isFailure(traceRecord)) {
|
|
5507
5898
|
yield* effect.Effect.logDebug(`GitVcsDriver.trace2: failed to parse trace line for ${quoteGitCommand(input.args)} in ${input.cwd}`, traceRecord.failure);
|
|
5508
5899
|
return;
|
|
@@ -5949,6 +6340,31 @@ const makeGitVcsDriverCore = effect.Effect.fn("makeGitVcsDriverCore")(function*
|
|
|
5949
6340
|
const parsed = Number.parseInt(result.stdout.trim(), 10);
|
|
5950
6341
|
return Number.isFinite(parsed) ? Math.max(0, parsed) : 0;
|
|
5951
6342
|
});
|
|
6343
|
+
const readCommittedAgainstBase = effect.Effect.fn("readCommittedAgainstBase")(function* (cwd, refName) {
|
|
6344
|
+
const baseRef = yield* resolveBaseBranchForNoUpstream(cwd, refName).pipe(effect.Effect.catch(() => effect.Effect.succeed(null)));
|
|
6345
|
+
if (!baseRef) return emptyDiffTotals();
|
|
6346
|
+
const result = yield* executeGit("GitVcsDriver.readCommittedAgainstBase.diff", cwd, [
|
|
6347
|
+
"diff",
|
|
6348
|
+
"--numstat",
|
|
6349
|
+
`${baseRef}...HEAD`
|
|
6350
|
+
], { allowNonZeroExit: true });
|
|
6351
|
+
if (result.exitCode !== 0) return emptyDiffTotals();
|
|
6352
|
+
let insertions = 0;
|
|
6353
|
+
let deletions = 0;
|
|
6354
|
+
return {
|
|
6355
|
+
files: parseNumstatEntries(result.stdout).map((entry) => {
|
|
6356
|
+
insertions += entry.insertions;
|
|
6357
|
+
deletions += entry.deletions;
|
|
6358
|
+
return {
|
|
6359
|
+
path: entry.path,
|
|
6360
|
+
insertions: entry.insertions,
|
|
6361
|
+
deletions: entry.deletions
|
|
6362
|
+
};
|
|
6363
|
+
}).toSorted((a, b) => a.path.localeCompare(b.path)),
|
|
6364
|
+
insertions,
|
|
6365
|
+
deletions
|
|
6366
|
+
};
|
|
6367
|
+
});
|
|
5952
6368
|
const readBranchRecency = effect.Effect.fn("readBranchRecency")(function* (cwd) {
|
|
5953
6369
|
const branchRecency = yield* executeGit("GitVcsDriver.readBranchRecency", cwd, [
|
|
5954
6370
|
"for-each-ref",
|
|
@@ -6067,6 +6483,7 @@ const makeGitVcsDriverCore = effect.Effect.fn("makeGitVcsDriverCore")(function*
|
|
|
6067
6483
|
});
|
|
6068
6484
|
}
|
|
6069
6485
|
files.sort((a, b) => a.path.localeCompare(b.path));
|
|
6486
|
+
const committed = refName && !isDefaultBranch ? yield* readCommittedAgainstBase(cwd, refName).pipe(effect.Effect.catch(() => effect.Effect.succeed(emptyDiffTotals()))) : void 0;
|
|
6070
6487
|
return {
|
|
6071
6488
|
isRepo: true,
|
|
6072
6489
|
hasOriginRemote: hasPrimaryRemote,
|
|
@@ -6079,6 +6496,7 @@ const makeGitVcsDriverCore = effect.Effect.fn("makeGitVcsDriverCore")(function*
|
|
|
6079
6496
|
insertions,
|
|
6080
6497
|
deletions
|
|
6081
6498
|
},
|
|
6499
|
+
...committed ? { committed } : {},
|
|
6082
6500
|
hasUpstream: upstreamRef !== null,
|
|
6083
6501
|
aheadCount,
|
|
6084
6502
|
behindCount,
|
|
@@ -6099,6 +6517,7 @@ const makeGitVcsDriverCore = effect.Effect.fn("makeGitVcsDriverCore")(function*
|
|
|
6099
6517
|
refName: details.branch,
|
|
6100
6518
|
hasWorkingTreeChanges: details.hasWorkingTreeChanges,
|
|
6101
6519
|
workingTree: details.workingTree,
|
|
6520
|
+
...details.committed ? { committed: details.committed } : {},
|
|
6102
6521
|
hasUpstream: details.hasUpstream,
|
|
6103
6522
|
aheadCount: details.aheadCount,
|
|
6104
6523
|
behindCount: details.behindCount,
|
|
@@ -6991,7 +7410,7 @@ const layer$13 = effect.Layer.effect(VcsDriverRegistry, make$16()).pipe(effect.L
|
|
|
6991
7410
|
//#endregion
|
|
6992
7411
|
//#region src/sourceControl/BitbucketApi.ts
|
|
6993
7412
|
const DEFAULT_API_BASE_URL = "https://api.bitbucket.org/2.0";
|
|
6994
|
-
const textDecoder$
|
|
7413
|
+
const textDecoder$1 = new TextDecoder();
|
|
6995
7414
|
const BitbucketApiEnvConfig = effect.Config.all({
|
|
6996
7415
|
baseUrl: effect.Config.string("RYCO_BITBUCKET_API_BASE_URL").pipe(effect.Config.withDefault(DEFAULT_API_BASE_URL)),
|
|
6997
7416
|
accessToken: effect.Config.string("RYCO_BITBUCKET_ACCESS_TOKEN").pipe(effect.Config.option),
|
|
@@ -7336,7 +7755,7 @@ const make$15 = effect.Effect.fn("makeBitbucketApi")(function* () {
|
|
|
7336
7755
|
cause
|
|
7337
7756
|
})));
|
|
7338
7757
|
if (!tokenBytes || tokenBytes.length === 0) continue;
|
|
7339
|
-
const token = textDecoder$
|
|
7758
|
+
const token = textDecoder$1.decode(tokenBytes).trim();
|
|
7340
7759
|
if (!token) continue;
|
|
7341
7760
|
return {
|
|
7342
7761
|
source: "stored",
|
|
@@ -7741,9 +8160,9 @@ function normalizeForgejoIssueDetail(input) {
|
|
|
7741
8160
|
comments: input.comments.map(normalizeForgejoComment)
|
|
7742
8161
|
};
|
|
7743
8162
|
}
|
|
7744
|
-
|
|
7745
|
-
|
|
7746
|
-
|
|
8163
|
+
require_collectUint8StreamText.decodeJsonResult(effect.Schema.Array(effect.Schema.Unknown));
|
|
8164
|
+
require_collectUint8StreamText.decodeJsonResult(ForgejoIssueSchema);
|
|
8165
|
+
require_collectUint8StreamText.decodeJsonResult(ForgejoCommentListSchema);
|
|
7747
8166
|
effect.Schema.decodeUnknownExit(ForgejoIssueSchema);
|
|
7748
8167
|
//#endregion
|
|
7749
8168
|
//#region src/sourceControl/forgejoPullRequests.ts
|
|
@@ -7882,8 +8301,8 @@ function normalizeForgejoPullRequestDetail(input) {
|
|
|
7882
8301
|
files
|
|
7883
8302
|
};
|
|
7884
8303
|
}
|
|
7885
|
-
|
|
7886
|
-
|
|
8304
|
+
require_collectUint8StreamText.decodeJsonResult(effect.Schema.Array(effect.Schema.Unknown));
|
|
8305
|
+
require_collectUint8StreamText.decodeJsonResult(ForgejoPullRequestSchema);
|
|
7887
8306
|
effect.Schema.decodeUnknownExit(ForgejoPullRequestSchema);
|
|
7888
8307
|
//#endregion
|
|
7889
8308
|
//#region src/sourceControl/ForgejoApi.ts
|
|
@@ -7915,7 +8334,7 @@ const ForgejoCliLoginSchema = effect.Schema.Struct({
|
|
|
7915
8334
|
name: effect.Schema.optional(require_collectUint8StreamText.TrimmedNonEmptyString),
|
|
7916
8335
|
token: effect.Schema.optional(require_collectUint8StreamText.TrimmedNonEmptyString)
|
|
7917
8336
|
});
|
|
7918
|
-
const decodeForgejoCliKeysJson =
|
|
8337
|
+
const decodeForgejoCliKeysJson = require_collectUint8StreamText.decodeJsonResult(effect.Schema.Struct({ hosts: effect.Schema.optional(effect.Schema.Record(effect.Schema.String, ForgejoCliLoginSchema)) }));
|
|
7919
8338
|
var ForgejoApi = class extends effect.Context.Service()("ryco/source-control/ForgejoApi") {};
|
|
7920
8339
|
function nonEmpty$1(value) {
|
|
7921
8340
|
const trimmed = value?.trim();
|
|
@@ -8478,7 +8897,7 @@ const RawGitHubReactionGroupSchema = effect.Schema.Struct({
|
|
|
8478
8897
|
reactors: effect.Schema.optional(effect.Schema.Struct({ totalCount: effect.Schema.optional(effect.Schema.Number) })),
|
|
8479
8898
|
users: effect.Schema.optional(effect.Schema.Struct({ totalCount: effect.Schema.optional(effect.Schema.Number) }))
|
|
8480
8899
|
});
|
|
8481
|
-
const decodeReactionGroupsBySubject =
|
|
8900
|
+
const decodeReactionGroupsBySubject = require_collectUint8StreamText.decodeJsonResult(effect.Schema.Struct({ data: effect.Schema.Struct({ nodes: effect.Schema.Array(effect.Schema.NullOr(effect.Schema.Struct({
|
|
8482
8901
|
id: effect.Schema.String,
|
|
8483
8902
|
reactionGroups: effect.Schema.Array(RawGitHubReactionGroupSchema)
|
|
8484
8903
|
}))) }) }));
|
|
@@ -8521,7 +8940,7 @@ function normalizeReactionGroups(raw) {
|
|
|
8521
8940
|
}];
|
|
8522
8941
|
});
|
|
8523
8942
|
}
|
|
8524
|
-
const formatGitHubReactionGroupsDecodeError =
|
|
8943
|
+
const formatGitHubReactionGroupsDecodeError = require_collectUint8StreamText.formatSchemaError;
|
|
8525
8944
|
function decodeGitHubReactionGroupsBySubjectJson(raw) {
|
|
8526
8945
|
const result = decodeReactionGroupsBySubject(raw);
|
|
8527
8946
|
if (!effect.Result.isSuccess(result)) return effect.Result.fail(result.failure);
|
|
@@ -8599,8 +9018,8 @@ function normalizeGitHubIssueRecord(raw) {
|
|
|
8599
9018
|
commentsCount
|
|
8600
9019
|
};
|
|
8601
9020
|
}
|
|
8602
|
-
const decodeIssueList$1 =
|
|
8603
|
-
const decodeIssueDetail$1 =
|
|
9021
|
+
const decodeIssueList$1 = require_collectUint8StreamText.decodeJsonResult(effect.Schema.Array(effect.Schema.Unknown));
|
|
9022
|
+
const decodeIssueDetail$1 = require_collectUint8StreamText.decodeJsonResult(GitHubIssueSchema);
|
|
8604
9023
|
const decodeIssueEntry$1 = effect.Schema.decodeUnknownExit(GitHubIssueSchema);
|
|
8605
9024
|
const GitHubLabelSchema = effect.Schema.Struct({
|
|
8606
9025
|
name: effect.Schema.String,
|
|
@@ -8612,9 +9031,9 @@ const GitHubAssigneeSchema = effect.Schema.Struct({
|
|
|
8612
9031
|
name: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
|
|
8613
9032
|
avatar_url: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String))
|
|
8614
9033
|
});
|
|
8615
|
-
const decodeJsonLabelList =
|
|
8616
|
-
const decodeJsonAssigneeList =
|
|
8617
|
-
const formatGitHubIssueDecodeError =
|
|
9034
|
+
const decodeJsonLabelList = require_collectUint8StreamText.decodeJsonResult(effect.Schema.Array(GitHubLabelSchema));
|
|
9035
|
+
const decodeJsonAssigneeList = require_collectUint8StreamText.decodeJsonResult(effect.Schema.Array(GitHubAssigneeSchema));
|
|
9036
|
+
const formatGitHubIssueDecodeError = require_collectUint8StreamText.formatSchemaError;
|
|
8618
9037
|
function decodeGitHubIssueListJson(raw) {
|
|
8619
9038
|
const result = decodeIssueList$1(raw);
|
|
8620
9039
|
if (!effect.Result.isSuccess(result)) return effect.Result.fail(result.failure);
|
|
@@ -8763,10 +9182,10 @@ function normalizePullRequestWorkflowContext(raw) {
|
|
|
8763
9182
|
baseRepositoryNameWithOwner: optionalTrimmed(raw.base?.repo?.full_name)
|
|
8764
9183
|
};
|
|
8765
9184
|
}
|
|
8766
|
-
const decodeWorkflowRunsResponse =
|
|
8767
|
-
const decodeWorkflowJobsResponse =
|
|
8768
|
-
const decodePullRequestWorkflowContext =
|
|
8769
|
-
const formatGitHubWorkflowDecodeError =
|
|
9185
|
+
const decodeWorkflowRunsResponse = require_collectUint8StreamText.decodeJsonResult(RawGitHubWorkflowRunsResponseSchema);
|
|
9186
|
+
const decodeWorkflowJobsResponse = require_collectUint8StreamText.decodeJsonResult(RawGitHubWorkflowJobsPayloadSchema);
|
|
9187
|
+
const decodePullRequestWorkflowContext = require_collectUint8StreamText.decodeJsonResult(RawGitHubPullRequestWorkflowContextSchema);
|
|
9188
|
+
const formatGitHubWorkflowDecodeError = require_collectUint8StreamText.formatSchemaError;
|
|
8770
9189
|
function decodeGitHubWorkflowRunsJson(raw) {
|
|
8771
9190
|
const result = decodeWorkflowRunsResponse(raw);
|
|
8772
9191
|
return effect.Result.isSuccess(result) ? effect.Result.succeed(result.success.workflow_runs.map(normalizeWorkflowRun)) : effect.Result.fail(result.failure);
|
|
@@ -8974,10 +9393,10 @@ function normalizeGitHubPullRequestRecord(raw) {
|
|
|
8974
9393
|
...raw.statusCheckRollup ? { checkRollup: raw.statusCheckRollup.map((item, index) => normalizeCheckRollupItem(item, index)) } : {}
|
|
8975
9394
|
};
|
|
8976
9395
|
}
|
|
8977
|
-
const decodeGitHubPullRequestList =
|
|
8978
|
-
const decodeGitHubPullRequest =
|
|
9396
|
+
const decodeGitHubPullRequestList = require_collectUint8StreamText.decodeJsonResult(effect.Schema.Array(effect.Schema.Unknown));
|
|
9397
|
+
const decodeGitHubPullRequest = require_collectUint8StreamText.decodeJsonResult(GitHubPullRequestSchema);
|
|
8979
9398
|
const decodeGitHubPullRequestEntry = effect.Schema.decodeUnknownExit(GitHubPullRequestSchema);
|
|
8980
|
-
const formatGitHubJsonDecodeError =
|
|
9399
|
+
const formatGitHubJsonDecodeError = require_collectUint8StreamText.formatSchemaError;
|
|
8981
9400
|
function decodeGitHubPullRequestListJson(raw) {
|
|
8982
9401
|
const result = decodeGitHubPullRequestList(raw);
|
|
8983
9402
|
if (effect.Result.isSuccess(result)) {
|
|
@@ -9650,7 +10069,7 @@ const make$13 = effect.Effect.fn("makeGitHubCli")(function* () {
|
|
|
9650
10069
|
...l.description ? { description: l.description } : {}
|
|
9651
10070
|
}))) : effect.Effect.fail(new GitHubCliError({
|
|
9652
10071
|
operation: "listLabels",
|
|
9653
|
-
detail: `Invalid label list output: ${
|
|
10072
|
+
detail: `Invalid label list output: ${require_collectUint8StreamText.formatSchemaError(decoded.failure)}`,
|
|
9654
10073
|
cause: decoded.failure
|
|
9655
10074
|
})))))),
|
|
9656
10075
|
listAssignees: (input) => execute({
|
|
@@ -9670,7 +10089,7 @@ const make$13 = effect.Effect.fn("makeGitHubCli")(function* () {
|
|
|
9670
10089
|
...u.avatar_url ? { avatarUrl: u.avatar_url } : {}
|
|
9671
10090
|
}))) : effect.Effect.fail(new GitHubCliError({
|
|
9672
10091
|
operation: "listAssignees",
|
|
9673
|
-
detail: `Invalid assignees output: ${
|
|
10092
|
+
detail: `Invalid assignees output: ${require_collectUint8StreamText.formatSchemaError(decoded.failure)}`,
|
|
9674
10093
|
cause: decoded.failure
|
|
9675
10094
|
})))))),
|
|
9676
10095
|
listWorkflowRuns: (input) => execute({
|
|
@@ -9779,10 +10198,10 @@ function normalizeGitLabIssueRecord(raw) {
|
|
|
9779
10198
|
labels: raw.labels ?? []
|
|
9780
10199
|
};
|
|
9781
10200
|
}
|
|
9782
|
-
const decodeIssueList =
|
|
9783
|
-
const decodeIssueDetail =
|
|
10201
|
+
const decodeIssueList = require_collectUint8StreamText.decodeJsonResult(effect.Schema.Array(effect.Schema.Unknown));
|
|
10202
|
+
const decodeIssueDetail = require_collectUint8StreamText.decodeJsonResult(GitLabIssueSchema);
|
|
9784
10203
|
const decodeIssueEntry = effect.Schema.decodeUnknownExit(GitLabIssueSchema);
|
|
9785
|
-
const formatGitLabIssueDecodeError =
|
|
10204
|
+
const formatGitLabIssueDecodeError = require_collectUint8StreamText.formatSchemaError;
|
|
9786
10205
|
function decodeGitLabIssueListJson(raw) {
|
|
9787
10206
|
const result = decodeIssueList(raw);
|
|
9788
10207
|
if (!effect.Result.isSuccess(result)) return effect.Result.fail(result.failure);
|
|
@@ -9869,10 +10288,10 @@ function normalizeGitLabMergeRequestRecord(raw) {
|
|
|
9869
10288
|
...headRepositoryOwnerLogin ? { headRepositoryOwnerLogin } : {}
|
|
9870
10289
|
};
|
|
9871
10290
|
}
|
|
9872
|
-
const decodeGitLabMergeRequestList =
|
|
9873
|
-
const decodeGitLabMergeRequest =
|
|
10291
|
+
const decodeGitLabMergeRequestList = require_collectUint8StreamText.decodeJsonResult(effect.Schema.Array(effect.Schema.Unknown));
|
|
10292
|
+
const decodeGitLabMergeRequest = require_collectUint8StreamText.decodeJsonResult(GitLabMergeRequestSchema);
|
|
9874
10293
|
const decodeGitLabMergeRequestEntry = effect.Schema.decodeUnknownExit(GitLabMergeRequestSchema);
|
|
9875
|
-
const formatGitLabJsonDecodeError =
|
|
10294
|
+
const formatGitLabJsonDecodeError = require_collectUint8StreamText.formatSchemaError;
|
|
9876
10295
|
function decodeGitLabMergeRequestListJson(raw) {
|
|
9877
10296
|
const result = decodeGitLabMergeRequestList(raw);
|
|
9878
10297
|
if (effect.Result.isSuccess(result)) {
|
|
@@ -9891,7 +10310,7 @@ function decodeGitLabMergeRequestJson(raw) {
|
|
|
9891
10310
|
if (effect.Result.isSuccess(result)) return effect.Result.succeed(normalizeGitLabMergeRequestRecord(result.success));
|
|
9892
10311
|
return effect.Result.fail(result.failure);
|
|
9893
10312
|
}
|
|
9894
|
-
const decodeGitLabMergeRequestDetail =
|
|
10313
|
+
const decodeGitLabMergeRequestDetail = require_collectUint8StreamText.decodeJsonResult(effect.Schema.Struct({
|
|
9895
10314
|
...GitLabMergeRequestSchema.fields,
|
|
9896
10315
|
description: effect.Schema.optional(effect.Schema.NullOr(effect.Schema.String)),
|
|
9897
10316
|
notes: effect.Schema.optional(effect.Schema.Array(effect.Schema.Struct({
|
|
@@ -10561,26 +10980,26 @@ const make$11 = effect.Effect.fn("makeSourceControlProviderRegistry")(function*
|
|
|
10561
10980
|
const azureDevOpsCli = yield* AzureDevOpsCli;
|
|
10562
10981
|
const fileSystem = yield* effect.FileSystem.FileSystem;
|
|
10563
10982
|
const github = yield* makeLazyProvider("github", effect.Effect.tryPromise({
|
|
10564
|
-
try: () => Promise.resolve().then(() => require("./GitHubSourceControlProvider-
|
|
10983
|
+
try: () => Promise.resolve().then(() => require("./GitHubSourceControlProvider-DWmwkA_y.cjs")),
|
|
10565
10984
|
catch: (cause) => providerLoadError("github", cause)
|
|
10566
10985
|
}).pipe(effect.Effect.flatMap((module) => module.make()), effect.Effect.provideService(GitHubCli, githubCli), effect.Effect.provideService(effect.FileSystem.FileSystem, fileSystem)));
|
|
10567
10986
|
const gitlab = yield* makeLazyProvider("gitlab", effect.Effect.tryPromise({
|
|
10568
|
-
try: () => Promise.resolve().then(() => require("./GitLabSourceControlProvider-
|
|
10987
|
+
try: () => Promise.resolve().then(() => require("./GitLabSourceControlProvider-D-YHnxRe.cjs")),
|
|
10569
10988
|
catch: (cause) => providerLoadError("gitlab", cause)
|
|
10570
10989
|
}).pipe(effect.Effect.flatMap((module) => module.make()), effect.Effect.provideService(GitLabCli, gitlabCli)));
|
|
10571
10990
|
const bitbucket = yield* makeLazyProvider("bitbucket", effect.Effect.tryPromise({
|
|
10572
|
-
try: () => Promise.resolve().then(() => require("./BitbucketSourceControlProvider-
|
|
10991
|
+
try: () => Promise.resolve().then(() => require("./BitbucketSourceControlProvider-1GWENqcl.cjs")),
|
|
10573
10992
|
catch: (cause) => providerLoadError("bitbucket", cause)
|
|
10574
10993
|
}).pipe(effect.Effect.flatMap((module) => module.make()), effect.Effect.provideService(BitbucketApi, bitbucketApi)), {
|
|
10575
10994
|
searchRepositories: true,
|
|
10576
10995
|
cloneAuthentication: true
|
|
10577
10996
|
});
|
|
10578
10997
|
const forgejo = yield* makeLazyProvider("forgejo", effect.Effect.tryPromise({
|
|
10579
|
-
try: () => Promise.resolve().then(() => require("./ForgejoSourceControlProvider-
|
|
10998
|
+
try: () => Promise.resolve().then(() => require("./ForgejoSourceControlProvider-BTXRDCGB.cjs")),
|
|
10580
10999
|
catch: (cause) => providerLoadError("forgejo", cause)
|
|
10581
11000
|
}).pipe(effect.Effect.flatMap((module) => module.make()), effect.Effect.provideService(ForgejoApi, forgejoApi)));
|
|
10582
11001
|
const azureDevOps = yield* makeLazyProvider("azure-devops", effect.Effect.tryPromise({
|
|
10583
|
-
try: () => Promise.resolve().then(() => require("./AzureDevOpsSourceControlProvider-
|
|
11002
|
+
try: () => Promise.resolve().then(() => require("./AzureDevOpsSourceControlProvider-5exivY-1.cjs")),
|
|
10584
11003
|
catch: (cause) => providerLoadError("azure-devops", cause)
|
|
10585
11004
|
}).pipe(effect.Effect.flatMap((module) => module.make()), effect.Effect.provideService(AzureDevOpsCli, azureDevOpsCli)));
|
|
10586
11005
|
const bitbucketDiscovery = require_SourceControlProviderDiscoveryCatalog.makeBitbucketDiscovery(bitbucketApi);
|
|
@@ -10703,22 +11122,6 @@ var CheckpointDiffQuery = class extends effect.Context.Service()("ryco/checkpoin
|
|
|
10703
11122
|
//#region src/diagnostics/Services/Diagnostics.ts
|
|
10704
11123
|
var Diagnostics = class extends effect.Context.Service()("ryco/diagnostics/Services/Diagnostics") {};
|
|
10705
11124
|
//#endregion
|
|
10706
|
-
//#region src/atomicWrite.ts
|
|
10707
|
-
const writeFileStringAtomically = (input) => effect.Effect.scoped(effect.Effect.gen(function* () {
|
|
10708
|
-
const fs = yield* effect.FileSystem.FileSystem;
|
|
10709
|
-
const path = yield* effect.Path.Path;
|
|
10710
|
-
const tempFileId = yield* effect_Random.nextUUIDv4;
|
|
10711
|
-
const targetDirectory = path.dirname(input.filePath);
|
|
10712
|
-
yield* fs.makeDirectory(targetDirectory, { recursive: true });
|
|
10713
|
-
const tempDirectory = yield* fs.makeTempDirectoryScoped({
|
|
10714
|
-
directory: targetDirectory,
|
|
10715
|
-
prefix: `${path.basename(input.filePath)}.`
|
|
10716
|
-
});
|
|
10717
|
-
const tempPath = path.join(tempDirectory, `${tempFileId}.tmp`);
|
|
10718
|
-
yield* fs.writeFileString(tempPath, input.contents);
|
|
10719
|
-
yield* fs.rename(tempPath, input.filePath);
|
|
10720
|
-
}));
|
|
10721
|
-
//#endregion
|
|
10722
11125
|
//#region ../../packages/shared/src/keybindings.ts
|
|
10723
11126
|
const DEFAULT_KEYBINDINGS = [
|
|
10724
11127
|
{
|
|
@@ -11069,7 +11472,7 @@ function encodeWhenAst(node) {
|
|
|
11069
11472
|
case "or": return `(${encodeWhenAst(node.left)} || ${encodeWhenAst(node.right)})`;
|
|
11070
11473
|
}
|
|
11071
11474
|
}
|
|
11072
|
-
const RawKeybindingsEntries =
|
|
11475
|
+
const RawKeybindingsEntries = require_collectUint8StreamText.fromLenientJson(effect.Schema.Array(effect.Schema.Unknown));
|
|
11073
11476
|
const KeybindingsConfigJson = effect.Schema.fromJsonString(require_collectUint8StreamText.KeybindingsConfig);
|
|
11074
11477
|
const PrettyJsonString = effect.SchemaGetter.parseJson().compose(effect.SchemaGetter.stringifyJson({ space: 2 }));
|
|
11075
11478
|
const KeybindingsConfigPrettyJson = KeybindingsConfigJson.pipe(effect.Schema.encode({
|
|
@@ -26104,300 +26507,6 @@ async function runProcess(command, args, options = {}) {
|
|
|
26104
26507
|
});
|
|
26105
26508
|
}
|
|
26106
26509
|
//#endregion
|
|
26107
|
-
//#region src/serverSettings.ts
|
|
26108
|
-
/**
|
|
26109
|
-
* ServerSettings - Server-authoritative settings service.
|
|
26110
|
-
*
|
|
26111
|
-
* Owns persistence, validation, and change notification of settings that affect
|
|
26112
|
-
* server-side behavior (binary paths, streaming mode, env mode, custom models,
|
|
26113
|
-
* text generation model selection).
|
|
26114
|
-
*
|
|
26115
|
-
* Follows the same pattern as `keybindings.ts`: JSON file + Cache + PubSub +
|
|
26116
|
-
* Semaphore + FileSystem.watch for concurrency and external edit detection.
|
|
26117
|
-
*
|
|
26118
|
-
* @module ServerSettings
|
|
26119
|
-
*/
|
|
26120
|
-
const textEncoder$1 = new TextEncoder();
|
|
26121
|
-
const textDecoder$1 = new TextDecoder();
|
|
26122
|
-
function providerEnvironmentSecretName(input) {
|
|
26123
|
-
return `provider-env-${Buffer.from(input.instanceId, "utf8").toString("base64url")}-${Buffer.from(input.name, "utf8").toString("base64url")}`;
|
|
26124
|
-
}
|
|
26125
|
-
function redactProviderEnvironmentVariable(variable) {
|
|
26126
|
-
if (!variable.sensitive) {
|
|
26127
|
-
const { valueRedacted: _omit, ...rest } = variable;
|
|
26128
|
-
return rest;
|
|
26129
|
-
}
|
|
26130
|
-
return {
|
|
26131
|
-
...variable,
|
|
26132
|
-
value: "",
|
|
26133
|
-
...variable.value.length > 0 || variable.valueRedacted ? { valueRedacted: true } : {}
|
|
26134
|
-
};
|
|
26135
|
-
}
|
|
26136
|
-
function redactServerSettingsForClient(settings) {
|
|
26137
|
-
const providerInstances = Object.fromEntries(Object.entries(settings.providerInstances).map(([instanceId, instance]) => [instanceId, instance.environment ? {
|
|
26138
|
-
...instance,
|
|
26139
|
-
environment: instance.environment.map(redactProviderEnvironmentVariable)
|
|
26140
|
-
} : instance]));
|
|
26141
|
-
return {
|
|
26142
|
-
...settings,
|
|
26143
|
-
providerInstances
|
|
26144
|
-
};
|
|
26145
|
-
}
|
|
26146
|
-
var ServerSettingsService = class ServerSettingsService extends effect.Context.Service()("ryco/serverSettings/ServerSettingsService") {
|
|
26147
|
-
static layerTest = (overrides = {}) => effect.Layer.effect(ServerSettingsService, effect.Effect.gen(function* () {
|
|
26148
|
-
const currentSettingsRef = yield* effect.Ref.make(deepMerge(require_collectUint8StreamText.DEFAULT_SERVER_SETTINGS, overrides));
|
|
26149
|
-
return {
|
|
26150
|
-
start: effect.Effect.void,
|
|
26151
|
-
ready: effect.Effect.void,
|
|
26152
|
-
getSettings: effect.Ref.get(currentSettingsRef),
|
|
26153
|
-
updateSettings: (patch) => effect.Ref.get(currentSettingsRef).pipe(effect.Effect.flatMap((currentSettings) => effect.Schema.decodeEffect(require_collectUint8StreamText.ServerSettings)(applyServerSettingsPatch(currentSettings, patch)).pipe(effect.Effect.mapError((cause) => new require_collectUint8StreamText.ServerSettingsError({
|
|
26154
|
-
settingsPath: "<memory>",
|
|
26155
|
-
detail: `failed to normalize server settings: ${effect.SchemaIssue.makeFormatterDefault()(cause.issue)}`,
|
|
26156
|
-
cause
|
|
26157
|
-
})))), effect.Effect.tap((nextSettings) => effect.Ref.set(currentSettingsRef, nextSettings))),
|
|
26158
|
-
streamChanges: effect.Stream.empty
|
|
26159
|
-
};
|
|
26160
|
-
}));
|
|
26161
|
-
};
|
|
26162
|
-
const ServerSettingsJson = require_SourceControlProviderDiscoveryCatalog.fromLenientJson(require_collectUint8StreamText.ServerSettings);
|
|
26163
|
-
const getLegacyProviderSettings = (settings, provider) => settings.providers[provider];
|
|
26164
|
-
/**
|
|
26165
|
-
* Ensure the `textGenerationModelSelection` points to an enabled provider.
|
|
26166
|
-
* If the selected provider is disabled, fall back to the first enabled
|
|
26167
|
-
* provider with its default model. This is applied at read-time so the
|
|
26168
|
-
* persisted preference is preserved for when a provider is re-enabled.
|
|
26169
|
-
*/
|
|
26170
|
-
function resolveTextGenerationProvider(settings) {
|
|
26171
|
-
const selection = settings.textGenerationModelSelection;
|
|
26172
|
-
const instanceConfig = settings.providerInstances[selection.instanceId];
|
|
26173
|
-
if (instanceConfig !== void 0) return instanceConfig.enabled ?? true ? settings : fallbackTextGenerationProvider(settings);
|
|
26174
|
-
if (require_collectUint8StreamText.isProviderDriverKind(selection.instanceId) && getLegacyProviderSettings(settings, selection.instanceId)?.enabled) return settings;
|
|
26175
|
-
return fallbackTextGenerationProvider(settings);
|
|
26176
|
-
}
|
|
26177
|
-
function fallbackTextGenerationProvider(settings) {
|
|
26178
|
-
const fallbackEntry = Object.entries(settings.providers).find(([, provider]) => provider.enabled);
|
|
26179
|
-
const fallback = fallbackEntry ? require_collectUint8StreamText.ProviderDriverKind.make(fallbackEntry[0]) : void 0;
|
|
26180
|
-
if (!fallback) return settings;
|
|
26181
|
-
return {
|
|
26182
|
-
...settings,
|
|
26183
|
-
textGenerationModelSelection: {
|
|
26184
|
-
instanceId: require_collectUint8StreamText.ProviderInstanceId.make(fallback),
|
|
26185
|
-
model: require_collectUint8StreamText.DEFAULT_GIT_TEXT_GENERATION_MODEL_BY_PROVIDER[fallback] ?? "gpt-5.4-mini"
|
|
26186
|
-
}
|
|
26187
|
-
};
|
|
26188
|
-
}
|
|
26189
|
-
const ATOMIC_SETTINGS_KEYS = new Set(["textGenerationModelSelection"]);
|
|
26190
|
-
function stripDefaultServerSettings(current, defaults) {
|
|
26191
|
-
if (Array.isArray(current) || Array.isArray(defaults)) return effect.Equal.equals(current, defaults) ? void 0 : current;
|
|
26192
|
-
if (current !== null && defaults !== null && typeof current === "object" && typeof defaults === "object") {
|
|
26193
|
-
const currentRecord = current;
|
|
26194
|
-
const defaultsRecord = defaults;
|
|
26195
|
-
const next = {};
|
|
26196
|
-
for (const key of Object.keys(currentRecord)) if (ATOMIC_SETTINGS_KEYS.has(key)) {
|
|
26197
|
-
if (!effect.Equal.equals(currentRecord[key], defaultsRecord[key])) next[key] = currentRecord[key];
|
|
26198
|
-
} else {
|
|
26199
|
-
const stripped = stripDefaultServerSettings(currentRecord[key], defaultsRecord[key]);
|
|
26200
|
-
if (stripped !== void 0) next[key] = stripped;
|
|
26201
|
-
}
|
|
26202
|
-
return Object.keys(next).length > 0 ? next : void 0;
|
|
26203
|
-
}
|
|
26204
|
-
return Object.is(current, defaults) ? void 0 : current;
|
|
26205
|
-
}
|
|
26206
|
-
const makeServerSettings = effect.Effect.gen(function* () {
|
|
26207
|
-
const { settingsPath } = yield* require_Metrics.ServerConfig;
|
|
26208
|
-
const fs = yield* effect.FileSystem.FileSystem;
|
|
26209
|
-
const pathService = yield* effect.Path.Path;
|
|
26210
|
-
const secretStore = yield* ServerSecretStore;
|
|
26211
|
-
const writeSemaphore = yield* effect_Semaphore.make(1);
|
|
26212
|
-
const cacheKey = "settings";
|
|
26213
|
-
const changesPubSub = yield* effect.PubSub.unbounded();
|
|
26214
|
-
const startedRef = yield* effect.Ref.make(false);
|
|
26215
|
-
const startedDeferred = yield* effect.Deferred.make();
|
|
26216
|
-
const watcherScope = yield* effect.Scope.make("sequential");
|
|
26217
|
-
yield* effect.Effect.addFinalizer(() => effect.Scope.close(watcherScope, effect.Exit.void));
|
|
26218
|
-
const emitChange = (settings) => effect.PubSub.publish(changesPubSub, settings).pipe(effect.Effect.asVoid);
|
|
26219
|
-
const readConfigExists = fs.exists(settingsPath).pipe(effect.Effect.mapError((cause) => new require_collectUint8StreamText.ServerSettingsError({
|
|
26220
|
-
settingsPath,
|
|
26221
|
-
detail: "failed to check settings file existence",
|
|
26222
|
-
cause
|
|
26223
|
-
})));
|
|
26224
|
-
const readRawConfig = fs.readFileString(settingsPath).pipe(effect.Effect.mapError((cause) => new require_collectUint8StreamText.ServerSettingsError({
|
|
26225
|
-
settingsPath,
|
|
26226
|
-
detail: "failed to read settings file",
|
|
26227
|
-
cause
|
|
26228
|
-
})));
|
|
26229
|
-
const loadSettingsFromDisk = effect.Effect.gen(function* () {
|
|
26230
|
-
if (!(yield* readConfigExists)) return require_collectUint8StreamText.DEFAULT_SERVER_SETTINGS;
|
|
26231
|
-
const raw = yield* readRawConfig;
|
|
26232
|
-
const decoded = effect.Schema.decodeUnknownExit(ServerSettingsJson)(raw);
|
|
26233
|
-
if (decoded._tag === "Failure") {
|
|
26234
|
-
yield* effect.Effect.logWarning("failed to parse settings.json, using defaults", {
|
|
26235
|
-
path: settingsPath,
|
|
26236
|
-
issues: effect.Cause.pretty(decoded.cause)
|
|
26237
|
-
});
|
|
26238
|
-
return require_collectUint8StreamText.DEFAULT_SERVER_SETTINGS;
|
|
26239
|
-
}
|
|
26240
|
-
return decoded.value;
|
|
26241
|
-
});
|
|
26242
|
-
const settingsCache = yield* effect.Cache.make({
|
|
26243
|
-
capacity: 1,
|
|
26244
|
-
lookup: () => loadSettingsFromDisk
|
|
26245
|
-
});
|
|
26246
|
-
const getSettingsFromCache = effect.Cache.get(settingsCache, cacheKey);
|
|
26247
|
-
const toSettingsError = (detail, cause) => new require_collectUint8StreamText.ServerSettingsError({
|
|
26248
|
-
settingsPath,
|
|
26249
|
-
detail,
|
|
26250
|
-
cause
|
|
26251
|
-
});
|
|
26252
|
-
const materializeProviderEnvironmentSecrets = (settings) => effect.Effect.gen(function* () {
|
|
26253
|
-
const providerInstances = { ...settings.providerInstances };
|
|
26254
|
-
for (const [instanceId, instance] of Object.entries(settings.providerInstances)) {
|
|
26255
|
-
if (!instance.environment) continue;
|
|
26256
|
-
const environment = [];
|
|
26257
|
-
for (const variable of instance.environment) {
|
|
26258
|
-
if (!variable.sensitive || !variable.valueRedacted) {
|
|
26259
|
-
environment.push(variable);
|
|
26260
|
-
continue;
|
|
26261
|
-
}
|
|
26262
|
-
const secret = yield* secretStore.get(providerEnvironmentSecretName({
|
|
26263
|
-
instanceId,
|
|
26264
|
-
name: variable.name
|
|
26265
|
-
})).pipe(effect.Effect.mapError((cause) => toSettingsError(`failed to read sensitive environment variable ${variable.name}`, cause)));
|
|
26266
|
-
environment.push({
|
|
26267
|
-
...variable,
|
|
26268
|
-
value: secret ? textDecoder$1.decode(secret) : ""
|
|
26269
|
-
});
|
|
26270
|
-
}
|
|
26271
|
-
providerInstances[instanceId] = {
|
|
26272
|
-
...instance,
|
|
26273
|
-
environment
|
|
26274
|
-
};
|
|
26275
|
-
}
|
|
26276
|
-
return {
|
|
26277
|
-
...settings,
|
|
26278
|
-
providerInstances
|
|
26279
|
-
};
|
|
26280
|
-
});
|
|
26281
|
-
const persistProviderEnvironmentSecrets = (current, next) => effect.Effect.gen(function* () {
|
|
26282
|
-
const providerInstances = { ...next.providerInstances };
|
|
26283
|
-
const nextSecretKeys = /* @__PURE__ */ new Set();
|
|
26284
|
-
for (const [instanceId, instance] of Object.entries(next.providerInstances)) {
|
|
26285
|
-
if (!instance.environment) continue;
|
|
26286
|
-
const environment = [];
|
|
26287
|
-
for (const variable of instance.environment) {
|
|
26288
|
-
const secretName = providerEnvironmentSecretName({
|
|
26289
|
-
instanceId,
|
|
26290
|
-
name: variable.name
|
|
26291
|
-
});
|
|
26292
|
-
if (!variable.sensitive) {
|
|
26293
|
-
yield* secretStore.remove(secretName).pipe(effect.Effect.mapError((cause) => toSettingsError(`failed to remove environment secret ${variable.name}`, cause)));
|
|
26294
|
-
environment.push(redactProviderEnvironmentVariable(variable));
|
|
26295
|
-
continue;
|
|
26296
|
-
}
|
|
26297
|
-
nextSecretKeys.add(secretName);
|
|
26298
|
-
if (!variable.valueRedacted) {
|
|
26299
|
-
if (variable.value.length > 0) {
|
|
26300
|
-
yield* secretStore.set(secretName, textEncoder$1.encode(variable.value)).pipe(effect.Effect.mapError((cause) => toSettingsError(`failed to persist environment secret ${variable.name}`, cause)));
|
|
26301
|
-
environment.push({
|
|
26302
|
-
...variable,
|
|
26303
|
-
value: "",
|
|
26304
|
-
valueRedacted: true
|
|
26305
|
-
});
|
|
26306
|
-
} else {
|
|
26307
|
-
yield* secretStore.remove(secretName).pipe(effect.Effect.mapError((cause) => toSettingsError(`failed to remove environment secret ${variable.name}`, cause)));
|
|
26308
|
-
const { valueRedacted: _omit, ...rest } = variable;
|
|
26309
|
-
environment.push(rest);
|
|
26310
|
-
}
|
|
26311
|
-
continue;
|
|
26312
|
-
}
|
|
26313
|
-
environment.push(redactProviderEnvironmentVariable(variable));
|
|
26314
|
-
}
|
|
26315
|
-
providerInstances[instanceId] = {
|
|
26316
|
-
...instance,
|
|
26317
|
-
environment
|
|
26318
|
-
};
|
|
26319
|
-
}
|
|
26320
|
-
for (const [instanceId, instance] of Object.entries(current.providerInstances)) for (const variable of instance.environment ?? []) {
|
|
26321
|
-
if (!variable.sensitive) continue;
|
|
26322
|
-
const secretName = providerEnvironmentSecretName({
|
|
26323
|
-
instanceId,
|
|
26324
|
-
name: variable.name
|
|
26325
|
-
});
|
|
26326
|
-
if (nextSecretKeys.has(secretName)) continue;
|
|
26327
|
-
yield* secretStore.remove(secretName).pipe(effect.Effect.mapError((cause) => toSettingsError(`failed to remove stale environment secret ${variable.name}`, cause)));
|
|
26328
|
-
}
|
|
26329
|
-
return {
|
|
26330
|
-
...next,
|
|
26331
|
-
providerInstances
|
|
26332
|
-
};
|
|
26333
|
-
});
|
|
26334
|
-
const writeSettingsAtomically = (settings) => {
|
|
26335
|
-
const sparseSettings = stripDefaultServerSettings(settings, require_collectUint8StreamText.DEFAULT_SERVER_SETTINGS) ?? {};
|
|
26336
|
-
return writeFileStringAtomically({
|
|
26337
|
-
filePath: settingsPath,
|
|
26338
|
-
contents: `${JSON.stringify(sparseSettings, null, 2)}\n`
|
|
26339
|
-
}).pipe(effect.Effect.provideService(effect.FileSystem.FileSystem, fs), effect.Effect.provideService(effect.Path.Path, pathService), effect.Effect.mapError((cause) => new require_collectUint8StreamText.ServerSettingsError({
|
|
26340
|
-
settingsPath,
|
|
26341
|
-
detail: "failed to write settings file",
|
|
26342
|
-
cause
|
|
26343
|
-
})));
|
|
26344
|
-
};
|
|
26345
|
-
const revalidateAndEmit = writeSemaphore.withPermits(1)(effect.Effect.gen(function* () {
|
|
26346
|
-
yield* effect.Cache.invalidate(settingsCache, cacheKey);
|
|
26347
|
-
yield* emitChange(yield* getSettingsFromCache);
|
|
26348
|
-
}));
|
|
26349
|
-
const startWatcher = effect.Effect.gen(function* () {
|
|
26350
|
-
const settingsDir = pathService.dirname(settingsPath);
|
|
26351
|
-
const settingsFile = pathService.basename(settingsPath);
|
|
26352
|
-
const settingsPathResolved = pathService.resolve(settingsPath);
|
|
26353
|
-
yield* fs.makeDirectory(settingsDir, { recursive: true }).pipe(effect.Effect.mapError((cause) => new require_collectUint8StreamText.ServerSettingsError({
|
|
26354
|
-
settingsPath,
|
|
26355
|
-
detail: "failed to prepare settings directory",
|
|
26356
|
-
cause
|
|
26357
|
-
})));
|
|
26358
|
-
const revalidateAndEmitSafely = revalidateAndEmit.pipe(effect.Effect.ignoreCause({ log: true }));
|
|
26359
|
-
const debouncedSettingsEvents = fs.watch(settingsDir).pipe(effect.Stream.filter((event) => {
|
|
26360
|
-
return event.path === settingsFile || event.path === settingsPath || pathService.resolve(settingsDir, event.path) === settingsPathResolved;
|
|
26361
|
-
}), effect.Stream.debounce(effect.Duration.millis(100)));
|
|
26362
|
-
yield* effect.Stream.runForEach(debouncedSettingsEvents, () => revalidateAndEmitSafely).pipe(effect.Effect.ignoreCause({ log: true }), effect.Effect.forkIn(watcherScope), effect.Effect.asVoid);
|
|
26363
|
-
});
|
|
26364
|
-
return {
|
|
26365
|
-
start: effect.Effect.gen(function* () {
|
|
26366
|
-
if (!(yield* effect.Ref.modify(startedRef, (started) => [!started, true]))) return yield* effect.Deferred.await(startedDeferred);
|
|
26367
|
-
const startup = effect.Effect.gen(function* () {
|
|
26368
|
-
yield* startWatcher;
|
|
26369
|
-
yield* effect.Cache.invalidate(settingsCache, cacheKey);
|
|
26370
|
-
yield* getSettingsFromCache;
|
|
26371
|
-
});
|
|
26372
|
-
const startupExit = yield* effect.Effect.exit(startup);
|
|
26373
|
-
if (startupExit._tag === "Failure") {
|
|
26374
|
-
yield* effect.Deferred.failCause(startedDeferred, startupExit.cause).pipe(effect.Effect.orDie);
|
|
26375
|
-
return yield* effect.Effect.failCause(startupExit.cause);
|
|
26376
|
-
}
|
|
26377
|
-
yield* effect.Deferred.succeed(startedDeferred, void 0).pipe(effect.Effect.orDie);
|
|
26378
|
-
}),
|
|
26379
|
-
ready: effect.Deferred.await(startedDeferred),
|
|
26380
|
-
getSettings: getSettingsFromCache.pipe(effect.Effect.flatMap(materializeProviderEnvironmentSecrets), effect.Effect.map(resolveTextGenerationProvider)),
|
|
26381
|
-
updateSettings: (patch) => writeSemaphore.withPermits(1)(effect.Effect.gen(function* () {
|
|
26382
|
-
const current = yield* getSettingsFromCache;
|
|
26383
|
-
const nextPersisted = yield* persistProviderEnvironmentSecrets(current, applyServerSettingsPatch(current, patch));
|
|
26384
|
-
const next = yield* effect.Schema.decodeEffect(require_collectUint8StreamText.ServerSettings)(nextPersisted).pipe(effect.Effect.mapError((cause) => new require_collectUint8StreamText.ServerSettingsError({
|
|
26385
|
-
settingsPath: "<memory>",
|
|
26386
|
-
detail: `failed to normalize server settings: ${effect.SchemaIssue.makeFormatterDefault()(cause.issue)}`,
|
|
26387
|
-
cause
|
|
26388
|
-
})));
|
|
26389
|
-
yield* writeSettingsAtomically(next);
|
|
26390
|
-
yield* effect.Cache.set(settingsCache, cacheKey, next);
|
|
26391
|
-
yield* emitChange(next);
|
|
26392
|
-
return resolveTextGenerationProvider(yield* materializeProviderEnvironmentSecrets(next));
|
|
26393
|
-
})),
|
|
26394
|
-
get streamChanges() {
|
|
26395
|
-
return effect.Stream.fromPubSub(changesPubSub).pipe(effect.Stream.mapEffect((settings) => materializeProviderEnvironmentSecrets(settings).pipe(effect.Effect.catch((error) => effect.Effect.logWarning("failed to materialize provider environment secrets", { detail: error.detail }).pipe(effect.Effect.as(settings))))), effect.Stream.map(resolveTextGenerationProvider));
|
|
26396
|
-
}
|
|
26397
|
-
};
|
|
26398
|
-
});
|
|
26399
|
-
const ServerSettingsLive = effect.Layer.effect(ServerSettingsService, makeServerSettings).pipe(effect.Layer.provide(ServerSecretStoreLive));
|
|
26400
|
-
//#endregion
|
|
26401
26510
|
//#region src/pathExpansion.ts
|
|
26402
26511
|
/**
|
|
26403
26512
|
* Expand a leading `~` (or `~/…`, `~\…`) in a user-supplied path to the
|
|
@@ -26718,7 +26827,7 @@ const BUILT_IN_DRIVERS = [
|
|
|
26718
26827
|
configSchema: require_collectUint8StreamText.CodexSettings,
|
|
26719
26828
|
defaultConfig: () => effect.Schema.decodeSync(require_collectUint8StreamText.CodexSettings)({}),
|
|
26720
26829
|
create: (input) => effect.Effect.tryPromise({
|
|
26721
|
-
try: () => Promise.resolve().then(() => require("./CodexDriver-
|
|
26830
|
+
try: () => Promise.resolve().then(() => require("./CodexDriver-BboMT9uk.cjs")),
|
|
26722
26831
|
catch: (cause) => driverImportError(codexDriverKind, input, cause)
|
|
26723
26832
|
}).pipe(effect.Effect.flatMap(({ CodexDriver }) => CodexDriver.create(input)))
|
|
26724
26833
|
},
|
|
@@ -26731,7 +26840,7 @@ const BUILT_IN_DRIVERS = [
|
|
|
26731
26840
|
configSchema: require_collectUint8StreamText.ClaudeSettings,
|
|
26732
26841
|
defaultConfig: () => effect.Schema.decodeSync(require_collectUint8StreamText.ClaudeSettings)({}),
|
|
26733
26842
|
create: (input) => effect.Effect.tryPromise({
|
|
26734
|
-
try: () => Promise.resolve().then(() => require("./ClaudeDriver-
|
|
26843
|
+
try: () => Promise.resolve().then(() => require("./ClaudeDriver-BXLdjrht.cjs")),
|
|
26735
26844
|
catch: (cause) => driverImportError(claudeDriverKind, input, cause)
|
|
26736
26845
|
}).pipe(effect.Effect.flatMap(({ ClaudeDriver }) => ClaudeDriver.create(input)))
|
|
26737
26846
|
},
|
|
@@ -26744,7 +26853,7 @@ const BUILT_IN_DRIVERS = [
|
|
|
26744
26853
|
configSchema: require_collectUint8StreamText.CopilotSettings,
|
|
26745
26854
|
defaultConfig: () => effect.Schema.decodeSync(require_collectUint8StreamText.CopilotSettings)({}),
|
|
26746
26855
|
create: (input) => effect.Effect.tryPromise({
|
|
26747
|
-
try: () => Promise.resolve().then(() => require("./CopilotDriver-
|
|
26856
|
+
try: () => Promise.resolve().then(() => require("./CopilotDriver-DCsv-17W.cjs")),
|
|
26748
26857
|
catch: (cause) => driverImportError(copilotDriverKind, input, cause)
|
|
26749
26858
|
}).pipe(effect.Effect.flatMap(({ CopilotDriver }) => CopilotDriver.create(input)))
|
|
26750
26859
|
},
|
|
@@ -26757,7 +26866,7 @@ const BUILT_IN_DRIVERS = [
|
|
|
26757
26866
|
configSchema: require_collectUint8StreamText.CursorSettings,
|
|
26758
26867
|
defaultConfig: () => effect.Schema.decodeSync(require_collectUint8StreamText.CursorSettings)({}),
|
|
26759
26868
|
create: (input) => effect.Effect.tryPromise({
|
|
26760
|
-
try: () => Promise.resolve().then(() => require("./CursorDriver-
|
|
26869
|
+
try: () => Promise.resolve().then(() => require("./CursorDriver-BTSiM3A8.cjs")),
|
|
26761
26870
|
catch: (cause) => driverImportError(cursorDriverKind, input, cause)
|
|
26762
26871
|
}).pipe(effect.Effect.flatMap(({ CursorDriver }) => CursorDriver.create(input)))
|
|
26763
26872
|
},
|
|
@@ -26770,7 +26879,7 @@ const BUILT_IN_DRIVERS = [
|
|
|
26770
26879
|
configSchema: require_collectUint8StreamText.OpenCodeSettings,
|
|
26771
26880
|
defaultConfig: () => effect.Schema.decodeSync(require_collectUint8StreamText.OpenCodeSettings)({}),
|
|
26772
26881
|
create: (input) => effect.Effect.tryPromise({
|
|
26773
|
-
try: () => Promise.resolve().then(() => require("./OpenCodeDriver-
|
|
26882
|
+
try: () => Promise.resolve().then(() => require("./OpenCodeDriver-CVeZ4n9-.cjs")),
|
|
26774
26883
|
catch: (cause) => driverImportError(openCodeDriverKind, input, cause)
|
|
26775
26884
|
}).pipe(effect.Effect.flatMap(({ OpenCodeDriver }) => OpenCodeDriver.create(input)))
|
|
26776
26885
|
}
|
|
@@ -27483,7 +27592,7 @@ const scopedSafeTeardown = (label) => (effect$15) => effect.Effect.gen(function*
|
|
|
27483
27592
|
});
|
|
27484
27593
|
//#endregion
|
|
27485
27594
|
//#region package.json
|
|
27486
|
-
var version = "0.1.
|
|
27595
|
+
var version = "0.1.7";
|
|
27487
27596
|
//#endregion
|
|
27488
27597
|
//#region src/provider/Layers/CodexProvider.ts
|
|
27489
27598
|
const PROVIDER_PROBE_TIMEOUT_MS = 8e3;
|
|
@@ -28520,6 +28629,387 @@ var OrchestrationEngineService = class extends effect.Context.Service()("ryco/or
|
|
|
28520
28629
|
*/
|
|
28521
28630
|
var ProjectionSnapshotQuery = class extends effect.Context.Service()("ryco/orchestration/Services/ProjectionSnapshotQuery") {};
|
|
28522
28631
|
//#endregion
|
|
28632
|
+
//#region src/statistics/StatisticsQuery.ts
|
|
28633
|
+
/**
|
|
28634
|
+
* StatisticsQuery - usage analytics over the orchestration projection tables.
|
|
28635
|
+
*
|
|
28636
|
+
* Aggregates the existing read models (threads, sessions, token-usage
|
|
28637
|
+
* activities, turns/checkpoints, worktrees) into a {@link StatisticsSnapshot}
|
|
28638
|
+
* on demand. No dedicated statistics tables exist; everything is derived from
|
|
28639
|
+
* data already persisted by the projection pipeline.
|
|
28640
|
+
*
|
|
28641
|
+
* Token figures use a per-turn delta attribution: for each `(thread, turn)` we
|
|
28642
|
+
* read the final `context-window.updated` activity and sum its `last*` deltas,
|
|
28643
|
+
* bucketed by day/project/model. When deltas are absent (older data / providers
|
|
28644
|
+
* that only report cumulative totals) we fall back to attributing a thread's
|
|
28645
|
+
* cumulative total to its primary model and last-activity day.
|
|
28646
|
+
*
|
|
28647
|
+
* @module StatisticsQuery
|
|
28648
|
+
*/
|
|
28649
|
+
/**
|
|
28650
|
+
* StatisticsQuery - service tag.
|
|
28651
|
+
*/
|
|
28652
|
+
var StatisticsQuery = class extends effect.Context.Service()("ryco/statistics/StatisticsQuery") {};
|
|
28653
|
+
function toPersistenceSqlOrDecodeError$7(sqlOperation, decodeOperation) {
|
|
28654
|
+
return (cause) => effect.Schema.isSchemaError(cause) ? toPersistenceDecodeError(decodeOperation)(cause) : toPersistenceSqlError(sqlOperation)(cause);
|
|
28655
|
+
}
|
|
28656
|
+
const ThreadRow = effect.Schema.Struct({
|
|
28657
|
+
threadId: effect.Schema.String,
|
|
28658
|
+
projectId: require_collectUint8StreamText.ProjectId,
|
|
28659
|
+
model: effect.Schema.NullOr(effect.Schema.String),
|
|
28660
|
+
createdAt: effect.Schema.String,
|
|
28661
|
+
providerName: effect.Schema.NullOr(effect.Schema.String)
|
|
28662
|
+
});
|
|
28663
|
+
const ProjectRow = effect.Schema.Struct({
|
|
28664
|
+
projectId: require_collectUint8StreamText.ProjectId,
|
|
28665
|
+
title: effect.Schema.String,
|
|
28666
|
+
deletedAt: effect.Schema.NullOr(effect.Schema.String)
|
|
28667
|
+
});
|
|
28668
|
+
const TokenActivityRow = effect.Schema.Struct({
|
|
28669
|
+
threadId: effect.Schema.String,
|
|
28670
|
+
turnId: effect.Schema.NullOr(effect.Schema.String),
|
|
28671
|
+
sequence: effect.Schema.NullOr(effect.Schema.Number),
|
|
28672
|
+
createdAt: effect.Schema.String,
|
|
28673
|
+
payloadJson: effect.Schema.String
|
|
28674
|
+
});
|
|
28675
|
+
const ToolUseRow = effect.Schema.Struct({
|
|
28676
|
+
threadId: effect.Schema.String,
|
|
28677
|
+
date: effect.Schema.String,
|
|
28678
|
+
count: effect.Schema.Number
|
|
28679
|
+
});
|
|
28680
|
+
const TurnRow = effect.Schema.Struct({
|
|
28681
|
+
threadId: effect.Schema.String,
|
|
28682
|
+
startedAt: effect.Schema.NullOr(effect.Schema.String),
|
|
28683
|
+
completedAt: effect.Schema.NullOr(effect.Schema.String),
|
|
28684
|
+
checkpointTurnCount: effect.Schema.NullOr(effect.Schema.Number),
|
|
28685
|
+
filesJson: effect.Schema.String
|
|
28686
|
+
});
|
|
28687
|
+
const WorktreeRow = effect.Schema.Struct({
|
|
28688
|
+
createdAt: effect.Schema.String,
|
|
28689
|
+
archivedAt: effect.Schema.NullOr(effect.Schema.String),
|
|
28690
|
+
prNumber: effect.Schema.NullOr(effect.Schema.Number)
|
|
28691
|
+
});
|
|
28692
|
+
function num(value) {
|
|
28693
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
28694
|
+
}
|
|
28695
|
+
function dayOf(iso) {
|
|
28696
|
+
return iso.length >= 10 ? iso.slice(0, 10) : null;
|
|
28697
|
+
}
|
|
28698
|
+
const makeStatisticsQuery = effect.Effect.gen(function* () {
|
|
28699
|
+
const sql = yield* effect_unstable_sql_SqlClient.SqlClient;
|
|
28700
|
+
const listThreadRows = effect_unstable_sql_SqlSchema.findAll({
|
|
28701
|
+
Request: effect.Schema.Void,
|
|
28702
|
+
Result: ThreadRow,
|
|
28703
|
+
execute: () => sql`
|
|
28704
|
+
SELECT
|
|
28705
|
+
t.thread_id AS "threadId",
|
|
28706
|
+
t.project_id AS "projectId",
|
|
28707
|
+
json_extract(t.model_selection_json, '$.model') AS "model",
|
|
28708
|
+
t.created_at AS "createdAt",
|
|
28709
|
+
COALESCE(
|
|
28710
|
+
s.provider_name,
|
|
28711
|
+
json_extract(t.model_selection_json, '$.provider')
|
|
28712
|
+
) AS "providerName"
|
|
28713
|
+
FROM projection_threads t
|
|
28714
|
+
LEFT JOIN projection_thread_sessions s ON s.thread_id = t.thread_id
|
|
28715
|
+
`
|
|
28716
|
+
});
|
|
28717
|
+
const listProjectRows = effect_unstable_sql_SqlSchema.findAll({
|
|
28718
|
+
Request: effect.Schema.Void,
|
|
28719
|
+
Result: ProjectRow,
|
|
28720
|
+
execute: () => sql`
|
|
28721
|
+
SELECT
|
|
28722
|
+
project_id AS "projectId",
|
|
28723
|
+
title,
|
|
28724
|
+
deleted_at AS "deletedAt"
|
|
28725
|
+
FROM projection_projects
|
|
28726
|
+
`
|
|
28727
|
+
});
|
|
28728
|
+
const listTokenActivityRows = effect_unstable_sql_SqlSchema.findAll({
|
|
28729
|
+
Request: effect.Schema.Void,
|
|
28730
|
+
Result: TokenActivityRow,
|
|
28731
|
+
execute: () => sql`
|
|
28732
|
+
SELECT
|
|
28733
|
+
thread_id AS "threadId",
|
|
28734
|
+
turn_id AS "turnId",
|
|
28735
|
+
sequence,
|
|
28736
|
+
created_at AS "createdAt",
|
|
28737
|
+
payload_json AS "payloadJson"
|
|
28738
|
+
FROM projection_thread_activities
|
|
28739
|
+
WHERE kind = 'context-window.updated'
|
|
28740
|
+
ORDER BY thread_id ASC, turn_id ASC, sequence ASC, created_at ASC, activity_id ASC
|
|
28741
|
+
`
|
|
28742
|
+
});
|
|
28743
|
+
const listToolUseRows = effect_unstable_sql_SqlSchema.findAll({
|
|
28744
|
+
Request: effect.Schema.Void,
|
|
28745
|
+
Result: ToolUseRow,
|
|
28746
|
+
execute: () => sql`
|
|
28747
|
+
SELECT
|
|
28748
|
+
thread_id AS "threadId",
|
|
28749
|
+
substr(created_at, 1, 10) AS "date",
|
|
28750
|
+
COUNT(*) AS "count"
|
|
28751
|
+
FROM projection_thread_activities
|
|
28752
|
+
WHERE kind = 'tool.completed'
|
|
28753
|
+
GROUP BY thread_id, substr(created_at, 1, 10)
|
|
28754
|
+
`
|
|
28755
|
+
});
|
|
28756
|
+
const listTurnRows = effect_unstable_sql_SqlSchema.findAll({
|
|
28757
|
+
Request: effect.Schema.Void,
|
|
28758
|
+
Result: TurnRow,
|
|
28759
|
+
execute: () => sql`
|
|
28760
|
+
SELECT
|
|
28761
|
+
thread_id AS "threadId",
|
|
28762
|
+
started_at AS "startedAt",
|
|
28763
|
+
completed_at AS "completedAt",
|
|
28764
|
+
checkpoint_turn_count AS "checkpointTurnCount",
|
|
28765
|
+
checkpoint_files_json AS "filesJson"
|
|
28766
|
+
FROM projection_turns
|
|
28767
|
+
`
|
|
28768
|
+
});
|
|
28769
|
+
const listWorktreeRows = effect_unstable_sql_SqlSchema.findAll({
|
|
28770
|
+
Request: effect.Schema.Void,
|
|
28771
|
+
Result: WorktreeRow,
|
|
28772
|
+
execute: () => sql`
|
|
28773
|
+
SELECT
|
|
28774
|
+
created_at AS "createdAt",
|
|
28775
|
+
archived_at AS "archivedAt",
|
|
28776
|
+
pr_number AS "prNumber"
|
|
28777
|
+
FROM projection_worktrees
|
|
28778
|
+
`
|
|
28779
|
+
});
|
|
28780
|
+
const getStatistics = () => effect.Effect.gen(function* () {
|
|
28781
|
+
const [threadRows, projectRows, tokenRows, toolRows, turnRows, worktreeRows] = yield* effect.Effect.all([
|
|
28782
|
+
listThreadRows(void 0).pipe(effect.Effect.mapError(toPersistenceSqlOrDecodeError$7("StatisticsQuery.getStatistics:listThreads:query", "StatisticsQuery.getStatistics:listThreads:decodeRows"))),
|
|
28783
|
+
listProjectRows(void 0).pipe(effect.Effect.mapError(toPersistenceSqlOrDecodeError$7("StatisticsQuery.getStatistics:listProjects:query", "StatisticsQuery.getStatistics:listProjects:decodeRows"))),
|
|
28784
|
+
listTokenActivityRows(void 0).pipe(effect.Effect.mapError(toPersistenceSqlOrDecodeError$7("StatisticsQuery.getStatistics:listTokenActivities:query", "StatisticsQuery.getStatistics:listTokenActivities:decodeRows"))),
|
|
28785
|
+
listToolUseRows(void 0).pipe(effect.Effect.mapError(toPersistenceSqlOrDecodeError$7("StatisticsQuery.getStatistics:listToolUses:query", "StatisticsQuery.getStatistics:listToolUses:decodeRows"))),
|
|
28786
|
+
listTurnRows(void 0).pipe(effect.Effect.mapError(toPersistenceSqlOrDecodeError$7("StatisticsQuery.getStatistics:listTurns:query", "StatisticsQuery.getStatistics:listTurns:decodeRows"))),
|
|
28787
|
+
listWorktreeRows(void 0).pipe(effect.Effect.mapError(toPersistenceSqlOrDecodeError$7("StatisticsQuery.getStatistics:listWorktrees:query", "StatisticsQuery.getStatistics:listWorktrees:decodeRows")))
|
|
28788
|
+
], { concurrency: "unbounded" });
|
|
28789
|
+
const threadMeta = /* @__PURE__ */ new Map();
|
|
28790
|
+
const modelProvider = /* @__PURE__ */ new Map();
|
|
28791
|
+
for (const row of threadRows) {
|
|
28792
|
+
const provider = row.providerName?.trim() || void 0;
|
|
28793
|
+
const model = (row.model ?? "").trim() || "unknown";
|
|
28794
|
+
threadMeta.set(row.threadId, {
|
|
28795
|
+
projectId: row.projectId,
|
|
28796
|
+
model,
|
|
28797
|
+
provider,
|
|
28798
|
+
createdAt: row.createdAt
|
|
28799
|
+
});
|
|
28800
|
+
if (!modelProvider.has(model) || modelProvider.get(model) === void 0 && provider) modelProvider.set(model, provider);
|
|
28801
|
+
}
|
|
28802
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
28803
|
+
const getBucket = (date, projectId, model) => {
|
|
28804
|
+
const key = `${date}${projectId}${model}`;
|
|
28805
|
+
let bucket = buckets.get(key);
|
|
28806
|
+
if (!bucket) {
|
|
28807
|
+
bucket = {
|
|
28808
|
+
date,
|
|
28809
|
+
projectId,
|
|
28810
|
+
model,
|
|
28811
|
+
provider: modelProvider.get(model),
|
|
28812
|
+
inputTokens: 0,
|
|
28813
|
+
outputTokens: 0,
|
|
28814
|
+
cachedInputTokens: 0,
|
|
28815
|
+
reasoningTokens: 0,
|
|
28816
|
+
turns: 0,
|
|
28817
|
+
activeMs: 0,
|
|
28818
|
+
toolUses: 0,
|
|
28819
|
+
filesChanged: 0,
|
|
28820
|
+
additions: 0,
|
|
28821
|
+
deletions: 0,
|
|
28822
|
+
commits: 0,
|
|
28823
|
+
pushes: 0,
|
|
28824
|
+
threadsCreated: 0
|
|
28825
|
+
};
|
|
28826
|
+
buckets.set(key, bucket);
|
|
28827
|
+
}
|
|
28828
|
+
return bucket;
|
|
28829
|
+
};
|
|
28830
|
+
let earliest;
|
|
28831
|
+
const considerIso = (iso) => {
|
|
28832
|
+
if (iso && (earliest === void 0 || iso < earliest)) earliest = iso;
|
|
28833
|
+
};
|
|
28834
|
+
const lastPerTurn = /* @__PURE__ */ new Map();
|
|
28835
|
+
const lastPerThread = /* @__PURE__ */ new Map();
|
|
28836
|
+
const isLater = (a, b) => {
|
|
28837
|
+
if (a.createdAt !== b.createdAt) return a.createdAt > b.createdAt;
|
|
28838
|
+
return (a.sequence ?? -1) >= (b.sequence ?? -1);
|
|
28839
|
+
};
|
|
28840
|
+
for (const row of tokenRows) {
|
|
28841
|
+
considerIso(row.createdAt);
|
|
28842
|
+
lastPerTurn.set(`${row.threadId}${row.turnId ?? ""}`, row);
|
|
28843
|
+
const prevThread = lastPerThread.get(row.threadId);
|
|
28844
|
+
if (!prevThread || isLater(row, prevThread)) lastPerThread.set(row.threadId, row);
|
|
28845
|
+
}
|
|
28846
|
+
let perTurnDeltaSum = 0;
|
|
28847
|
+
for (const row of lastPerTurn.values()) {
|
|
28848
|
+
const payload = safeParse(row.payloadJson);
|
|
28849
|
+
perTurnDeltaSum += num(payload?.lastInputTokens) + num(payload?.lastOutputTokens) + num(payload?.lastCachedInputTokens) + num(payload?.lastReasoningOutputTokens);
|
|
28850
|
+
}
|
|
28851
|
+
let cumulativeSum = 0;
|
|
28852
|
+
for (const row of lastPerThread.values()) {
|
|
28853
|
+
const payload = safeParse(row.payloadJson);
|
|
28854
|
+
cumulativeSum += num(payload?.inputTokens) + num(payload?.outputTokens);
|
|
28855
|
+
}
|
|
28856
|
+
const attribution = perTurnDeltaSum === 0 && cumulativeSum > 0 ? "thread-cumulative" : "per-turn-delta";
|
|
28857
|
+
if (attribution === "per-turn-delta") for (const row of lastPerTurn.values()) {
|
|
28858
|
+
const meta = threadMeta.get(row.threadId);
|
|
28859
|
+
const date = dayOf(row.createdAt);
|
|
28860
|
+
if (!meta || !date) continue;
|
|
28861
|
+
const payload = safeParse(row.payloadJson);
|
|
28862
|
+
const bucket = getBucket(date, meta.projectId, meta.model);
|
|
28863
|
+
bucket.inputTokens += num(payload?.lastInputTokens);
|
|
28864
|
+
bucket.outputTokens += num(payload?.lastOutputTokens);
|
|
28865
|
+
bucket.cachedInputTokens += num(payload?.lastCachedInputTokens);
|
|
28866
|
+
bucket.reasoningTokens += num(payload?.lastReasoningOutputTokens);
|
|
28867
|
+
}
|
|
28868
|
+
else for (const row of lastPerThread.values()) {
|
|
28869
|
+
const meta = threadMeta.get(row.threadId);
|
|
28870
|
+
const date = dayOf(row.createdAt);
|
|
28871
|
+
if (!meta || !date) continue;
|
|
28872
|
+
const payload = safeParse(row.payloadJson);
|
|
28873
|
+
const bucket = getBucket(date, meta.projectId, meta.model);
|
|
28874
|
+
bucket.inputTokens += num(payload?.inputTokens);
|
|
28875
|
+
bucket.outputTokens += num(payload?.outputTokens);
|
|
28876
|
+
bucket.cachedInputTokens += num(payload?.cachedInputTokens);
|
|
28877
|
+
bucket.reasoningTokens += num(payload?.reasoningOutputTokens);
|
|
28878
|
+
}
|
|
28879
|
+
for (const row of turnRows) {
|
|
28880
|
+
const meta = threadMeta.get(row.threadId);
|
|
28881
|
+
if (!meta) continue;
|
|
28882
|
+
considerIso(row.startedAt);
|
|
28883
|
+
considerIso(row.completedAt);
|
|
28884
|
+
const anchor = row.completedAt ?? row.startedAt;
|
|
28885
|
+
const date = anchor ? dayOf(anchor) : null;
|
|
28886
|
+
if (!date) continue;
|
|
28887
|
+
const bucket = getBucket(date, meta.projectId, meta.model);
|
|
28888
|
+
if (row.completedAt) {
|
|
28889
|
+
bucket.turns += 1;
|
|
28890
|
+
if (row.startedAt) {
|
|
28891
|
+
const delta = Date.parse(row.completedAt) - Date.parse(row.startedAt);
|
|
28892
|
+
if (Number.isFinite(delta) && delta > 0) bucket.activeMs += delta;
|
|
28893
|
+
}
|
|
28894
|
+
}
|
|
28895
|
+
const files = safeParseArray(row.filesJson);
|
|
28896
|
+
if (files.length > 0) {
|
|
28897
|
+
bucket.filesChanged += files.length;
|
|
28898
|
+
for (const file of files) {
|
|
28899
|
+
bucket.additions += num(file?.additions);
|
|
28900
|
+
bucket.deletions += num(file?.deletions);
|
|
28901
|
+
}
|
|
28902
|
+
}
|
|
28903
|
+
}
|
|
28904
|
+
for (const row of toolRows) {
|
|
28905
|
+
const meta = threadMeta.get(row.threadId);
|
|
28906
|
+
if (!meta) continue;
|
|
28907
|
+
const bucket = getBucket(row.date, meta.projectId, meta.model);
|
|
28908
|
+
bucket.toolUses += num(row.count);
|
|
28909
|
+
}
|
|
28910
|
+
for (const meta of threadMeta.values()) {
|
|
28911
|
+
considerIso(meta.createdAt);
|
|
28912
|
+
const date = dayOf(meta.createdAt);
|
|
28913
|
+
if (!date) continue;
|
|
28914
|
+
getBucket(date, meta.projectId, meta.model).threadsCreated += 1;
|
|
28915
|
+
}
|
|
28916
|
+
let wtCreated = 0;
|
|
28917
|
+
let wtArchived = 0;
|
|
28918
|
+
let wtOpenPrs = 0;
|
|
28919
|
+
for (const row of worktreeRows) {
|
|
28920
|
+
considerIso(row.createdAt);
|
|
28921
|
+
wtCreated += 1;
|
|
28922
|
+
if (row.archivedAt) wtArchived += 1;
|
|
28923
|
+
else if (row.prNumber !== null) wtOpenPrs += 1;
|
|
28924
|
+
}
|
|
28925
|
+
const dailyBuckets = [];
|
|
28926
|
+
const totals = {
|
|
28927
|
+
inputTokens: 0,
|
|
28928
|
+
outputTokens: 0,
|
|
28929
|
+
cachedInputTokens: 0,
|
|
28930
|
+
reasoningTokens: 0,
|
|
28931
|
+
totalTokens: 0,
|
|
28932
|
+
turns: 0,
|
|
28933
|
+
activeMs: 0,
|
|
28934
|
+
toolUses: 0,
|
|
28935
|
+
filesChanged: 0,
|
|
28936
|
+
additions: 0,
|
|
28937
|
+
deletions: 0,
|
|
28938
|
+
commits: 0,
|
|
28939
|
+
pushes: 0,
|
|
28940
|
+
threads: threadMeta.size,
|
|
28941
|
+
projects: 0
|
|
28942
|
+
};
|
|
28943
|
+
for (const bucket of buckets.values()) {
|
|
28944
|
+
const { provider, ...rest } = bucket;
|
|
28945
|
+
dailyBuckets.push(provider ? {
|
|
28946
|
+
...rest,
|
|
28947
|
+
provider
|
|
28948
|
+
} : rest);
|
|
28949
|
+
totals.inputTokens += bucket.inputTokens;
|
|
28950
|
+
totals.outputTokens += bucket.outputTokens;
|
|
28951
|
+
totals.cachedInputTokens += bucket.cachedInputTokens;
|
|
28952
|
+
totals.reasoningTokens += bucket.reasoningTokens;
|
|
28953
|
+
totals.turns += bucket.turns;
|
|
28954
|
+
totals.activeMs += bucket.activeMs;
|
|
28955
|
+
totals.toolUses += bucket.toolUses;
|
|
28956
|
+
totals.filesChanged += bucket.filesChanged;
|
|
28957
|
+
totals.additions += bucket.additions;
|
|
28958
|
+
totals.deletions += bucket.deletions;
|
|
28959
|
+
totals.commits += bucket.commits;
|
|
28960
|
+
totals.pushes += bucket.pushes;
|
|
28961
|
+
}
|
|
28962
|
+
totals.totalTokens = totals.inputTokens + totals.outputTokens;
|
|
28963
|
+
const projectTitle = /* @__PURE__ */ new Map();
|
|
28964
|
+
for (const row of projectRows) projectTitle.set(row.projectId, row.title);
|
|
28965
|
+
const projectIdsInData = /* @__PURE__ */ new Set();
|
|
28966
|
+
for (const meta of threadMeta.values()) projectIdsInData.add(meta.projectId);
|
|
28967
|
+
for (const bucket of buckets.values()) projectIdsInData.add(bucket.projectId);
|
|
28968
|
+
totals.projects = projectIdsInData.size;
|
|
28969
|
+
const projects = [...projectIdsInData].map((id) => ({
|
|
28970
|
+
id,
|
|
28971
|
+
title: projectTitle.get(id)?.trim() || id
|
|
28972
|
+
}));
|
|
28973
|
+
const models = [...modelProvider].map(([model, provider]) => provider ? {
|
|
28974
|
+
model,
|
|
28975
|
+
provider
|
|
28976
|
+
} : { model });
|
|
28977
|
+
return {
|
|
28978
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
28979
|
+
...earliest ? { earliestActivityAt: earliest } : {},
|
|
28980
|
+
projects,
|
|
28981
|
+
models,
|
|
28982
|
+
dailyBuckets,
|
|
28983
|
+
worktrees: {
|
|
28984
|
+
created: wtCreated,
|
|
28985
|
+
archived: wtArchived,
|
|
28986
|
+
active: wtCreated - wtArchived,
|
|
28987
|
+
openPrs: wtOpenPrs
|
|
28988
|
+
},
|
|
28989
|
+
totals,
|
|
28990
|
+
tokenAttribution: attribution
|
|
28991
|
+
};
|
|
28992
|
+
});
|
|
28993
|
+
return { getStatistics };
|
|
28994
|
+
});
|
|
28995
|
+
function safeParse(json) {
|
|
28996
|
+
try {
|
|
28997
|
+
const parsed = JSON.parse(json);
|
|
28998
|
+
return parsed && typeof parsed === "object" ? parsed : null;
|
|
28999
|
+
} catch {
|
|
29000
|
+
return null;
|
|
29001
|
+
}
|
|
29002
|
+
}
|
|
29003
|
+
function safeParseArray(json) {
|
|
29004
|
+
try {
|
|
29005
|
+
const parsed = JSON.parse(json);
|
|
29006
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
29007
|
+
} catch {
|
|
29008
|
+
return [];
|
|
29009
|
+
}
|
|
29010
|
+
}
|
|
29011
|
+
const StatisticsQueryLive = effect.Layer.effect(StatisticsQuery, makeStatisticsQuery);
|
|
29012
|
+
//#endregion
|
|
28523
29013
|
//#region src/serverLifecycleEvents.ts
|
|
28524
29014
|
var ServerLifecycleEvents = class extends effect.Context.Service()("ryco/serverLifecycleEvents") {};
|
|
28525
29015
|
const ServerLifecycleEventsLive = effect.Layer.effect(ServerLifecycleEvents, effect.Effect.gen(function* () {
|
|
@@ -30409,7 +30899,8 @@ const makeGitManager = effect.Effect.fn("makeGitManager")(function* () {
|
|
|
30409
30899
|
isDefaultRef: details.isDefaultBranch,
|
|
30410
30900
|
refName: details.branch,
|
|
30411
30901
|
hasWorkingTreeChanges: details.hasWorkingTreeChanges,
|
|
30412
|
-
workingTree: details.workingTree
|
|
30902
|
+
workingTree: details.workingTree,
|
|
30903
|
+
...details.committed ? { committed: details.committed } : {}
|
|
30413
30904
|
};
|
|
30414
30905
|
});
|
|
30415
30906
|
const localStatusResultCache = yield* effect.Cache.makeWith(readLocalStatus, {
|
|
@@ -32543,6 +33034,8 @@ const layer = effect.Layer.effect(JiraWorkItemService, make$5());
|
|
|
32543
33034
|
//#region src/remote/Services/AdvertisedEndpointRegistry.ts
|
|
32544
33035
|
var AdvertisedEndpointRegistry = class extends effect.Context.Service()("ryco/remote/Services/AdvertisedEndpointRegistry") {};
|
|
32545
33036
|
const ORCHESTRATION_REPLAY_PAGE_MAX_LIMIT = 1e3;
|
|
33037
|
+
const ORCHESTRATION_LEGACY_REPLAY_MAX_EVENTS = ORCHESTRATION_REPLAY_PAGE_MAX_LIMIT;
|
|
33038
|
+
const ORCHESTRATION_LIVE_QUEUE_MAX_EVENTS = 1e3;
|
|
32546
33039
|
//#endregion
|
|
32547
33040
|
//#region src/ws/context/gitErrors.ts
|
|
32548
33041
|
function gitErrorText(error) {
|
|
@@ -32576,6 +33069,10 @@ const failGitWorkflow = (operation, detail, cause) => effect.Effect.fail(toGitMa
|
|
|
32576
33069
|
const wsOrchestrationReplayDepth = effect.Metric.gauge("t3_ws_orchestration_replay_depth", { description: "Current persisted orchestration event replay depth for a replayable WebSocket subscription." });
|
|
32577
33070
|
const wsOrchestrationLiveBufferDepth = effect.Metric.gauge("t3_ws_orchestration_live_buffer_depth", { description: "Current live orchestration event buffer depth for a replayable WebSocket subscription." });
|
|
32578
33071
|
const wsOrchestrationLiveBufferHighWater = effect.Metric.gauge("t3_ws_orchestration_live_buffer_high_water", { description: "Highest observed live orchestration event buffer depth for a replayable WebSocket subscription." });
|
|
33072
|
+
const wsOrchestrationLiveBufferOverflowsTotal = effect.Metric.counter("t3_ws_orchestration_live_buffer_overflows_total", {
|
|
33073
|
+
description: "Total live orchestration event buffer overflows that forced replayable WebSocket subscription resync.",
|
|
33074
|
+
incremental: true
|
|
33075
|
+
});
|
|
32579
33076
|
const wsOrchestrationReplayLag = effect.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." });
|
|
32580
33077
|
const normalizeSequence = (sequence) => Number.isFinite(sequence) ? Math.max(0, Math.floor(sequence)) : 0;
|
|
32581
33078
|
const updateGauge$1 = (metric, attributes, value) => effect.Metric.update(effect.Metric.withAttributes(metric, attributes), value);
|
|
@@ -32613,6 +33110,18 @@ const makeWsReplayMetrics = (input) => effect.Effect.gen(function* () {
|
|
|
32613
33110
|
yield* recordLiveBuffer(yield* effect.Ref.updateAndGet(liveBufferDepth, (current) => Math.max(0, current - 1)), yield* effect.Ref.get(liveBufferHighWater));
|
|
32614
33111
|
yield* markDrained(sequence);
|
|
32615
33112
|
}),
|
|
33113
|
+
recordLiveOverflow: (sequence, capacity) => effect.Effect.gen(function* () {
|
|
33114
|
+
const normalizedSequence = normalizeSequence(sequence);
|
|
33115
|
+
const normalizedCapacity = Math.max(0, Math.floor(capacity));
|
|
33116
|
+
yield* effect.Ref.update(latestLiveSequence, (current) => Math.max(current, normalizedSequence));
|
|
33117
|
+
yield* effect.Ref.set(liveBufferDepth, normalizedCapacity);
|
|
33118
|
+
const highWater = yield* effect.Ref.updateAndGet(liveBufferHighWater, (current) => Math.max(current, normalizedCapacity));
|
|
33119
|
+
yield* effect.Effect.all([
|
|
33120
|
+
recordLiveBuffer(normalizedCapacity, highWater),
|
|
33121
|
+
updateGauge$1(wsOrchestrationLiveBufferOverflowsTotal, attributes, 1),
|
|
33122
|
+
recordLag
|
|
33123
|
+
], { discard: true });
|
|
33124
|
+
}),
|
|
32616
33125
|
reset: effect.Effect.all([
|
|
32617
33126
|
updateGauge$1(wsOrchestrationReplayDepth, attributes, 0),
|
|
32618
33127
|
updateGauge$1(wsOrchestrationLiveBufferDepth, attributes, 0),
|
|
@@ -32663,6 +33172,29 @@ const buildWorkItemBranchNameMessage = (input) => {
|
|
|
32663
33172
|
};
|
|
32664
33173
|
//#endregion
|
|
32665
33174
|
//#region src/ws/context/orchestrationStreams.ts
|
|
33175
|
+
const makeLiveQueueOverflowError = (input) => new require_collectUint8StreamText.OrchestrationGetSnapshotError({
|
|
33176
|
+
message: `Orchestration ${input.stream} live event queue overflowed; reconnect to resynchronize`,
|
|
33177
|
+
cause: /* @__PURE__ */ new Error(`orchestration ${input.stream} live queue overflow at sequence ${input.sequence} with capacity ${input.capacity}`)
|
|
33178
|
+
});
|
|
33179
|
+
const offerOrchestrationLiveEventOrFail = (input) => effect.Effect.gen(function* () {
|
|
33180
|
+
const capacity = input.capacity ?? 1e3;
|
|
33181
|
+
if (effect.Queue.offerUnsafe(input.liveQueue, input.event)) {
|
|
33182
|
+
yield* input.replayMetrics.recordLiveEnqueued(input.event.sequence);
|
|
33183
|
+
return;
|
|
33184
|
+
}
|
|
33185
|
+
if (!(yield* effect.Ref.modify(input.overflowedRef, (overflowed) => [!overflowed, true]))) return;
|
|
33186
|
+
yield* input.replayMetrics.recordLiveOverflow(input.event.sequence, capacity);
|
|
33187
|
+
yield* effect.Effect.logWarning("orchestration live stream queue overflow; forcing resync", {
|
|
33188
|
+
stream: input.stream,
|
|
33189
|
+
sequence: input.event.sequence,
|
|
33190
|
+
capacity
|
|
33191
|
+
});
|
|
33192
|
+
yield* effect.Queue.fail(input.liveQueue, makeLiveQueueOverflowError({
|
|
33193
|
+
stream: input.stream,
|
|
33194
|
+
sequence: input.event.sequence,
|
|
33195
|
+
capacity
|
|
33196
|
+
}));
|
|
33197
|
+
});
|
|
32666
33198
|
const makeOrchestrationStreamHelpers = (deps) => {
|
|
32667
33199
|
const { orchestrationEngine, projectionSnapshotQuery, repositoryIdentityResolver } = deps;
|
|
32668
33200
|
const enrichProjectEvent = (event) => {
|
|
@@ -32782,8 +33314,9 @@ const makeOrchestrationStreamHelpers = (deps) => {
|
|
|
32782
33314
|
const loadedSnapshot = yield* snapshot;
|
|
32783
33315
|
const snapshotSequence = loadedSnapshot.snapshotSequence;
|
|
32784
33316
|
const liveSubscription = yield* orchestrationEngine.subscribeDomainEvents;
|
|
32785
|
-
const liveQueue = yield* effect.Queue.
|
|
33317
|
+
const liveQueue = yield* effect.Queue.bounded(ORCHESTRATION_LIVE_QUEUE_MAX_EVENTS);
|
|
32786
33318
|
const lastSequenceRef = yield* effect.Ref.make(snapshotSequence);
|
|
33319
|
+
const overflowedRef = yield* effect.Ref.make(false);
|
|
32787
33320
|
const replayBoundary = yield* makeReplayBoundaryTracker(snapshotSequence);
|
|
32788
33321
|
const replayMetrics = yield* makeWsReplayMetrics({
|
|
32789
33322
|
stream: "shell",
|
|
@@ -32792,8 +33325,13 @@ const makeOrchestrationStreamHelpers = (deps) => {
|
|
|
32792
33325
|
});
|
|
32793
33326
|
yield* effect.Stream.fromSubscription(liveSubscription).pipe(effect.Stream.runForEach((event) => effect.Effect.gen(function* () {
|
|
32794
33327
|
yield* replayBoundary.recordLiveSequence(event.sequence);
|
|
32795
|
-
yield*
|
|
32796
|
-
|
|
33328
|
+
yield* offerOrchestrationLiveEventOrFail({
|
|
33329
|
+
stream: "shell",
|
|
33330
|
+
event,
|
|
33331
|
+
liveQueue,
|
|
33332
|
+
overflowedRef,
|
|
33333
|
+
replayMetrics
|
|
33334
|
+
});
|
|
32797
33335
|
})), effect.Effect.ensuring(effect.Queue.shutdown(liveQueue)), effect.Effect.ignoreCause({ log: true }), effect.Effect.forkScoped);
|
|
32798
33336
|
const replayStream = makeBoundedReplayStream({
|
|
32799
33337
|
snapshotSequence,
|
|
@@ -32811,8 +33349,9 @@ const makeOrchestrationStreamHelpers = (deps) => {
|
|
|
32811
33349
|
const loadedSnapshot = yield* snapshot;
|
|
32812
33350
|
const snapshotSequence = loadedSnapshot.snapshotSequence;
|
|
32813
33351
|
const liveSubscription = yield* orchestrationEngine.subscribeDomainEvents;
|
|
32814
|
-
const liveQueue = yield* effect.Queue.
|
|
33352
|
+
const liveQueue = yield* effect.Queue.bounded(ORCHESTRATION_LIVE_QUEUE_MAX_EVENTS);
|
|
32815
33353
|
const lastSequenceRef = yield* effect.Ref.make(snapshotSequence);
|
|
33354
|
+
const overflowedRef = yield* effect.Ref.make(false);
|
|
32816
33355
|
const replayBoundary = yield* makeReplayBoundaryTracker(snapshotSequence);
|
|
32817
33356
|
const replayMetrics = yield* makeWsReplayMetrics({
|
|
32818
33357
|
stream: "thread",
|
|
@@ -32825,8 +33364,13 @@ const makeOrchestrationStreamHelpers = (deps) => {
|
|
|
32825
33364
|
})));
|
|
32826
33365
|
yield* effect.Stream.fromSubscription(liveSubscription).pipe(effect.Stream.runForEach((event) => effect.Effect.gen(function* () {
|
|
32827
33366
|
yield* replayBoundary.recordLiveSequence(event.sequence);
|
|
32828
|
-
yield*
|
|
32829
|
-
|
|
33367
|
+
yield* offerOrchestrationLiveEventOrFail({
|
|
33368
|
+
stream: "thread",
|
|
33369
|
+
event,
|
|
33370
|
+
liveQueue,
|
|
33371
|
+
overflowedRef,
|
|
33372
|
+
replayMetrics
|
|
33373
|
+
});
|
|
32830
33374
|
})), effect.Effect.ensuring(effect.Queue.shutdown(liveQueue)), effect.Effect.ignoreCause({ log: true }), effect.Effect.forkScoped);
|
|
32831
33375
|
const replayStream = makeBoundedReplayStream({
|
|
32832
33376
|
snapshotSequence,
|
|
@@ -33367,6 +33911,7 @@ function toDiagnosticsProviderProcess(provider) {
|
|
|
33367
33911
|
const makeWsRpcContext = (session) => effect.Effect.gen(function* () {
|
|
33368
33912
|
const currentSessionId = session.sessionId;
|
|
33369
33913
|
const projectionSnapshotQuery = yield* ProjectionSnapshotQuery;
|
|
33914
|
+
const statisticsQuery = yield* StatisticsQuery;
|
|
33370
33915
|
const orchestrationEngine = yield* OrchestrationEngineService;
|
|
33371
33916
|
const checkpointDiffQuery = yield* CheckpointDiffQuery;
|
|
33372
33917
|
const keybindings = yield* Keybindings;
|
|
@@ -33690,6 +34235,7 @@ const makeWsRpcContext = (session) => effect.Effect.gen(function* () {
|
|
|
33690
34235
|
return {
|
|
33691
34236
|
currentSessionId,
|
|
33692
34237
|
projectionSnapshotQuery,
|
|
34238
|
+
statisticsQuery,
|
|
33693
34239
|
orchestrationEngine,
|
|
33694
34240
|
checkpointDiffQuery,
|
|
33695
34241
|
keybindings,
|
|
@@ -33967,9 +34513,9 @@ function recordServerPerfPayload(label, value, record) {
|
|
|
33967
34513
|
//#endregion
|
|
33968
34514
|
//#region src/ws/orchestrationRpc.ts
|
|
33969
34515
|
const makeOrchestrationHandlers = (ctx) => {
|
|
33970
|
-
const {
|
|
34516
|
+
const { ownerEffect, projectionSnapshotQuery, dispatchNormalizedCommand, dispatchWorktreeCommand, serverCommandId, terminalManager, checkpointDiffQuery, orchestrationEngine, enrichOrchestrationEvents, makeReplayableShellStream, makeReplayableThreadStream } = ctx;
|
|
33971
34517
|
return defineWsHandlers({
|
|
33972
|
-
[require_collectUint8StreamText.ORCHESTRATION_WS_METHODS.dispatchCommand]: (command) => observeRpcEffect(require_collectUint8StreamText.ORCHESTRATION_WS_METHODS.dispatchCommand,
|
|
34518
|
+
[require_collectUint8StreamText.ORCHESTRATION_WS_METHODS.dispatchCommand]: (command) => observeRpcEffect(require_collectUint8StreamText.ORCHESTRATION_WS_METHODS.dispatchCommand, ownerEffect(require_collectUint8StreamText.ORCHESTRATION_WS_METHODS.dispatchCommand, effect.Effect.gen(function* () {
|
|
33973
34519
|
const normalizedCommand = yield* normalizeDispatchCommand(command);
|
|
33974
34520
|
const shouldStopSessionAfterArchive = normalizedCommand.type === "thread.archive" ? yield* projectionSnapshotQuery.getThreadShellById(normalizedCommand.threadId).pipe(effect.Effect.map(effect.Option.match({
|
|
33975
34521
|
onNone: () => false,
|
|
@@ -34009,7 +34555,7 @@ const makeOrchestrationHandlers = (ctx) => {
|
|
|
34009
34555
|
[require_collectUint8StreamText.ORCHESTRATION_WS_METHODS.replayEvents]: (input) => observeRpcEffect(require_collectUint8StreamText.ORCHESTRATION_WS_METHODS.replayEvents, effect.Stream.runCollect(orchestrationEngine.readEvents((0, effect_Number.clamp)(input.fromSequenceExclusive, {
|
|
34010
34556
|
maximum: Number.MAX_SAFE_INTEGER,
|
|
34011
34557
|
minimum: 0
|
|
34012
|
-
}))).pipe(effect.Effect.map((events) => Array.from(events)), effect.Effect.flatMap(enrichOrchestrationEvents), effect.Effect.mapError((cause) => new require_collectUint8StreamText.OrchestrationReplayEventsError({
|
|
34558
|
+
}), ORCHESTRATION_LEGACY_REPLAY_MAX_EVENTS)).pipe(effect.Effect.map((events) => Array.from(events)), effect.Effect.flatMap(enrichOrchestrationEvents), effect.Effect.mapError((cause) => new require_collectUint8StreamText.OrchestrationReplayEventsError({
|
|
34013
34559
|
message: "Failed to replay orchestration events",
|
|
34014
34560
|
cause
|
|
34015
34561
|
}))), { "rpc.aggregate": "orchestration" }),
|
|
@@ -34140,10 +34686,25 @@ const makeTerminalHandlers = (ctx) => {
|
|
|
34140
34686
|
[require_collectUint8StreamText.WS_METHODS.terminalClear]: (input) => observeRpcEffect(require_collectUint8StreamText.WS_METHODS.terminalClear, ownerEffect(require_collectUint8StreamText.WS_METHODS.terminalClear, terminalManager.clear(input)), { "rpc.aggregate": "terminal" }),
|
|
34141
34687
|
[require_collectUint8StreamText.WS_METHODS.terminalRestart]: (input) => observeRpcEffect(require_collectUint8StreamText.WS_METHODS.terminalRestart, ownerEffect(require_collectUint8StreamText.WS_METHODS.terminalRestart, terminalManager.restart(input)), { "rpc.aggregate": "terminal" }),
|
|
34142
34688
|
[require_collectUint8StreamText.WS_METHODS.terminalClose]: (input) => observeRpcEffect(require_collectUint8StreamText.WS_METHODS.terminalClose, ownerEffect(require_collectUint8StreamText.WS_METHODS.terminalClose, terminalManager.close(input)), { "rpc.aggregate": "terminal" }),
|
|
34143
|
-
[require_collectUint8StreamText.WS_METHODS.subscribeTerminalEvents]: (_input) => observeRpcStream(require_collectUint8StreamText.WS_METHODS.subscribeTerminalEvents, ownerStream(require_collectUint8StreamText.WS_METHODS.subscribeTerminalEvents, effect.Stream.callback((queue) => effect.Effect.acquireRelease(
|
|
34144
|
-
|
|
34145
|
-
|
|
34146
|
-
|
|
34689
|
+
[require_collectUint8StreamText.WS_METHODS.subscribeTerminalEvents]: (_input) => observeRpcStream(require_collectUint8StreamText.WS_METHODS.subscribeTerminalEvents, ownerStream(require_collectUint8StreamText.WS_METHODS.subscribeTerminalEvents, effect.Stream.callback((queue) => effect.Effect.acquireRelease(effect.Effect.gen(function* () {
|
|
34690
|
+
const unsubscribe = yield* terminalManager.subscribe((event) => effect.Effect.gen(function* () {
|
|
34691
|
+
recordServerPerfPayload("server.ws.terminal.events", event);
|
|
34692
|
+
yield* effect.Queue.offer(queue, event);
|
|
34693
|
+
}));
|
|
34694
|
+
const snapshots = yield* terminalManager.listSessions;
|
|
34695
|
+
yield* effect.Effect.forEach(snapshots.filter((snapshot) => snapshot.status === "running"), (snapshot) => {
|
|
34696
|
+
const event = {
|
|
34697
|
+
type: "started",
|
|
34698
|
+
threadId: snapshot.threadId,
|
|
34699
|
+
terminalId: snapshot.terminalId,
|
|
34700
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
34701
|
+
snapshot
|
|
34702
|
+
};
|
|
34703
|
+
recordServerPerfPayload("server.ws.terminal.events", event);
|
|
34704
|
+
return effect.Queue.offer(queue, event);
|
|
34705
|
+
}, { discard: true });
|
|
34706
|
+
return unsubscribe;
|
|
34707
|
+
}), (unsubscribe) => effect.Effect.sync(unsubscribe)))), { "rpc.aggregate": "terminal" })
|
|
34147
34708
|
});
|
|
34148
34709
|
};
|
|
34149
34710
|
//#endregion
|
|
@@ -34238,7 +34799,7 @@ const makeSourceControlHandlers = (ctx) => {
|
|
|
34238
34799
|
cwd,
|
|
34239
34800
|
reason: "sourceControl.searchIssues"
|
|
34240
34801
|
})))), { "rpc.aggregate": "source-control" }),
|
|
34241
|
-
[require_collectUint8StreamText.WS_METHODS.sourceControlListChangeRequests]: ({ cwd, state, limit, query }) => observeRpcEffect(require_collectUint8StreamText.WS_METHODS.sourceControlListChangeRequests, sourceControlRegistry.resolve({ cwd }).pipe(effect.Effect.flatMap((provider) => {
|
|
34802
|
+
[require_collectUint8StreamText.WS_METHODS.sourceControlListChangeRequests]: ({ cwd, state, limit, query }) => observeRpcEffect(require_collectUint8StreamText.WS_METHODS.sourceControlListChangeRequests, ownerEffect(require_collectUint8StreamText.WS_METHODS.sourceControlListChangeRequests, sourceControlRegistry.resolve({ cwd }).pipe(effect.Effect.flatMap((provider) => {
|
|
34242
34803
|
const trimmedQuery = query?.trim() ?? "";
|
|
34243
34804
|
if (trimmedQuery.length > 0) return provider.searchChangeRequests({
|
|
34244
34805
|
cwd,
|
|
@@ -34254,7 +34815,7 @@ const makeSourceControlHandlers = (ctx) => {
|
|
|
34254
34815
|
}), effect.Effect.tap(() => refreshLinkedWorktreeSourceControlStates({
|
|
34255
34816
|
cwd,
|
|
34256
34817
|
reason: "sourceControl.listChangeRequests"
|
|
34257
|
-
}))), { "rpc.aggregate": "source-control" }),
|
|
34818
|
+
})))), { "rpc.aggregate": "source-control" }),
|
|
34258
34819
|
[require_collectUint8StreamText.WS_METHODS.sourceControlSearchChangeRequests]: ({ cwd, query, limit }) => observeRpcEffect(require_collectUint8StreamText.WS_METHODS.sourceControlSearchChangeRequests, ownerEffect(require_collectUint8StreamText.WS_METHODS.sourceControlSearchChangeRequests, sourceControlRegistry.resolve({ cwd }).pipe(effect.Effect.flatMap((provider) => provider.searchChangeRequests({
|
|
34259
34820
|
cwd,
|
|
34260
34821
|
query,
|
|
@@ -35004,12 +35565,19 @@ const makeProviderHandlers = (ctx) => {
|
|
|
35004
35565
|
});
|
|
35005
35566
|
};
|
|
35006
35567
|
//#endregion
|
|
35568
|
+
//#region src/ws/statisticsRpc.ts
|
|
35569
|
+
const makeStatisticsHandlers = (ctx) => {
|
|
35570
|
+
const { statisticsQuery, ownerEffect } = ctx;
|
|
35571
|
+
return defineWsHandlers({ [require_collectUint8StreamText.WS_METHODS.serverGetStatistics]: (_input) => observeRpcEffect(require_collectUint8StreamText.WS_METHODS.serverGetStatistics, ownerEffect(require_collectUint8StreamText.WS_METHODS.serverGetStatistics, statisticsQuery.getStatistics().pipe(effect.Effect.orDie)), { "rpc.aggregate": "server" }) });
|
|
35572
|
+
};
|
|
35573
|
+
//#endregion
|
|
35007
35574
|
//#region src/ws/index.ts
|
|
35008
35575
|
const makeWsRpcLayer = (session) => require_collectUint8StreamText.WsRpcGroup.toLayer(effect.Effect.gen(function* () {
|
|
35009
35576
|
const ctx = yield* makeWsRpcContext(session);
|
|
35010
35577
|
return require_collectUint8StreamText.WsRpcGroup.of({
|
|
35011
35578
|
...makeOrchestrationHandlers(ctx),
|
|
35012
35579
|
...makeProviderHandlers(ctx),
|
|
35580
|
+
...makeStatisticsHandlers(ctx),
|
|
35013
35581
|
...makeSourceControlHandlers(ctx),
|
|
35014
35582
|
...makeProjectHandlers(ctx),
|
|
35015
35583
|
...makeGitHandlers(ctx),
|
|
@@ -37427,6 +37995,8 @@ const DEFAULT_PERSIST_DEBOUNCE_MS = 40;
|
|
|
37427
37995
|
const DEFAULT_SUBPROCESS_POLL_INTERVAL_MS = 1e3;
|
|
37428
37996
|
const DEFAULT_PROCESS_KILL_GRACE_MS = 1e3;
|
|
37429
37997
|
const DEFAULT_MAX_RETAINED_INACTIVE_SESSIONS = 128;
|
|
37998
|
+
const DEFAULT_MAX_PENDING_PROCESS_EVENTS = 2048;
|
|
37999
|
+
const DEFAULT_MAX_PENDING_PROCESS_OUTPUT_BYTES = 2 * 1024 * 1024;
|
|
37430
38000
|
const DEFAULT_OPEN_COLS = 120;
|
|
37431
38001
|
const DEFAULT_OPEN_ROWS = 30;
|
|
37432
38002
|
const TERMINAL_ENV_BLOCKLIST = new Set([
|
|
@@ -37483,13 +38053,86 @@ function cleanupProcessHandles(session) {
|
|
|
37483
38053
|
session.unsubscribeExit?.();
|
|
37484
38054
|
session.unsubscribeExit = null;
|
|
37485
38055
|
}
|
|
37486
|
-
function
|
|
38056
|
+
function clearPendingProcessEvents(session) {
|
|
38057
|
+
session.pendingProcessEvents = [];
|
|
38058
|
+
session.pendingProcessEventIndex = 0;
|
|
38059
|
+
session.pendingProcessOutputBytes = 0;
|
|
38060
|
+
session.processEventDrainRunning = false;
|
|
38061
|
+
}
|
|
38062
|
+
function enqueueProcessEvent(session, expectedPid, event, limits) {
|
|
37487
38063
|
if (!session.process || session.status !== "running" || session.pid !== expectedPid) return false;
|
|
38064
|
+
if (event.type === "output" && session.pendingProcessEvents.some((pendingEvent) => pendingEvent.type === "exit")) return false;
|
|
38065
|
+
compactPendingProcessEvents(session);
|
|
37488
38066
|
session.pendingProcessEvents.push(event);
|
|
38067
|
+
if (event.type === "output") session.pendingProcessOutputBytes += event.byteLength;
|
|
38068
|
+
enforcePendingProcessEventLimits(session, limits);
|
|
37489
38069
|
if (session.processEventDrainRunning) return false;
|
|
37490
38070
|
session.processEventDrainRunning = true;
|
|
37491
38071
|
return true;
|
|
37492
38072
|
}
|
|
38073
|
+
function compactPendingProcessEvents(session) {
|
|
38074
|
+
if (session.pendingProcessEventIndex <= 0) return;
|
|
38075
|
+
session.pendingProcessEvents = session.pendingProcessEvents.slice(session.pendingProcessEventIndex);
|
|
38076
|
+
session.pendingProcessEventIndex = 0;
|
|
38077
|
+
}
|
|
38078
|
+
function coalesceOldestPendingOutputPair(session) {
|
|
38079
|
+
for (let index = 0; index < session.pendingProcessEvents.length - 1; index += 1) {
|
|
38080
|
+
const current = session.pendingProcessEvents[index];
|
|
38081
|
+
const next = session.pendingProcessEvents[index + 1];
|
|
38082
|
+
if (current?.type !== "output" || next?.type !== "output") continue;
|
|
38083
|
+
session.pendingProcessEvents.splice(index, 2, {
|
|
38084
|
+
type: "output",
|
|
38085
|
+
data: `${current.data}${next.data}`,
|
|
38086
|
+
byteLength: current.byteLength + next.byteLength
|
|
38087
|
+
});
|
|
38088
|
+
return true;
|
|
38089
|
+
}
|
|
38090
|
+
return false;
|
|
38091
|
+
}
|
|
38092
|
+
function trimOutputDataToApproxBytes(data, maxBytes) {
|
|
38093
|
+
if (maxBytes <= 0 || data.length === 0) return {
|
|
38094
|
+
data: "",
|
|
38095
|
+
byteLength: 0
|
|
38096
|
+
};
|
|
38097
|
+
let nextData = data;
|
|
38098
|
+
let byteLength = approximateTextBytes(nextData);
|
|
38099
|
+
while (byteLength > maxBytes && nextData.length > 0) {
|
|
38100
|
+
const excessBytes = byteLength - maxBytes;
|
|
38101
|
+
const sliceStart = Math.min(nextData.length, Math.max(1, excessBytes));
|
|
38102
|
+
nextData = nextData.slice(sliceStart);
|
|
38103
|
+
byteLength = approximateTextBytes(nextData);
|
|
38104
|
+
}
|
|
38105
|
+
return {
|
|
38106
|
+
data: nextData,
|
|
38107
|
+
byteLength
|
|
38108
|
+
};
|
|
38109
|
+
}
|
|
38110
|
+
function trimPendingOutputBytesToLimit(session, maxPendingProcessOutputBytes) {
|
|
38111
|
+
if (session.pendingProcessOutputBytes <= maxPendingProcessOutputBytes) return;
|
|
38112
|
+
for (let index = 0; index < session.pendingProcessEvents.length; index += 1) {
|
|
38113
|
+
if (session.pendingProcessOutputBytes <= maxPendingProcessOutputBytes) return;
|
|
38114
|
+
const event = session.pendingProcessEvents[index];
|
|
38115
|
+
if (event?.type !== "output") continue;
|
|
38116
|
+
const targetEventBytes = Math.max(0, event.byteLength - (session.pendingProcessOutputBytes - maxPendingProcessOutputBytes));
|
|
38117
|
+
if (targetEventBytes <= 0) {
|
|
38118
|
+
session.pendingProcessEvents.splice(index, 1);
|
|
38119
|
+
session.pendingProcessOutputBytes = Math.max(0, session.pendingProcessOutputBytes - event.byteLength);
|
|
38120
|
+
index -= 1;
|
|
38121
|
+
continue;
|
|
38122
|
+
}
|
|
38123
|
+
const trimmed = trimOutputDataToApproxBytes(event.data, targetEventBytes);
|
|
38124
|
+
session.pendingProcessEvents[index] = {
|
|
38125
|
+
type: "output",
|
|
38126
|
+
data: trimmed.data,
|
|
38127
|
+
byteLength: trimmed.byteLength
|
|
38128
|
+
};
|
|
38129
|
+
session.pendingProcessOutputBytes = Math.max(0, session.pendingProcessOutputBytes - (event.byteLength - trimmed.byteLength));
|
|
38130
|
+
}
|
|
38131
|
+
}
|
|
38132
|
+
function enforcePendingProcessEventLimits(session, limits) {
|
|
38133
|
+
while (session.pendingProcessEvents.length > limits.maxPendingProcessEvents && coalesceOldestPendingOutputPair(session));
|
|
38134
|
+
trimPendingOutputBytesToLimit(session, limits.maxPendingProcessOutputBytes);
|
|
38135
|
+
}
|
|
37493
38136
|
function defaultShellResolver(platform = process.platform, env = process.env) {
|
|
37494
38137
|
if (platform === "win32") return "pwsh.exe";
|
|
37495
38138
|
return env.SHELL ?? "bash";
|
|
@@ -37856,6 +38499,10 @@ const makeTerminalManagerWithOptions = effect.Effect.fn("makeTerminalManagerWith
|
|
|
37856
38499
|
const subprocessPollIntervalMs = options.subprocessPollIntervalMs ?? DEFAULT_SUBPROCESS_POLL_INTERVAL_MS;
|
|
37857
38500
|
const processKillGraceMs = options.processKillGraceMs ?? DEFAULT_PROCESS_KILL_GRACE_MS;
|
|
37858
38501
|
const maxRetainedInactiveSessions = options.maxRetainedInactiveSessions ?? DEFAULT_MAX_RETAINED_INACTIVE_SESSIONS;
|
|
38502
|
+
const pendingProcessEventLimits = {
|
|
38503
|
+
maxPendingProcessEvents: Math.max(1, options.maxPendingProcessEvents ?? DEFAULT_MAX_PENDING_PROCESS_EVENTS),
|
|
38504
|
+
maxPendingProcessOutputBytes: Math.max(1, options.maxPendingProcessOutputBytes ?? DEFAULT_MAX_PENDING_PROCESS_OUTPUT_BYTES)
|
|
38505
|
+
};
|
|
37859
38506
|
yield* fileSystem.makeDirectory(logsDir, { recursive: true }).pipe(effect.Effect.orDie);
|
|
37860
38507
|
const managerStateRef = yield* effect.SynchronizedRef.make({
|
|
37861
38508
|
sessions: /* @__PURE__ */ new Map(),
|
|
@@ -38092,16 +38739,12 @@ const makeTerminalManagerWithOptions = effect.Effect.fn("makeTerminalManagerWith
|
|
|
38092
38739
|
while (true) {
|
|
38093
38740
|
const action = yield* effect.Effect.sync(() => {
|
|
38094
38741
|
if (session.pid !== expectedPid || !session.process || session.status !== "running") {
|
|
38095
|
-
session
|
|
38096
|
-
session.pendingProcessEventIndex = 0;
|
|
38097
|
-
session.processEventDrainRunning = false;
|
|
38742
|
+
clearPendingProcessEvents(session);
|
|
38098
38743
|
return { type: "idle" };
|
|
38099
38744
|
}
|
|
38100
38745
|
const nextEvent = session.pendingProcessEvents[session.pendingProcessEventIndex];
|
|
38101
38746
|
if (!nextEvent) {
|
|
38102
|
-
session
|
|
38103
|
-
session.pendingProcessEventIndex = 0;
|
|
38104
|
-
session.processEventDrainRunning = false;
|
|
38747
|
+
clearPendingProcessEvents(session);
|
|
38105
38748
|
return { type: "idle" };
|
|
38106
38749
|
}
|
|
38107
38750
|
session.pendingProcessEventIndex += 1;
|
|
@@ -38110,6 +38753,7 @@ const makeTerminalManagerWithOptions = effect.Effect.fn("makeTerminalManagerWith
|
|
|
38110
38753
|
session.pendingProcessEventIndex = 0;
|
|
38111
38754
|
}
|
|
38112
38755
|
if (nextEvent.type === "output") {
|
|
38756
|
+
session.pendingProcessOutputBytes = Math.max(0, session.pendingProcessOutputBytes - nextEvent.byteLength);
|
|
38113
38757
|
const sanitized = sanitizeTerminalHistoryChunk(session.pendingHistoryControlSequence, nextEvent.data);
|
|
38114
38758
|
session.pendingHistoryControlSequence = sanitized.pendingControlSequence;
|
|
38115
38759
|
if (sanitized.visibleText.length > 0) session.history = capHistory(`${session.history}${sanitized.visibleText}`, historyLineLimit);
|
|
@@ -38129,9 +38773,7 @@ const makeTerminalManagerWithOptions = effect.Effect.fn("makeTerminalManagerWith
|
|
|
38129
38773
|
session.hasRunningSubprocess = false;
|
|
38130
38774
|
session.status = "exited";
|
|
38131
38775
|
session.pendingHistoryControlSequence = "";
|
|
38132
|
-
session
|
|
38133
|
-
session.pendingProcessEventIndex = 0;
|
|
38134
|
-
session.processEventDrainRunning = false;
|
|
38776
|
+
clearPendingProcessEvents(session);
|
|
38135
38777
|
session.exitCode = Number.isInteger(nextEvent.event.exitCode) ? nextEvent.event.exitCode : null;
|
|
38136
38778
|
session.exitSignal = Number.isInteger(nextEvent.event.signal) ? nextEvent.event.signal : null;
|
|
38137
38779
|
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -38179,9 +38821,7 @@ const makeTerminalManagerWithOptions = effect.Effect.fn("makeTerminalManagerWith
|
|
|
38179
38821
|
session.hasRunningSubprocess = false;
|
|
38180
38822
|
session.status = "exited";
|
|
38181
38823
|
session.pendingHistoryControlSequence = "";
|
|
38182
|
-
session
|
|
38183
|
-
session.pendingProcessEventIndex = 0;
|
|
38184
|
-
session.processEventDrainRunning = false;
|
|
38824
|
+
clearPendingProcessEvents(session);
|
|
38185
38825
|
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
38186
38826
|
return [void 0, state];
|
|
38187
38827
|
});
|
|
@@ -38233,9 +38873,7 @@ const makeTerminalManagerWithOptions = effect.Effect.fn("makeTerminalManagerWith
|
|
|
38233
38873
|
session.exitCode = null;
|
|
38234
38874
|
session.exitSignal = null;
|
|
38235
38875
|
session.hasRunningSubprocess = false;
|
|
38236
|
-
session
|
|
38237
|
-
session.pendingProcessEventIndex = 0;
|
|
38238
|
-
session.processEventDrainRunning = false;
|
|
38876
|
+
clearPendingProcessEvents(session);
|
|
38239
38877
|
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
38240
38878
|
return [void 0, state];
|
|
38241
38879
|
});
|
|
@@ -38249,15 +38887,16 @@ const makeTerminalManagerWithOptions = effect.Effect.fn("makeTerminalManagerWith
|
|
|
38249
38887
|
const unsubscribeData = ptyProcess.onData((data) => {
|
|
38250
38888
|
if (!enqueueProcessEvent(session, processPid, {
|
|
38251
38889
|
type: "output",
|
|
38252
|
-
data
|
|
38253
|
-
|
|
38890
|
+
data,
|
|
38891
|
+
byteLength: approximateTextBytes(data)
|
|
38892
|
+
}, pendingProcessEventLimits)) return;
|
|
38254
38893
|
runFork(drainProcessEvents(session, processPid));
|
|
38255
38894
|
});
|
|
38256
38895
|
const unsubscribeExit = ptyProcess.onExit((event) => {
|
|
38257
38896
|
if (!enqueueProcessEvent(session, processPid, {
|
|
38258
38897
|
type: "exit",
|
|
38259
38898
|
event
|
|
38260
|
-
})) return;
|
|
38899
|
+
}, pendingProcessEventLimits)) return;
|
|
38261
38900
|
runFork(drainProcessEvents(session, processPid));
|
|
38262
38901
|
});
|
|
38263
38902
|
yield* modifyManagerState((state) => {
|
|
@@ -38289,9 +38928,7 @@ const makeTerminalManagerWithOptions = effect.Effect.fn("makeTerminalManagerWith
|
|
|
38289
38928
|
session.unsubscribeData = null;
|
|
38290
38929
|
session.unsubscribeExit = null;
|
|
38291
38930
|
session.hasRunningSubprocess = false;
|
|
38292
|
-
session
|
|
38293
|
-
session.pendingProcessEventIndex = 0;
|
|
38294
|
-
session.processEventDrainRunning = false;
|
|
38931
|
+
clearPendingProcessEvents(session);
|
|
38295
38932
|
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
38296
38933
|
return [void 0, state];
|
|
38297
38934
|
});
|
|
@@ -38401,6 +39038,7 @@ const makeTerminalManagerWithOptions = effect.Effect.fn("makeTerminalManagerWith
|
|
|
38401
39038
|
pendingHistoryControlSequence: "",
|
|
38402
39039
|
pendingProcessEvents: [],
|
|
38403
39040
|
pendingProcessEventIndex: 0,
|
|
39041
|
+
pendingProcessOutputBytes: 0,
|
|
38404
39042
|
processEventDrainRunning: false,
|
|
38405
39043
|
exitCode: null,
|
|
38406
39044
|
exitSignal: null,
|
|
@@ -38447,18 +39085,14 @@ const makeTerminalManagerWithOptions = effect.Effect.fn("makeTerminalManagerWith
|
|
|
38447
39085
|
liveSession.runtimeEnv = nextRuntimeEnv;
|
|
38448
39086
|
liveSession.history = "";
|
|
38449
39087
|
liveSession.pendingHistoryControlSequence = "";
|
|
38450
|
-
liveSession
|
|
38451
|
-
liveSession.pendingProcessEventIndex = 0;
|
|
38452
|
-
liveSession.processEventDrainRunning = false;
|
|
39088
|
+
clearPendingProcessEvents(liveSession);
|
|
38453
39089
|
yield* persistHistory(liveSession.threadId, liveSession.terminalId, liveSession.history);
|
|
38454
39090
|
} else if (liveSession.status === "exited" || liveSession.status === "error") {
|
|
38455
39091
|
liveSession.runtimeEnv = nextRuntimeEnv;
|
|
38456
39092
|
liveSession.worktreePath = input.worktreePath ?? null;
|
|
38457
39093
|
liveSession.history = "";
|
|
38458
39094
|
liveSession.pendingHistoryControlSequence = "";
|
|
38459
|
-
liveSession
|
|
38460
|
-
liveSession.pendingProcessEventIndex = 0;
|
|
38461
|
-
liveSession.processEventDrainRunning = false;
|
|
39095
|
+
clearPendingProcessEvents(liveSession);
|
|
38462
39096
|
yield* persistHistory(liveSession.threadId, liveSession.terminalId, liveSession.history);
|
|
38463
39097
|
}
|
|
38464
39098
|
if (!liveSession.process) {
|
|
@@ -38512,9 +39146,7 @@ const makeTerminalManagerWithOptions = effect.Effect.fn("makeTerminalManagerWith
|
|
|
38512
39146
|
const session = yield* requireSession(input.threadId, terminalId);
|
|
38513
39147
|
session.history = "";
|
|
38514
39148
|
session.pendingHistoryControlSequence = "";
|
|
38515
|
-
session
|
|
38516
|
-
session.pendingProcessEventIndex = 0;
|
|
38517
|
-
session.processEventDrainRunning = false;
|
|
39149
|
+
clearPendingProcessEvents(session);
|
|
38518
39150
|
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
38519
39151
|
yield* persistHistory(input.threadId, terminalId, session.history);
|
|
38520
39152
|
yield* publishEvent({
|
|
@@ -38545,6 +39177,7 @@ const makeTerminalManagerWithOptions = effect.Effect.fn("makeTerminalManagerWith
|
|
|
38545
39177
|
pendingHistoryControlSequence: "",
|
|
38546
39178
|
pendingProcessEvents: [],
|
|
38547
39179
|
pendingProcessEventIndex: 0,
|
|
39180
|
+
pendingProcessOutputBytes: 0,
|
|
38548
39181
|
processEventDrainRunning: false,
|
|
38549
39182
|
exitCode: null,
|
|
38550
39183
|
exitSignal: null,
|
|
@@ -38578,9 +39211,7 @@ const makeTerminalManagerWithOptions = effect.Effect.fn("makeTerminalManagerWith
|
|
|
38578
39211
|
const rows = input.rows ?? session.rows;
|
|
38579
39212
|
session.history = "";
|
|
38580
39213
|
session.pendingHistoryControlSequence = "";
|
|
38581
|
-
session
|
|
38582
|
-
session.pendingProcessEventIndex = 0;
|
|
38583
|
-
session.processEventDrainRunning = false;
|
|
39214
|
+
clearPendingProcessEvents(session);
|
|
38584
39215
|
yield* persistHistory(input.threadId, terminalId, session.history);
|
|
38585
39216
|
yield* startSession(session, {
|
|
38586
39217
|
threadId: input.threadId,
|
|
@@ -38602,6 +39233,7 @@ const makeTerminalManagerWithOptions = effect.Effect.fn("makeTerminalManagerWith
|
|
|
38602
39233
|
yield* effect.Effect.forEach(threadSessions, (session) => closeSession(input.threadId, session.terminalId, false), { discard: true });
|
|
38603
39234
|
if (input.deleteHistory) yield* deleteAllHistoryForThread(input.threadId);
|
|
38604
39235
|
}));
|
|
39236
|
+
const listSessions = effect.SynchronizedRef.get(managerStateRef).pipe(effect.Effect.map((state) => [...state.sessions.values()].map(snapshot).toSorted((left, right) => right.updatedAt.localeCompare(left.updatedAt))));
|
|
38605
39237
|
return {
|
|
38606
39238
|
open,
|
|
38607
39239
|
write,
|
|
@@ -38610,6 +39242,7 @@ const makeTerminalManagerWithOptions = effect.Effect.fn("makeTerminalManagerWith
|
|
|
38610
39242
|
restart,
|
|
38611
39243
|
close,
|
|
38612
39244
|
listDiagnostics: effect.SynchronizedRef.get(managerStateRef).pipe(effect.Effect.map((state) => [...state.sessions.values()].map(diagnosticsSnapshot).toSorted((left, right) => right.updatedAt.localeCompare(left.updatedAt)))),
|
|
39245
|
+
listSessions,
|
|
38613
39246
|
subscribe: (listener) => effect.Effect.sync(() => {
|
|
38614
39247
|
terminalEventListeners.add(listener);
|
|
38615
39248
|
return () => {
|
|
@@ -39105,7 +39738,7 @@ function isGitRepository(cwd) {
|
|
|
39105
39738
|
//#endregion
|
|
39106
39739
|
//#region src/orchestration/Layers/ProviderRuntimeIngestion.ts
|
|
39107
39740
|
const providerTurnKey = (threadId, turnId) => `${threadId}:${turnId}`;
|
|
39108
|
-
const providerCommandId = (event, tag) => require_collectUint8StreamText.CommandId.make(`provider:${event.eventId}:${tag}:${
|
|
39741
|
+
const providerCommandId = (event, tag, discriminator) => require_collectUint8StreamText.CommandId.make(discriminator === void 0 ? `provider:${event.eventId}:${tag}` : `provider:${event.eventId}:${tag}:${discriminator}`);
|
|
39109
39742
|
const liveAssistantDeltaBufferKey = (threadId, messageId) => `${threadId}:${messageId}`;
|
|
39110
39743
|
const TURN_MESSAGE_IDS_BY_TURN_CACHE_CAPACITY = 1e4;
|
|
39111
39744
|
const TURN_MESSAGE_IDS_BY_TURN_TTL = effect.Duration.minutes(120);
|
|
@@ -39179,6 +39812,7 @@ function rawPayloadThreadId(event) {
|
|
|
39179
39812
|
return asTrimmedString(asRecord(event.raw?.payload)?.threadId);
|
|
39180
39813
|
}
|
|
39181
39814
|
function collabReceiverThreadIdsFromRuntimeEvent(event) {
|
|
39815
|
+
if (event.type === "subagent.started" || event.type === "subagent.updated" || event.type === "subagent.completed") return event.payload.subagent.providerThreadId ? [event.payload.subagent.providerThreadId] : [];
|
|
39182
39816
|
if (event.type !== "item.started" && event.type !== "item.updated" && event.type !== "item.completed") return [];
|
|
39183
39817
|
if (event.payload.itemType !== "collab_agent_tool_call") return [];
|
|
39184
39818
|
const item = asRecord(asRecord(event.payload.data)?.item);
|
|
@@ -39236,6 +39870,9 @@ function normalizeRuntimeTurnState(value) {
|
|
|
39236
39870
|
default: return "completed";
|
|
39237
39871
|
}
|
|
39238
39872
|
}
|
|
39873
|
+
function isTerminalProjectionTurnState(state) {
|
|
39874
|
+
return state === "completed" || state === "error" || state === "interrupted";
|
|
39875
|
+
}
|
|
39239
39876
|
function orchestrationSessionStatusFromRuntimeState(state) {
|
|
39240
39877
|
switch (state) {
|
|
39241
39878
|
case "starting": return "starting";
|
|
@@ -39423,6 +40060,53 @@ function runtimeEventToActivities(event) {
|
|
|
39423
40060
|
turnId: toTurnId$1(event.turnId) ?? null,
|
|
39424
40061
|
...maybeSequence
|
|
39425
40062
|
}];
|
|
40063
|
+
case "subagent.started": return [{
|
|
40064
|
+
id: event.eventId,
|
|
40065
|
+
createdAt: event.createdAt,
|
|
40066
|
+
tone: "tool",
|
|
40067
|
+
kind: "subagent.started",
|
|
40068
|
+
summary: `${event.payload.subagent.label ?? "Subagent"} started`,
|
|
40069
|
+
payload: {
|
|
40070
|
+
itemType: "collab_agent_tool_call",
|
|
40071
|
+
status: "running",
|
|
40072
|
+
subagent: event.payload.subagent
|
|
40073
|
+
},
|
|
40074
|
+
turnId: toTurnId$1(event.turnId) ?? null,
|
|
40075
|
+
...maybeSequence
|
|
40076
|
+
}];
|
|
40077
|
+
case "subagent.updated": return [{
|
|
40078
|
+
id: event.eventId,
|
|
40079
|
+
createdAt: event.createdAt,
|
|
40080
|
+
tone: "tool",
|
|
40081
|
+
kind: "subagent.updated",
|
|
40082
|
+
summary: event.payload.summary ?? `${event.payload.subagent.label ?? "Subagent"} updated`,
|
|
40083
|
+
payload: {
|
|
40084
|
+
itemType: "collab_agent_tool_call",
|
|
40085
|
+
...event.payload.status ? { status: event.payload.status } : {},
|
|
40086
|
+
subagent: event.payload.subagent,
|
|
40087
|
+
...event.payload.detail ? { detail: truncateDetail(event.payload.detail) } : {},
|
|
40088
|
+
...event.payload.summary ? { summary: truncateDetail(event.payload.summary) } : {},
|
|
40089
|
+
...event.payload.usage !== void 0 ? { usage: event.payload.usage } : {}
|
|
40090
|
+
},
|
|
40091
|
+
turnId: toTurnId$1(event.turnId) ?? null,
|
|
40092
|
+
...maybeSequence
|
|
40093
|
+
}];
|
|
40094
|
+
case "subagent.completed": return [{
|
|
40095
|
+
id: event.eventId,
|
|
40096
|
+
createdAt: event.createdAt,
|
|
40097
|
+
tone: event.payload.status === "failed" ? "error" : "tool",
|
|
40098
|
+
kind: "subagent.completed",
|
|
40099
|
+
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`,
|
|
40100
|
+
payload: {
|
|
40101
|
+
itemType: "collab_agent_tool_call",
|
|
40102
|
+
status: event.payload.status,
|
|
40103
|
+
subagent: event.payload.subagent,
|
|
40104
|
+
...event.payload.summary ? { detail: truncateDetail(event.payload.summary) } : {},
|
|
40105
|
+
...event.payload.usage !== void 0 ? { usage: event.payload.usage } : {}
|
|
40106
|
+
},
|
|
40107
|
+
turnId: toTurnId$1(event.turnId) ?? null,
|
|
40108
|
+
...maybeSequence
|
|
40109
|
+
}];
|
|
39426
40110
|
case "thread.state.changed":
|
|
39427
40111
|
if (event.payload.state !== "compacted") return [];
|
|
39428
40112
|
return [{
|
|
@@ -39615,7 +40299,7 @@ const make$3 = effect.Effect.gen(function* () {
|
|
|
39615
40299
|
}
|
|
39616
40300
|
yield* orchestrationEngine.dispatch({
|
|
39617
40301
|
type: "thread.message.assistant.delta",
|
|
39618
|
-
commandId: providerCommandId(buffer.event, input.commandTag),
|
|
40302
|
+
commandId: providerCommandId(buffer.event, input.commandTag, String(buffer.messageId)),
|
|
39619
40303
|
threadId: buffer.threadId,
|
|
39620
40304
|
messageId: buffer.messageId,
|
|
39621
40305
|
delta: buffer.text,
|
|
@@ -39694,9 +40378,10 @@ const make$3 = effect.Effect.gen(function* () {
|
|
|
39694
40378
|
};
|
|
39695
40379
|
const upsertSubagentMessageActivity = (input) => effect.Effect.gen(function* () {
|
|
39696
40380
|
const sessionSequence = input.event.sessionSequence;
|
|
40381
|
+
const commandKey = `${input.providerThreadId}:${input.providerItemId}`;
|
|
39697
40382
|
yield* orchestrationEngine.dispatch({
|
|
39698
40383
|
type: "thread.activity.append",
|
|
39699
|
-
commandId: providerCommandId(input.event, "subagent-message-upsert"),
|
|
40384
|
+
commandId: providerCommandId(input.event, "subagent-message-upsert", commandKey),
|
|
39700
40385
|
threadId: input.threadId,
|
|
39701
40386
|
activity: {
|
|
39702
40387
|
id: subagentMessageActivityId({
|
|
@@ -39714,6 +40399,7 @@ const make$3 = effect.Effect.gen(function* () {
|
|
|
39714
40399
|
streaming: input.streaming,
|
|
39715
40400
|
providerThreadId: input.providerThreadId,
|
|
39716
40401
|
providerItemId: input.providerItemId,
|
|
40402
|
+
...input.subagentId ? { subagentId: input.subagentId } : {},
|
|
39717
40403
|
...input.event.providerRefs ? { providerRefs: input.event.providerRefs } : {}
|
|
39718
40404
|
},
|
|
39719
40405
|
turnId: toTurnId$1(input.event.turnId) ?? null,
|
|
@@ -39753,6 +40439,16 @@ const make$3 = effect.Effect.gen(function* () {
|
|
|
39753
40439
|
streaming: false
|
|
39754
40440
|
});
|
|
39755
40441
|
});
|
|
40442
|
+
const bufferedSubagentProviderItemIds = (input) => {
|
|
40443
|
+
const prefix = subagentMessageBufferKey({
|
|
40444
|
+
threadId: input.threadId,
|
|
40445
|
+
providerThreadId: input.providerThreadId,
|
|
40446
|
+
providerItemId: ""
|
|
40447
|
+
});
|
|
40448
|
+
const providerItemIds = /* @__PURE__ */ new Set();
|
|
40449
|
+
for (const key of subagentMessageTextByKey.keys()) if (key.startsWith(prefix)) providerItemIds.add(key.slice(prefix.length));
|
|
40450
|
+
return [...providerItemIds];
|
|
40451
|
+
};
|
|
39756
40452
|
const clearSubagentMessageBuffersForThread = (threadId) => effect.Effect.sync(() => {
|
|
39757
40453
|
const prefix = `${threadId}:`;
|
|
39758
40454
|
for (const key of subagentMessageTextByKey.keys()) if (key.startsWith(prefix)) subagentMessageTextByKey.delete(key);
|
|
@@ -39786,7 +40482,7 @@ const make$3 = effect.Effect.gen(function* () {
|
|
|
39786
40482
|
if (!hasRenderableAssistantText(bufferedText)) return false;
|
|
39787
40483
|
yield* orchestrationEngine.dispatch({
|
|
39788
40484
|
type: "thread.message.assistant.delta",
|
|
39789
|
-
commandId: providerCommandId(input.event, input.commandTag),
|
|
40485
|
+
commandId: providerCommandId(input.event, input.commandTag, String(input.messageId)),
|
|
39790
40486
|
threadId: input.threadId,
|
|
39791
40487
|
messageId: input.messageId,
|
|
39792
40488
|
delta: bufferedText,
|
|
@@ -39814,7 +40510,7 @@ const make$3 = effect.Effect.gen(function* () {
|
|
|
39814
40510
|
const hasRenderableText = hasRenderableAssistantText(text);
|
|
39815
40511
|
if (hasRenderableText) yield* orchestrationEngine.dispatch({
|
|
39816
40512
|
type: "thread.message.assistant.delta",
|
|
39817
|
-
commandId: providerCommandId(input.event, input.finalDeltaCommandTag),
|
|
40513
|
+
commandId: providerCommandId(input.event, input.finalDeltaCommandTag, String(input.messageId)),
|
|
39818
40514
|
threadId: input.threadId,
|
|
39819
40515
|
messageId: input.messageId,
|
|
39820
40516
|
delta: text,
|
|
@@ -39823,7 +40519,7 @@ const make$3 = effect.Effect.gen(function* () {
|
|
|
39823
40519
|
});
|
|
39824
40520
|
if (input.hasProjectedMessage || hasRenderableText) yield* orchestrationEngine.dispatch({
|
|
39825
40521
|
type: "thread.message.assistant.complete",
|
|
39826
|
-
commandId: providerCommandId(input.event, input.commandTag),
|
|
40522
|
+
commandId: providerCommandId(input.event, input.commandTag, String(input.messageId)),
|
|
39827
40523
|
threadId: input.threadId,
|
|
39828
40524
|
messageId: input.messageId,
|
|
39829
40525
|
...input.turnId ? { turnId: input.turnId } : {},
|
|
@@ -39857,7 +40553,7 @@ const make$3 = effect.Effect.gen(function* () {
|
|
|
39857
40553
|
const existingPlan = findProposedPlanById(input.threadProposedPlans, input.planId);
|
|
39858
40554
|
yield* orchestrationEngine.dispatch({
|
|
39859
40555
|
type: "thread.proposed-plan.upsert",
|
|
39860
|
-
commandId: providerCommandId(input.event, "proposed-plan-upsert"),
|
|
40556
|
+
commandId: providerCommandId(input.event, "proposed-plan-upsert", input.planId),
|
|
39861
40557
|
threadId: input.threadId,
|
|
39862
40558
|
proposedPlan: {
|
|
39863
40559
|
id: input.planId,
|
|
@@ -39924,13 +40620,13 @@ const make$3 = effect.Effect.gen(function* () {
|
|
|
39924
40620
|
if (!sameId$1(yield* getExpectedProviderTurnIdForThread(threadId), eventTurnId)) return null;
|
|
39925
40621
|
return yield* getSourceProposedPlanReferenceForPendingTurnStart(threadId);
|
|
39926
40622
|
});
|
|
39927
|
-
const markSourceProposedPlanImplemented = effect.Effect.fn("markSourceProposedPlanImplemented")(function* (sourceThreadId, sourcePlanId, implementationThreadId, implementedAt) {
|
|
40623
|
+
const markSourceProposedPlanImplemented = effect.Effect.fn("markSourceProposedPlanImplemented")(function* (event, sourceThreadId, sourcePlanId, implementationThreadId, implementedAt) {
|
|
39928
40624
|
const sourceThread = yield* resolveThreadDetail(sourceThreadId);
|
|
39929
40625
|
const sourcePlan = sourceThread?.proposedPlans.find((entry) => entry.id === sourcePlanId);
|
|
39930
40626
|
if (!sourceThread || !sourcePlan || sourcePlan.implementedAt !== null) return;
|
|
39931
40627
|
yield* orchestrationEngine.dispatch({
|
|
39932
40628
|
type: "thread.proposed-plan.upsert",
|
|
39933
|
-
commandId:
|
|
40629
|
+
commandId: providerCommandId(event, "source-proposed-plan-implemented", `${sourceThreadId}:${sourcePlanId}:${implementationThreadId}`),
|
|
39934
40630
|
threadId: sourceThread.id,
|
|
39935
40631
|
proposedPlan: {
|
|
39936
40632
|
...sourcePlan,
|
|
@@ -39955,6 +40651,12 @@ const make$3 = effect.Effect.gen(function* () {
|
|
|
39955
40651
|
const activeTurnId = thread.session?.activeTurnId ?? null;
|
|
39956
40652
|
const conflictsWithActiveTurn = activeTurnId !== null && eventTurnId !== void 0 && !sameId$1(activeTurnId, eventTurnId);
|
|
39957
40653
|
const missingTurnForActiveTurn = activeTurnId !== null && eventTurnId === void 0;
|
|
40654
|
+
const existingEventTurn = event.type === "turn.started" && eventTurnId !== void 0 ? yield* projectionTurnRepository.getByTurnId({
|
|
40655
|
+
threadId: thread.id,
|
|
40656
|
+
turnId: eventTurnId
|
|
40657
|
+
}) : effect.Option.none();
|
|
40658
|
+
const eventTurnAlreadyTerminal = effect.Option.isSome(existingEventTurn) && isTerminalProjectionTurnState(existingEventTurn.value.state);
|
|
40659
|
+
const eventTurnAlreadyProjectedWithoutActiveSession = activeTurnId === null && effect.Option.isSome(existingEventTurn);
|
|
39958
40660
|
if (!isAssistantTextDeltaEvent(event)) yield* flushLiveAssistantDeltaBuffersSafely({ commandTag: "assistant-delta-flush-before-runtime-event" });
|
|
39959
40661
|
yield* rememberSubagentProviderThreadIds(thread.id, event);
|
|
39960
40662
|
const eventProviderThreadId = rawPayloadThreadId(event);
|
|
@@ -39965,8 +40667,9 @@ const make$3 = effect.Effect.gen(function* () {
|
|
|
39965
40667
|
case "session.exited": return true;
|
|
39966
40668
|
case "session.started":
|
|
39967
40669
|
case "thread.started": return true;
|
|
39968
|
-
case "turn.started": return !conflictsWithActiveTurn;
|
|
40670
|
+
case "turn.started": return !conflictsWithActiveTurn && !eventTurnAlreadyTerminal && !eventTurnAlreadyProjectedWithoutActiveSession;
|
|
39969
40671
|
case "turn.completed":
|
|
40672
|
+
case "turn.aborted":
|
|
39970
40673
|
if (conflictsWithActiveTurn || missingTurnForActiveTurn) return false;
|
|
39971
40674
|
if (activeTurnId !== null && eventTurnId !== void 0) return sameId$1(activeTurnId, eventTurnId);
|
|
39972
40675
|
return true;
|
|
@@ -39974,21 +40677,22 @@ const make$3 = effect.Effect.gen(function* () {
|
|
|
39974
40677
|
}
|
|
39975
40678
|
})();
|
|
39976
40679
|
const acceptedTurnStartedSourcePlan = event.type === "turn.started" && shouldApplyThreadLifecycle ? yield* getSourceProposedPlanReferenceForAcceptedTurnStart(thread.id, eventTurnId) : null;
|
|
39977
|
-
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") {
|
|
39978
|
-
const nextActiveTurnId = event.type === "turn.started" ? eventTurnId ?? null : event.type === "turn.completed" || event.type === "session.exited" ? null : activeTurnId;
|
|
40680
|
+
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") {
|
|
40681
|
+
const nextActiveTurnId = event.type === "turn.started" ? eventTurnId ?? null : event.type === "turn.completed" || event.type === "turn.aborted" || event.type === "session.exited" ? null : activeTurnId;
|
|
39979
40682
|
const status = (() => {
|
|
39980
40683
|
switch (event.type) {
|
|
39981
40684
|
case "session.state.changed": return orchestrationSessionStatusFromRuntimeState(event.payload.state);
|
|
39982
40685
|
case "turn.started": return "running";
|
|
39983
40686
|
case "session.exited": return "stopped";
|
|
39984
40687
|
case "turn.completed": return normalizeRuntimeTurnState(event.payload.state) === "failed" ? "error" : "ready";
|
|
40688
|
+
case "turn.aborted": return "ready";
|
|
39985
40689
|
case "session.started":
|
|
39986
40690
|
case "thread.started": return activeTurnId !== null ? "running" : "ready";
|
|
39987
40691
|
}
|
|
39988
40692
|
})();
|
|
39989
40693
|
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;
|
|
39990
40694
|
if (shouldApplyThreadLifecycle) {
|
|
39991
|
-
if (event.type === "turn.started" && acceptedTurnStartedSourcePlan !== null) yield* markSourceProposedPlanImplemented(acceptedTurnStartedSourcePlan.sourceThreadId, acceptedTurnStartedSourcePlan.sourcePlanId, thread.id, now).pipe(effect.Effect.catchCause((cause) => effect.Effect.logWarning("provider runtime ingestion failed to mark source proposed plan", {
|
|
40695
|
+
if (event.type === "turn.started" && acceptedTurnStartedSourcePlan !== null) yield* markSourceProposedPlanImplemented(event, acceptedTurnStartedSourcePlan.sourceThreadId, acceptedTurnStartedSourcePlan.sourcePlanId, thread.id, now).pipe(effect.Effect.catchCause((cause) => effect.Effect.logWarning("provider runtime ingestion failed to mark source proposed plan", {
|
|
39992
40696
|
eventId: event.eventId,
|
|
39993
40697
|
eventType: event.type,
|
|
39994
40698
|
cause: effect.Cause.pretty(cause)
|
|
@@ -40010,11 +40714,30 @@ const make$3 = effect.Effect.gen(function* () {
|
|
|
40010
40714
|
},
|
|
40011
40715
|
createdAt: now
|
|
40012
40716
|
});
|
|
40717
|
+
if (event.type === "turn.aborted" && eventTurnId !== void 0) yield* orchestrationEngine.dispatch({
|
|
40718
|
+
type: "thread.turn.interrupt",
|
|
40719
|
+
commandId: providerCommandId(event, "thread-turn-interrupt", String(eventTurnId)),
|
|
40720
|
+
threadId: thread.id,
|
|
40721
|
+
turnId: eventTurnId,
|
|
40722
|
+
createdAt: now
|
|
40723
|
+
});
|
|
40013
40724
|
}
|
|
40014
40725
|
}
|
|
40015
40726
|
const assistantDelta = isAssistantTextDeltaEvent(event) ? event.payload.delta : void 0;
|
|
40727
|
+
const subagentDelta = event.type === "subagent.message.delta" ? event.payload.delta : void 0;
|
|
40016
40728
|
const proposedPlanDelta = event.type === "turn.proposed.delta" ? event.payload.delta : void 0;
|
|
40017
|
-
if (
|
|
40729
|
+
if (event.type === "subagent.message.delta" && subagentDelta && subagentDelta.length > 0) {
|
|
40730
|
+
const subagentPayload = event.payload;
|
|
40731
|
+
yield* appendSubagentMessageDelta({
|
|
40732
|
+
event,
|
|
40733
|
+
threadId: thread.id,
|
|
40734
|
+
subagentId: String(subagentPayload.subagentId),
|
|
40735
|
+
providerThreadId: subagentPayload.providerThreadId ?? String(subagentPayload.subagentId),
|
|
40736
|
+
providerItemId: subagentPayload.providerMessageId ?? String(subagentPayload.subagentId),
|
|
40737
|
+
delta: subagentDelta,
|
|
40738
|
+
createdAt: now
|
|
40739
|
+
});
|
|
40740
|
+
} else if (assistantDelta && assistantDelta.length > 0 && isSubagentProviderThread && eventProviderThreadId) yield* appendSubagentMessageDelta({
|
|
40018
40741
|
event,
|
|
40019
40742
|
threadId: thread.id,
|
|
40020
40743
|
providerThreadId: eventProviderThreadId,
|
|
@@ -40034,7 +40757,7 @@ const make$3 = effect.Effect.gen(function* () {
|
|
|
40034
40757
|
const spillChunk = yield* appendBufferedAssistantText(assistantMessageId, assistantDelta);
|
|
40035
40758
|
if (spillChunk.length > 0) yield* orchestrationEngine.dispatch({
|
|
40036
40759
|
type: "thread.message.assistant.delta",
|
|
40037
|
-
commandId: providerCommandId(event, "assistant-delta-buffer-spill"),
|
|
40760
|
+
commandId: providerCommandId(event, "assistant-delta-buffer-spill", String(assistantMessageId)),
|
|
40038
40761
|
threadId: thread.id,
|
|
40039
40762
|
messageId: assistantMessageId,
|
|
40040
40763
|
delta: spillChunk,
|
|
@@ -40119,6 +40842,26 @@ const make$3 = effect.Effect.gen(function* () {
|
|
|
40119
40842
|
...subagentMessageCompletion.fallbackText !== void 0 ? { fallbackText: subagentMessageCompletion.fallbackText } : {},
|
|
40120
40843
|
createdAt: now
|
|
40121
40844
|
});
|
|
40845
|
+
if (event.type === "subagent.completed") {
|
|
40846
|
+
const subagentId = String(event.payload.subagent.subagentId);
|
|
40847
|
+
const providerThreadId = event.payload.subagent.providerThreadId ?? subagentId;
|
|
40848
|
+
const providerItemIds = bufferedSubagentProviderItemIds({
|
|
40849
|
+
threadId: thread.id,
|
|
40850
|
+
providerThreadId
|
|
40851
|
+
});
|
|
40852
|
+
yield* effect.Effect.forEach(providerItemIds.length > 0 ? providerItemIds : [subagentId], (providerItemId) => completeSubagentMessage({
|
|
40853
|
+
event,
|
|
40854
|
+
threadId: thread.id,
|
|
40855
|
+
subagentId,
|
|
40856
|
+
providerThreadId,
|
|
40857
|
+
providerItemId,
|
|
40858
|
+
...event.payload.summary !== void 0 ? { fallbackText: event.payload.summary } : {},
|
|
40859
|
+
createdAt: now
|
|
40860
|
+
}), {
|
|
40861
|
+
concurrency: 1,
|
|
40862
|
+
discard: true
|
|
40863
|
+
});
|
|
40864
|
+
}
|
|
40122
40865
|
if (proposedPlanCompletion) {
|
|
40123
40866
|
const detailedThread = yield* getLoadedThreadDetail();
|
|
40124
40867
|
yield* finalizeBufferedProposedPlan({
|
|
@@ -40131,7 +40874,7 @@ const make$3 = effect.Effect.gen(function* () {
|
|
|
40131
40874
|
updatedAt: now
|
|
40132
40875
|
});
|
|
40133
40876
|
}
|
|
40134
|
-
if (event.type === "turn.completed") {
|
|
40877
|
+
if (event.type === "turn.completed" || event.type === "turn.aborted") {
|
|
40135
40878
|
const detailedThread = yield* getLoadedThreadDetail();
|
|
40136
40879
|
const messages = detailedThread?.messages ?? [];
|
|
40137
40880
|
const proposedPlans = detailedThread?.proposedPlans ?? [];
|
|
@@ -40201,7 +40944,7 @@ const make$3 = effect.Effect.gen(function* () {
|
|
|
40201
40944
|
const assistantMessageId = require_collectUint8StreamText.MessageId.make(`assistant:${event.itemId ?? event.turnId ?? event.eventId}`);
|
|
40202
40945
|
yield* orchestrationEngine.dispatch({
|
|
40203
40946
|
type: "thread.turn.diff.complete",
|
|
40204
|
-
commandId: providerCommandId(event, "thread-turn-diff-complete"),
|
|
40947
|
+
commandId: providerCommandId(event, "thread-turn-diff-complete", String(turnId)),
|
|
40205
40948
|
threadId: thread.id,
|
|
40206
40949
|
turnId,
|
|
40207
40950
|
completedAt: now,
|
|
@@ -40217,7 +40960,7 @@ const make$3 = effect.Effect.gen(function* () {
|
|
|
40217
40960
|
const activities = runtimeEventToActivities(event);
|
|
40218
40961
|
yield* effect.Effect.forEach(activities, (activity) => orchestrationEngine.dispatch({
|
|
40219
40962
|
type: "thread.activity.append",
|
|
40220
|
-
commandId: providerCommandId(event, "thread-activity-append"),
|
|
40963
|
+
commandId: providerCommandId(event, "thread-activity-append", String(activity.id)),
|
|
40221
40964
|
threadId: thread.id,
|
|
40222
40965
|
activity,
|
|
40223
40966
|
createdAt: activity.createdAt
|
|
@@ -40281,6 +41024,7 @@ function mapProviderSessionStatusToOrchestrationStatus(status) {
|
|
|
40281
41024
|
}
|
|
40282
41025
|
const turnStartKeyForEvent = (event) => event.commandId !== null ? `command:${event.commandId}` : `event:${event.eventId}`;
|
|
40283
41026
|
const serverCommandId$1 = (tag) => require_collectUint8StreamText.CommandId.make(`server:${tag}:${crypto.randomUUID()}`);
|
|
41027
|
+
const isProviderOriginatedCommandId = (commandId) => commandId !== null && String(commandId).startsWith("provider:");
|
|
40284
41028
|
const HANDLED_TURN_START_KEY_MAX = 1e4;
|
|
40285
41029
|
const HANDLED_TURN_START_KEY_TTL = effect.Duration.minutes(30);
|
|
40286
41030
|
const DEFAULT_RUNTIME_MODE = "full-access";
|
|
@@ -40632,6 +41376,17 @@ const make$2 = effect.Effect.gen(function* () {
|
|
|
40632
41376
|
if (yield* hasHandledTurnStartRecently(turnStartKeyForEvent(event))) return;
|
|
40633
41377
|
const thread = yield* resolveThread(event.payload.threadId);
|
|
40634
41378
|
if (!thread) return;
|
|
41379
|
+
if (thread.session?.status === "running" && thread.session.activeTurnId !== null) {
|
|
41380
|
+
yield* appendProviderFailureActivity({
|
|
41381
|
+
threadId: event.payload.threadId,
|
|
41382
|
+
kind: "provider.turn.start.failed",
|
|
41383
|
+
summary: "Provider turn start rejected",
|
|
41384
|
+
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.`,
|
|
41385
|
+
turnId: null,
|
|
41386
|
+
createdAt: event.payload.createdAt
|
|
41387
|
+
});
|
|
41388
|
+
return;
|
|
41389
|
+
}
|
|
40635
41390
|
const message = thread.messages.find((entry) => entry.id === event.payload.messageId);
|
|
40636
41391
|
if (!message || message.role !== "user") {
|
|
40637
41392
|
yield* appendProviderFailureActivity({
|
|
@@ -40702,6 +41457,7 @@ const make$2 = effect.Effect.gen(function* () {
|
|
|
40702
41457
|
yield* providerService.sendTurn(sendTurnRequest.value).pipe(effect.Effect.catchCause(recoverTurnStartFailure), effect.Effect.forkScoped);
|
|
40703
41458
|
});
|
|
40704
41459
|
const processTurnInterruptRequested = effect.Effect.fn("processTurnInterruptRequested")(function* (event) {
|
|
41460
|
+
if (isProviderOriginatedCommandId(event.commandId)) return;
|
|
40705
41461
|
const thread = yield* resolveThread(event.payload.threadId);
|
|
40706
41462
|
if (!thread) return;
|
|
40707
41463
|
if (!(thread.session && thread.session.status !== "stopped")) return yield* appendProviderFailureActivity({
|
|
@@ -46998,6 +47754,10 @@ const decideOrchestrationCommand = effect.Effect.fn("decideOrchestrationCommand"
|
|
|
46998
47754
|
command,
|
|
46999
47755
|
threadId: command.threadId
|
|
47000
47756
|
});
|
|
47757
|
+
if (targetThread.session?.status === "running" && targetThread.session.activeTurnId !== null) return yield* new OrchestrationCommandInvariantError({
|
|
47758
|
+
commandType: command.type,
|
|
47759
|
+
detail: `Thread '${command.threadId}' already has active turn '${targetThread.session.activeTurnId}' and cannot start another turn until it finishes.`
|
|
47760
|
+
});
|
|
47001
47761
|
const sourceProposedPlan = command.sourceProposedPlan;
|
|
47002
47762
|
const sourceThread = sourceProposedPlan ? yield* requireThread({
|
|
47003
47763
|
readModel,
|
|
@@ -50955,7 +51715,7 @@ const OrchestrationProjectionSnapshotQueryLive = effect.Layer.effect(ProjectionS
|
|
|
50955
51715
|
//#region src/orchestration/runtimeLayer.ts
|
|
50956
51716
|
const OrchestrationEventInfrastructureLayerLive = effect.Layer.mergeAll(OrchestrationEventStoreLive, OrchestrationCommandReceiptRepositoryLive);
|
|
50957
51717
|
const OrchestrationProjectionPipelineLayerLive = OrchestrationProjectionPipelineLive.pipe(effect.Layer.provide(OrchestrationEventStoreLive));
|
|
50958
|
-
const OrchestrationInfrastructureLayerLive = effect.Layer.mergeAll(OrchestrationProjectionSnapshotQueryLive, OrchestrationEventInfrastructureLayerLive, OrchestrationProjectionPipelineLayerLive);
|
|
51718
|
+
const OrchestrationInfrastructureLayerLive = effect.Layer.mergeAll(OrchestrationProjectionSnapshotQueryLive, StatisticsQueryLive, OrchestrationEventInfrastructureLayerLive, OrchestrationProjectionPipelineLayerLive);
|
|
50959
51719
|
const OrchestrationLayerLive = effect.Layer.mergeAll(OrchestrationInfrastructureLayerLive, OrchestrationEngineLive.pipe(effect.Layer.provide(OrchestrationInfrastructureLayerLive)));
|
|
50960
51720
|
//#endregion
|
|
50961
51721
|
//#region src/serverRuntimeState.ts
|
|
@@ -51762,6 +52522,7 @@ exports.ServerRequest__DynamicToolCallParams = ServerRequest__DynamicToolCallPar
|
|
|
51762
52522
|
exports.ServerRequest__ExecCommandApprovalParams = ServerRequest__ExecCommandApprovalParams;
|
|
51763
52523
|
exports.ServerRequest__FileChangeRequestApprovalParams = ServerRequest__FileChangeRequestApprovalParams;
|
|
51764
52524
|
exports.ServerRequest__ToolRequestUserInputParams = ServerRequest__ToolRequestUserInputParams;
|
|
52525
|
+
exports.ServerSettingsService = ServerSettingsService;
|
|
51765
52526
|
exports.ToolRequestUserInputParams = ToolRequestUserInputParams;
|
|
51766
52527
|
exports.ToolRequestUserInputResponse = ToolRequestUserInputResponse;
|
|
51767
52528
|
exports.V2AccountRateLimitsUpdatedNotification = V2AccountRateLimitsUpdatedNotification;
|