@jingyi0605/codingns 0.5.5 → 0.6.1
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/bin/codingns.mjs +15 -2
- package/dist/public/assets/{AdaptiveButlerPage-CUyNL98E.js → AdaptiveButlerPage-Dw72U3hG.js} +3 -3
- package/dist/public/assets/App-CcDXqFl1.css +1 -0
- package/dist/public/assets/{App-BFP7LCSC.js → App-Dsf3ooXU.js} +3 -3
- package/dist/public/assets/{BootstrapPage-G74dX2Us.js → BootstrapPage-CE0m1qSR.js} +1 -1
- package/dist/public/assets/ConversationPage-8wOY7SX-.js +4 -0
- package/dist/public/assets/{DesktopDetachPreviewPage-IV7oEdOX.js → DesktopDetachPreviewPage-Dxarr_Wf.js} +1 -1
- package/dist/public/assets/DesktopWindowPage-VytPwJ4c.js +2 -0
- package/dist/public/assets/FileContextPanel-DwFzLsOp.js +1 -0
- package/dist/public/assets/GitSidebar-CH6WqTrM.js +6 -0
- package/dist/public/assets/MobileCreateSessionSheet-DcxKM00P.js +1 -0
- package/dist/public/assets/{MobileTopHeaderFrame-COTc7cRr.js → MobileTopHeaderFrame-C5rIKQT6.js} +1 -1
- package/dist/public/assets/MobileWorkspaceSwitcherHeader-CfUnHgv_.js +1 -0
- package/dist/public/assets/RelayConnectEntryPage-CgMvVZwa.js +1 -0
- package/dist/public/assets/ServerSettingsModal-CFul__z1.js +1 -0
- package/dist/public/assets/SessionIndexPage-B-tRhBXC.js +1 -0
- package/dist/public/assets/SettingsPage-C9LGxSQZ.js +1 -0
- package/dist/public/assets/TerminalManagerPanel-BbORd-ee.js +1 -0
- package/dist/public/assets/{TerminalPage-DpsvQQVR.js → TerminalPage-DWHv6mlu.js} +19 -19
- package/dist/public/assets/TerminalRuntimeFallbackModal-B29YxbQe.js +1 -0
- package/dist/public/assets/ToolFilesPage-Dx9cv9hu.js +1 -0
- package/dist/public/assets/ToolGitPage-D7H3vAia.js +1 -0
- package/dist/public/assets/ToolProcessesPage-PqQWxsy-.js +1 -0
- package/dist/public/assets/ToolsHomePage-CX05Pe_4.js +1 -0
- package/dist/public/assets/WorkbenchLandingPage-CchkAC75.js +1 -0
- package/dist/public/assets/WorkbenchLayout-pOZvEqp7.js +3 -0
- package/dist/public/assets/{WorkbenchModal-CbDxaCOR.js → WorkbenchModal-ColqvV6a.js} +1 -1
- package/dist/public/assets/WorkbenchShellRoute-C0_h4lP6.js +1 -0
- package/dist/public/assets/WorkbenchShellRoute-RGZpA0_J.css +1 -0
- package/dist/public/assets/WorkspaceDebugDetailPage-Deqy2_pO.js +1 -0
- package/dist/public/assets/WorkspaceDetailPage-Cvf-ZdlB.js +1 -0
- package/dist/public/assets/WorkspaceHomePage-Dsyvqyk1.js +1 -0
- package/dist/public/assets/client-runtime-manager-DROQJ9v3.js +1 -0
- package/dist/public/assets/{file-tree-icon-BMKuc5pw.js → file-tree-icon-Bp3Ntt7u.js} +7 -7
- package/dist/public/assets/index-B84Po2NA.css +1 -0
- package/dist/public/assets/index-C-0oeG_5.js +42 -0
- package/dist/public/assets/legna-code-6TqgZ4Ls.png +0 -0
- package/dist/public/assets/login-direct-candidate-resolver-DotM530R.js +1 -0
- package/dist/public/assets/model-switch-api-Bh9nYslz.js +1 -0
- package/dist/public/assets/{preferences-service-gv_9vGKz.js → preferences-service-BG6GKG29.js} +1 -1
- package/dist/public/assets/relay-entry-pmr-c42O.js +1 -0
- package/dist/public/assets/session-runtime-machine-YN84QBlr.js +21 -0
- package/dist/public/assets/{styles-BWPBZvze.css → styles-CsEMfdaS.css} +1 -1
- package/dist/public/assets/{terminal-runtime-meta-B9xJGY__.js → terminal-runtime-meta-8_uRZf7h.js} +1 -1
- package/dist/public/assets/useRegisteredDebugTemplates-DWX7LXQu.js +1 -0
- package/dist/public/assets/window-BVUB8gMK.js +1 -0
- package/dist/public/index.html +2 -2
- package/dist/server/config/env.d.ts +3 -0
- package/dist/server/config/env.js +10 -0
- package/dist/server/config/env.js.map +1 -1
- package/dist/server/modules/client/npm-global-package-service.d.ts +7 -1
- package/dist/server/modules/client/npm-global-package-service.js +149 -43
- package/dist/server/modules/client/npm-global-package-service.js.map +1 -1
- package/dist/server/modules/client/service-update-task-service.js +6 -2
- package/dist/server/modules/client/service-update-task-service.js.map +1 -1
- package/dist/server/modules/client/service-update-types.d.ts +2 -0
- package/dist/server/modules/git/git-controller.d.ts +3 -0
- package/dist/server/modules/git/git-controller.js +3 -0
- package/dist/server/modules/git/git-controller.js.map +1 -1
- package/dist/server/modules/git/git-read-service.js +47 -1
- package/dist/server/modules/git/git-read-service.js.map +1 -1
- package/dist/server/modules/git/git-write-service.d.ts +4 -0
- package/dist/server/modules/git/git-write-service.js +24 -0
- package/dist/server/modules/git/git-write-service.js.map +1 -1
- package/dist/server/modules/git/types.d.ts +1 -0
- package/dist/server/modules/git/workspace-repo-guard.d.ts +2 -0
- package/dist/server/modules/git/workspace-repo-guard.js +24 -10
- package/dist/server/modules/git/workspace-repo-guard.js.map +1 -1
- package/dist/server/modules/model-switch/cc-switch-adapter.d.ts +7 -0
- package/dist/server/modules/model-switch/cc-switch-adapter.js +17 -0
- package/dist/server/modules/model-switch/cc-switch-adapter.js.map +1 -1
- package/dist/server/modules/parallel-sessions/parallel-session-controller.d.ts +57 -0
- package/dist/server/modules/parallel-sessions/parallel-session-controller.js +77 -0
- package/dist/server/modules/parallel-sessions/parallel-session-controller.js.map +1 -0
- package/dist/server/modules/parallel-sessions/parallel-session-group-service.d.ts +88 -0
- package/dist/server/modules/parallel-sessions/parallel-session-group-service.js +625 -0
- package/dist/server/modules/parallel-sessions/parallel-session-group-service.js.map +1 -0
- package/dist/server/modules/parallel-sessions/session-isolated-workspace-service.d.ts +56 -0
- package/dist/server/modules/parallel-sessions/session-isolated-workspace-service.js +483 -0
- package/dist/server/modules/parallel-sessions/session-isolated-workspace-service.js.map +1 -0
- package/dist/server/modules/provider/opencode-model-options.d.ts +1 -0
- package/dist/server/modules/provider/opencode-model-options.js +54 -12
- package/dist/server/modules/provider/opencode-model-options.js.map +1 -1
- package/dist/server/modules/provider/provider-controller.d.ts +6 -1
- package/dist/server/modules/provider/provider-controller.js +24 -2
- package/dist/server/modules/provider/provider-controller.js.map +1 -1
- package/dist/server/modules/provider/provider-discovery-helper-client.d.ts +2 -0
- package/dist/server/modules/provider/provider-discovery-helper-client.js.map +1 -1
- package/dist/server/modules/provider/provider-discovery-helper-process.js +1 -1
- package/dist/server/modules/provider/provider-discovery-helper-process.js.map +1 -1
- package/dist/server/modules/provider/provider-discovery-runtime.js +5 -1
- package/dist/server/modules/provider/provider-discovery-runtime.js.map +1 -1
- package/dist/server/modules/relay-tunnel/relay-tunnel-candidate-endpoints.d.ts +2 -0
- package/dist/server/modules/relay-tunnel/relay-tunnel-candidate-endpoints.js +129 -0
- package/dist/server/modules/relay-tunnel/relay-tunnel-candidate-endpoints.js.map +1 -0
- package/dist/server/modules/relay-tunnel/relay-tunnel-runtime-adapter.js +12 -9
- package/dist/server/modules/relay-tunnel/relay-tunnel-runtime-adapter.js.map +1 -1
- package/dist/server/modules/relay-tunnel/relay-tunnel-service.js +1 -128
- package/dist/server/modules/relay-tunnel/relay-tunnel-service.js.map +1 -1
- package/dist/server/modules/sessions/claude-runtime-helper-client.d.ts +1 -0
- package/dist/server/modules/sessions/claude-runtime-helper-client.js +14 -0
- package/dist/server/modules/sessions/claude-runtime-helper-client.js.map +1 -1
- package/dist/server/modules/sessions/codex-app-server-helper-client.d.ts +4 -0
- package/dist/server/modules/sessions/codex-app-server-helper-client.js +66 -45
- package/dist/server/modules/sessions/codex-app-server-helper-client.js.map +1 -1
- package/dist/server/modules/sessions/codex-app-server-helper-process.js +21 -2
- package/dist/server/modules/sessions/codex-app-server-helper-process.js.map +1 -1
- package/dist/server/modules/sessions/provider-session-delete-cli.js +2 -0
- package/dist/server/modules/sessions/provider-session-delete-cli.js.map +1 -1
- package/dist/server/modules/sessions/session-controller.d.ts +7 -0
- package/dist/server/modules/sessions/session-controller.js +22 -0
- package/dist/server/modules/sessions/session-controller.js.map +1 -1
- package/dist/server/modules/sessions/session-history-service.d.ts +21 -2
- package/dist/server/modules/sessions/session-history-service.js +425 -29
- package/dist/server/modules/sessions/session-history-service.js.map +1 -1
- package/dist/server/modules/sessions/session-live-runtime-service.d.ts +23 -2
- package/dist/server/modules/sessions/session-live-runtime-service.js +472 -74
- package/dist/server/modules/sessions/session-live-runtime-service.js.map +1 -1
- package/dist/server/modules/sessions/session-message-attachment-service.js +2 -2
- package/dist/server/modules/sessions/session-message-attachment-service.js.map +1 -1
- package/dist/server/modules/sessions/session-provider-config-service.d.ts +66 -0
- package/dist/server/modules/sessions/session-provider-config-service.js +821 -0
- package/dist/server/modules/sessions/session-provider-config-service.js.map +1 -0
- package/dist/server/modules/sessions/session-provider-error-mapper.d.ts +2 -0
- package/dist/server/modules/sessions/session-provider-error-mapper.js +42 -0
- package/dist/server/modules/sessions/session-provider-error-mapper.js.map +1 -1
- package/dist/server/modules/workbench/codex-archive-watcher.d.ts +16 -0
- package/dist/server/modules/workbench/codex-archive-watcher.js +50 -0
- package/dist/server/modules/workbench/codex-archive-watcher.js.map +1 -0
- package/dist/server/modules/workbench/workbench-service.d.ts +11 -2
- package/dist/server/modules/workbench/workbench-service.js +37 -8
- package/dist/server/modules/workbench/workbench-service.js.map +1 -1
- package/dist/server/modules/workbench/workspace-panel-snapshot-service.d.ts +1 -1
- package/dist/server/modules/workbench/workspace-panel-snapshot-service.js +26 -3
- package/dist/server/modules/workbench/workspace-panel-snapshot-service.js.map +1 -1
- package/dist/server/modules/workspace/workspace-service.d.ts +3 -1
- package/dist/server/modules/workspace/workspace-service.js +10 -2
- package/dist/server/modules/workspace/workspace-service.js.map +1 -1
- package/dist/server/modules/worktree/worktree-base-ref-resolver.d.ts +20 -0
- package/dist/server/modules/worktree/worktree-base-ref-resolver.js +111 -0
- package/dist/server/modules/worktree/worktree-base-ref-resolver.js.map +1 -0
- package/dist/server/modules/worktree/worktree-cleanup-service.js +9 -3
- package/dist/server/modules/worktree/worktree-cleanup-service.js.map +1 -1
- package/dist/server/modules/worktree/worktree-manager.d.ts +0 -1
- package/dist/server/modules/worktree/worktree-manager.js +14 -20
- package/dist/server/modules/worktree/worktree-manager.js.map +1 -1
- package/dist/server/routes/git.js +1 -0
- package/dist/server/routes/git.js.map +1 -1
- package/dist/server/routes/parallel-groups.d.ts +3 -0
- package/dist/server/routes/parallel-groups.js +9 -0
- package/dist/server/routes/parallel-groups.js.map +1 -0
- package/dist/server/server/create-server.d.ts +8 -0
- package/dist/server/server/create-server.js +48 -11
- package/dist/server/server/create-server.js.map +1 -1
- package/dist/server/server/workbench-runtime-terminal-sync.d.ts +14 -0
- package/dist/server/server/workbench-runtime-terminal-sync.js +17 -0
- package/dist/server/server/workbench-runtime-terminal-sync.js.map +1 -0
- package/dist/server/storage/repositories/parallel-session-group-repository.d.ts +11 -0
- package/dist/server/storage/repositories/parallel-session-group-repository.js +131 -0
- package/dist/server/storage/repositories/parallel-session-group-repository.js.map +1 -0
- package/dist/server/storage/repositories/parallel-session-member-repository.d.ts +12 -0
- package/dist/server/storage/repositories/parallel-session-member-repository.js +150 -0
- package/dist/server/storage/repositories/parallel-session-member-repository.js.map +1 -0
- package/dist/server/storage/repositories/session-binding-repository.js +44 -5
- package/dist/server/storage/repositories/session-binding-repository.js.map +1 -1
- package/dist/server/storage/repositories/session-index-repository.js +6 -0
- package/dist/server/storage/repositories/session-index-repository.js.map +1 -1
- package/dist/server/storage/repositories/session-isolated-workspace-repository.d.ts +15 -0
- package/dist/server/storage/repositories/session-isolated-workspace-repository.js +230 -0
- package/dist/server/storage/repositories/session-isolated-workspace-repository.js.map +1 -0
- package/dist/server/storage/sqlite/client.js +19 -0
- package/dist/server/storage/sqlite/client.js.map +1 -1
- package/dist/server/storage/sqlite/schema.sql +78 -0
- package/dist/server/types/domain.d.ts +78 -0
- package/dist/server/ws/workbench-ws-hub.d.ts +3 -1
- package/dist/server/ws/workbench-ws-hub.js +23 -4
- package/dist/server/ws/workbench-ws-hub.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/claude-message-utils.d.ts +5 -2
- package/node_modules/@codingns/session-sync-core/dist/claude-message-utils.js +40 -8
- package/node_modules/@codingns/session-sync-core/dist/claude-message-utils.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/index.d.ts +2 -0
- package/node_modules/@codingns/session-sync-core/dist/index.js +2 -0
- package/node_modules/@codingns/session-sync-core/dist/index.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.d.ts +10 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.js +110 -35
- package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/claude-session-store.d.ts +11 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/claude-session-store.js +105 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/claude-session-store.js.map +1 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/codex.d.ts +1 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/codex.js +34 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/codex.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/gemini.js +131 -39
- package/node_modules/@codingns/session-sync-core/dist/providers/gemini.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/legna-code.d.ts +9 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/legna-code.js +17 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/legna-code.js.map +1 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/opencode-shared.d.ts +8 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/opencode-shared.js +19 -6
- package/node_modules/@codingns/session-sync-core/dist/providers/opencode-shared.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/opencode.d.ts +1 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/opencode.js +13 -8
- package/node_modules/@codingns/session-sync-core/dist/providers/opencode.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.d.ts +3 -0
- package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.js +46 -22
- package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.d.ts +5 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.js +103 -51
- package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.d.ts +2 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js +528 -301
- package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/gemini-runtime.js +32 -8
- package/node_modules/@codingns/session-sync-core/dist/runtime/gemini-runtime.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/legna-runtime.d.ts +10 -0
- package/node_modules/@codingns/session-sync-core/dist/runtime/legna-runtime.js +16 -0
- package/node_modules/@codingns/session-sync-core/dist/runtime/legna-runtime.js.map +1 -0
- package/node_modules/@codingns/session-sync-core/dist/runtime/opencode-runtime.js +196 -15
- package/node_modules/@codingns/session-sync-core/dist/runtime/opencode-runtime.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/types.d.ts +2 -0
- package/node_modules/@codingns/session-sync-core/dist/types.d.ts +1 -1
- package/node_modules/@codingns/session-sync-core/dist/types.js +1 -1
- package/node_modules/@codingns/session-sync-core/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/dist/public/assets/App-DUAg5urj.css +0 -1
- package/dist/public/assets/ConversationPage-Bz0_tvvM.js +0 -2
- package/dist/public/assets/DesktopWindowPage-BBmHyRg5.js +0 -2
- package/dist/public/assets/FileContextPanel--FVTxDrq.js +0 -1
- package/dist/public/assets/GitSidebar-DAiSi9oc.js +0 -6
- package/dist/public/assets/MobileCreateSessionSheet-DqVwz_Hp.js +0 -1
- package/dist/public/assets/MobileSheet-D1lMrcvD.js +0 -1
- package/dist/public/assets/MobileWorkspaceSwitcherHeader-DJPV9ym2.js +0 -1
- package/dist/public/assets/RelayConnectEntryPage-dSwU8VzK.js +0 -1
- package/dist/public/assets/ServerSettingsModal-B34ms3ze.js +0 -1
- package/dist/public/assets/SessionIndexPage-D3tG1gmM.js +0 -1
- package/dist/public/assets/SettingsPage-B3-6-5GL.js +0 -1
- package/dist/public/assets/TerminalManagerPanel-DhuTEdzV.js +0 -1
- package/dist/public/assets/TerminalRuntimeFallbackModal-CNzOt5v5.js +0 -1
- package/dist/public/assets/ToolFilesPage-BX9QDi9Y.js +0 -1
- package/dist/public/assets/ToolGitPage-4VtFox3p.js +0 -1
- package/dist/public/assets/ToolProcessesPage-DZJC6Qnt.js +0 -1
- package/dist/public/assets/ToolsHomePage-D7JbrAWv.js +0 -1
- package/dist/public/assets/WorkbenchLandingPage-C0yqnzqh.js +0 -1
- package/dist/public/assets/WorkbenchLayout-Brlj8K3i.js +0 -3
- package/dist/public/assets/WorkbenchShellRoute-BMcnFadA.css +0 -1
- package/dist/public/assets/WorkbenchShellRoute-puGpdDFY.js +0 -1
- package/dist/public/assets/WorkspaceDebugDetailPage-fTGweC9N.js +0 -1
- package/dist/public/assets/WorkspaceDetailPage-BtaIzSDB.js +0 -1
- package/dist/public/assets/WorkspaceHomePage-CUmmYDrM.js +0 -1
- package/dist/public/assets/client-runtime-manager-RHFa_iWo.js +0 -1
- package/dist/public/assets/default-session-permission-mode-Cu5SreTG.js +0 -1
- package/dist/public/assets/index-Cq3ue0za.css +0 -1
- package/dist/public/assets/index-DEbFT-Aq.js +0 -42
- package/dist/public/assets/session-runtime-machine-Bfnxkk9B.js +0 -17
- package/dist/public/assets/useRegisteredDebugTemplates-CDfl54Wt.js +0 -1
- package/dist/public/assets/window-BWqRixxq.js +0 -1
- /package/dist/public/assets/{styles-CSUx5LGe.js → styles-DRVvx_kv.js} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { existsSync, readdirSync } from "node:fs";
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, writeFileSync } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { performance } from "node:perf_hooks";
|
|
4
|
-
import { ClaudeRuntimeAdapter, CodexRuntimeAdapter, GeminiRuntimeAdapter, KimiRuntimeAdapter, OpenCodeRuntimeAdapter, ProviderRuntimeService } from "@codingns/session-sync-core";
|
|
4
|
+
import { ClaudeRuntimeAdapter, CodexRuntimeAdapter, GeminiRuntimeAdapter, KimiRuntimeAdapter, LegnaRuntimeAdapter, OpenCodeRuntimeAdapter, ProviderRuntimeService } from "@codingns/session-sync-core";
|
|
5
5
|
import { AppError, isAppError } from "../../shared/errors/app-error.js";
|
|
6
6
|
import { createId } from "../../shared/utils/id.js";
|
|
7
7
|
import { isPerfDebugEnabled, logPerformance } from "../../shared/utils/perf-log.js";
|
|
@@ -9,11 +9,14 @@ import { logPermissionDebug } from "../../shared/utils/permission-debug-log.js";
|
|
|
9
9
|
import { nowIso } from "../../shared/utils/time.js";
|
|
10
10
|
import { SessionActivityAuthorityService } from "./session-activity-authority-service.js";
|
|
11
11
|
import { SessionPermissionRequestService } from "./session-permission-request-service.js";
|
|
12
|
-
import { mapSessionProviderError } from "./session-provider-error-mapper.js";
|
|
12
|
+
import { appendSessionProviderErrorContext, mapSessionProviderError } from "./session-provider-error-mapper.js";
|
|
13
13
|
import { ClaudeRuntimeHelperAdapter } from "./claude-runtime-helper-client.js";
|
|
14
14
|
import { CodexAppServerHelperClient } from "./codex-app-server-helper-client.js";
|
|
15
|
+
const OPENCODE_ORDER_DEBUG_ENABLED = /^(1|true|yes)$/i.test(process.env.CODINGNS_OPENCODE_ORDER_DEBUG?.trim() ?? "");
|
|
15
16
|
const RUNTIME_START_BINDING_WAIT_TIMEOUT_MS = 10_000;
|
|
16
17
|
const START_BINDING_POLL_INTERVAL_MS = 50;
|
|
18
|
+
const EXTERNAL_RUNTIME_INTERRUPT_SUPPRESSION_MS = 30_000;
|
|
19
|
+
const EXTERNAL_RUNTIME_SNAPSHOT_MAX_AGE_MS = 90_000;
|
|
17
20
|
export class SessionLiveRuntimeService {
|
|
18
21
|
sessionHistoryService;
|
|
19
22
|
sessionMessageAttachmentService;
|
|
@@ -25,12 +28,14 @@ export class SessionLiveRuntimeService {
|
|
|
25
28
|
sessionIndexRepository;
|
|
26
29
|
sessionStateRepository;
|
|
27
30
|
sessionStatusSnapshotRepository;
|
|
31
|
+
sessionProviderConfigService;
|
|
28
32
|
config;
|
|
29
33
|
providerRuntimeService;
|
|
30
34
|
sessionActivityAuthorityService;
|
|
31
35
|
sessionPermissionRequestService;
|
|
32
36
|
runtimeAdapterDisposables;
|
|
33
37
|
externalRuntimeSnapshots = new Map();
|
|
38
|
+
externalRuntimeInterruptSuppressions = new Map();
|
|
34
39
|
runtimeListeners = new Map();
|
|
35
40
|
terminalStateListeners = new Set();
|
|
36
41
|
deadRuntimeReconciliationSessions = new Set();
|
|
@@ -39,7 +44,7 @@ export class SessionLiveRuntimeService {
|
|
|
39
44
|
queueDispatchSessions = new Set();
|
|
40
45
|
queueRetryTimers = new Map();
|
|
41
46
|
pendingSendDebugTracesBySessionId = new Map();
|
|
42
|
-
constructor(sessionHistoryService, sessionMessageAttachmentService, workspaceService, sessionChangedFileService, sessionBindingRepository, authUserRepository, sessionSendQueueRepository, sessionIndexRepository, sessionStateRepository, sessionStatusSnapshotRepository, config, sessionActivityAuthorityService = new SessionActivityAuthorityService()) {
|
|
47
|
+
constructor(sessionHistoryService, sessionMessageAttachmentService, workspaceService, sessionChangedFileService, sessionBindingRepository, authUserRepository, sessionSendQueueRepository, sessionIndexRepository, sessionStateRepository, sessionStatusSnapshotRepository, sessionProviderConfigService, config, sessionActivityAuthorityService = new SessionActivityAuthorityService()) {
|
|
43
48
|
this.sessionHistoryService = sessionHistoryService;
|
|
44
49
|
this.sessionMessageAttachmentService = sessionMessageAttachmentService;
|
|
45
50
|
this.workspaceService = workspaceService;
|
|
@@ -50,6 +55,7 @@ export class SessionLiveRuntimeService {
|
|
|
50
55
|
this.sessionIndexRepository = sessionIndexRepository;
|
|
51
56
|
this.sessionStateRepository = sessionStateRepository;
|
|
52
57
|
this.sessionStatusSnapshotRepository = sessionStatusSnapshotRepository;
|
|
58
|
+
this.sessionProviderConfigService = sessionProviderConfigService;
|
|
53
59
|
this.config = config;
|
|
54
60
|
this.sessionActivityAuthorityService = sessionActivityAuthorityService;
|
|
55
61
|
this.sessionPermissionRequestService = new SessionPermissionRequestService(sessionHistoryService, sessionBindingRepository, authUserRepository, workspaceService, config, async (envelope) => {
|
|
@@ -76,7 +82,19 @@ export class SessionLiveRuntimeService {
|
|
|
76
82
|
});
|
|
77
83
|
try {
|
|
78
84
|
const capabilities = this.sessionHistoryService.getProviderCapabilitiesSnapshot(input.provider);
|
|
79
|
-
this.
|
|
85
|
+
const providerBinding = this.sessionProviderConfigService.prepareSessionBinding({
|
|
86
|
+
sessionId,
|
|
87
|
+
provider: input.provider,
|
|
88
|
+
providerConfigMode: input.providerConfigMode,
|
|
89
|
+
providerPresetId: input.providerPresetId ?? null
|
|
90
|
+
});
|
|
91
|
+
const providerLaunchContext = this.sessionProviderConfigService.resolveLaunchContext({
|
|
92
|
+
provider: input.provider,
|
|
93
|
+
providerConfigMode: providerBinding.providerConfigMode,
|
|
94
|
+
providerPresetId: providerBinding.providerPresetId,
|
|
95
|
+
runtimeHomeDir: providerBinding.runtimeHomeDir
|
|
96
|
+
});
|
|
97
|
+
this.ensurePendingSessionBinding(sessionId, workspace.id, input.provider, providerBinding);
|
|
80
98
|
const persistedAttachments = this.persistMessageAttachments(sessionId, input.clientRequestId, input.runtimeOptions?.attachments ?? []);
|
|
81
99
|
const providerPrompt = this.sessionMessageAttachmentService.buildProviderPrompt(input.provider, input.content, persistedAttachments.runtimeAttachments);
|
|
82
100
|
const providerInstructionFilePath = resolveRuntimeInstructionFilePath(input.provider, workspace.path, input.runtimeOptions?.providerInstructionFilePath ?? null);
|
|
@@ -90,6 +108,8 @@ export class SessionLiveRuntimeService {
|
|
|
90
108
|
provider: input.provider,
|
|
91
109
|
providerSessionId: null,
|
|
92
110
|
rawStoreRef: null,
|
|
111
|
+
runtimeHomeDir: providerLaunchContext.runtimeHomeDir,
|
|
112
|
+
runtimeEnv: providerLaunchContext.runtimeEnv,
|
|
93
113
|
sequenceBase: 1,
|
|
94
114
|
options: {
|
|
95
115
|
content: input.content,
|
|
@@ -101,7 +121,12 @@ export class SessionLiveRuntimeService {
|
|
|
101
121
|
providerInstructionFilePath,
|
|
102
122
|
attachments: persistedAttachments.runtimeAttachments
|
|
103
123
|
}
|
|
104
|
-
}, "start"
|
|
124
|
+
}, "start", {
|
|
125
|
+
provider: input.provider,
|
|
126
|
+
providerConfigMode: providerBinding.providerConfigMode,
|
|
127
|
+
providerPresetId: providerBinding.providerPresetId,
|
|
128
|
+
runtimeHomeDir: providerBinding.runtimeHomeDir
|
|
129
|
+
});
|
|
105
130
|
this.logSendDebugStep(debugTrace, "launch_runtime", launchRuntimeStartedAtMs, {
|
|
106
131
|
userId: input.userId
|
|
107
132
|
});
|
|
@@ -200,6 +225,7 @@ export class SessionLiveRuntimeService {
|
|
|
200
225
|
}
|
|
201
226
|
async enqueueLiveMessage(input) {
|
|
202
227
|
const session = await this.resolveQueueDispatchSession(input.sessionId, input.userId);
|
|
228
|
+
this.resolveEffectiveSessionProviderBinding(session, input);
|
|
203
229
|
this.persistMessageAttachments(input.sessionId, input.clientRequestId, input.runtimeOptions?.attachments ?? []);
|
|
204
230
|
const timestamp = nowIso();
|
|
205
231
|
const queueItem = {
|
|
@@ -435,7 +461,7 @@ export class SessionLiveRuntimeService {
|
|
|
435
461
|
async getSessionRuntime(sessionId, userId) {
|
|
436
462
|
const runtimeSessionId = this.resolveRuntimeSessionId(sessionId);
|
|
437
463
|
const runtimeSnapshot = this.getLiveRuntimeSnapshot(runtimeSessionId);
|
|
438
|
-
const externalRuntimeSnapshot = this.
|
|
464
|
+
const externalRuntimeSnapshot = this.getFreshExternalRuntimeSnapshot(runtimeSessionId);
|
|
439
465
|
const runtimeHasActiveRun = runtimeSnapshot ? isActiveRuntimeState(runtimeSnapshot.runningState) : false;
|
|
440
466
|
const externalHasActiveRun = externalRuntimeSnapshot
|
|
441
467
|
? isActiveRuntimeState(externalRuntimeSnapshot.runningState)
|
|
@@ -485,7 +511,7 @@ export class SessionLiveRuntimeService {
|
|
|
485
511
|
runningState: resolution.runningState,
|
|
486
512
|
hasActiveRun: externalHasActiveRun,
|
|
487
513
|
canAttach: false,
|
|
488
|
-
canInterrupt:
|
|
514
|
+
canInterrupt: externalHasActiveRun,
|
|
489
515
|
inRunInputMode: capabilities.inRunInputMode,
|
|
490
516
|
activityResolutionSource: resolution.activityResolutionSource,
|
|
491
517
|
activityConfidence: resolution.activityConfidence,
|
|
@@ -528,32 +554,59 @@ export class SessionLiveRuntimeService {
|
|
|
528
554
|
if (runtimeSnapshot) {
|
|
529
555
|
return createRuntimeActivityObservation(runtimeSessionId, runtimeSnapshot);
|
|
530
556
|
}
|
|
531
|
-
const externalRuntimeSnapshot = this.
|
|
557
|
+
const externalRuntimeSnapshot = this.getFreshExternalRuntimeSnapshot(runtimeSessionId);
|
|
532
558
|
if (externalRuntimeSnapshot) {
|
|
533
559
|
return createExternalRuntimeActivityObservation(runtimeSessionId, externalRuntimeSnapshot);
|
|
534
560
|
}
|
|
535
561
|
return null;
|
|
536
562
|
}
|
|
537
563
|
async interruptSession(sessionId, userId) {
|
|
538
|
-
this.sessionHistoryService.getSession(sessionId, userId);
|
|
564
|
+
const session = this.sessionHistoryService.getSession(sessionId, userId);
|
|
539
565
|
const runtimeSessionId = this.resolveRuntimeSessionId(sessionId);
|
|
540
566
|
const runtime = this.getLiveRuntimeSnapshot(runtimeSessionId);
|
|
541
|
-
const externalRuntimeSnapshot = this.
|
|
567
|
+
const externalRuntimeSnapshot = this.getFreshExternalRuntimeSnapshot(runtimeSessionId);
|
|
542
568
|
if (!runtime || (runtime.runningState !== "running" && runtime.runningState !== "starting")) {
|
|
569
|
+
if (runtime && !isActiveRuntimeState(runtime.runningState)) {
|
|
570
|
+
await this.reconcileTerminalRuntimeSnapshot(sessionId, runtime);
|
|
571
|
+
return {
|
|
572
|
+
sessionId,
|
|
573
|
+
interrupted: true,
|
|
574
|
+
detail: runtime.detail ?? "当前会话已结束,已自动同步状态"
|
|
575
|
+
};
|
|
576
|
+
}
|
|
543
577
|
if (externalRuntimeSnapshot && isActiveRuntimeState(externalRuntimeSnapshot.runningState)) {
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
578
|
+
const refreshedSession = await Promise.resolve(this.sessionHistoryService.refreshRuntimeFallbackSession(sessionId, userId)).catch(() => null);
|
|
579
|
+
if (refreshedSession && !isPendingSessionRunningState(refreshedSession.runningState)) {
|
|
580
|
+
await this.forceInterruptInactiveSession(sessionId);
|
|
581
|
+
return {
|
|
582
|
+
sessionId,
|
|
583
|
+
interrupted: true,
|
|
584
|
+
detail: "当前会话已停止,已自动同步状态"
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
await this.forceInterruptExternalSession(sessionId);
|
|
588
|
+
return {
|
|
589
|
+
sessionId,
|
|
590
|
+
interrupted: true,
|
|
591
|
+
detail: "Claude 外部运行当前无法直接中断,已强制清理本地运行状态"
|
|
592
|
+
};
|
|
550
593
|
}
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
594
|
+
const refreshedSession = isPendingSessionRunningState(session.runningState)
|
|
595
|
+
? await Promise.resolve(this.sessionHistoryService.refreshRuntimeFallbackSession(sessionId, userId)).catch(() => null)
|
|
596
|
+
: session;
|
|
597
|
+
if (refreshedSession && !isPendingSessionRunningState(refreshedSession.runningState)) {
|
|
598
|
+
return {
|
|
599
|
+
sessionId,
|
|
600
|
+
interrupted: true,
|
|
601
|
+
detail: "当前会话已停止,已自动同步状态"
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
await this.forceInterruptInactiveSession(sessionId);
|
|
605
|
+
return {
|
|
606
|
+
sessionId,
|
|
607
|
+
interrupted: true,
|
|
608
|
+
detail: "当前会话已停止,已自动修正残留运行状态"
|
|
609
|
+
};
|
|
557
610
|
}
|
|
558
611
|
const interrupted = await this.providerRuntimeService.interrupt(runtimeSessionId).catch((error) => {
|
|
559
612
|
if (error instanceof Error && error.message === "INTERRUPT_NOT_SUPPORTED") {
|
|
@@ -589,7 +642,7 @@ export class SessionLiveRuntimeService {
|
|
|
589
642
|
subscribeRuntime(sessionId, onEnvelope) {
|
|
590
643
|
const runtimeSessionId = this.resolveRuntimeSessionId(sessionId);
|
|
591
644
|
const runtimeSnapshot = this.getLiveRuntimeSnapshot(runtimeSessionId);
|
|
592
|
-
const externalRuntimeSnapshot = this.
|
|
645
|
+
const externalRuntimeSnapshot = this.getFreshExternalRuntimeSnapshot(runtimeSessionId);
|
|
593
646
|
const initialActivityEnvelope = this.buildSessionActivityEnvelope(sessionId, runtimeSessionId);
|
|
594
647
|
if (runtimeSnapshot) {
|
|
595
648
|
void onEnvelope({
|
|
@@ -619,6 +672,16 @@ export class SessionLiveRuntimeService {
|
|
|
619
672
|
if (!envelope) {
|
|
620
673
|
return;
|
|
621
674
|
}
|
|
675
|
+
logOpenCodeOrderEnvelopeDebug("runtime.envelope.forward", {
|
|
676
|
+
sessionId,
|
|
677
|
+
runtimeSessionId,
|
|
678
|
+
provider: event.provider ?? null,
|
|
679
|
+
eventType: event.type ?? null,
|
|
680
|
+
envelopeType: envelope.type,
|
|
681
|
+
message: "message" in envelope && envelope.message
|
|
682
|
+
? summarizeOpenCodeOrderMessage(envelope.message)
|
|
683
|
+
: null
|
|
684
|
+
});
|
|
622
685
|
await onEnvelope(envelope);
|
|
623
686
|
});
|
|
624
687
|
const externalSubscription = this.subscribeExternalRuntime(runtimeSessionId, async (envelope) => {
|
|
@@ -767,13 +830,13 @@ export class SessionLiveRuntimeService {
|
|
|
767
830
|
sessionId
|
|
768
831
|
};
|
|
769
832
|
}
|
|
770
|
-
const externalRuntimeSnapshot = this.
|
|
833
|
+
const externalRuntimeSnapshot = this.getFreshExternalRuntimeSnapshot(runtimeSessionId);
|
|
771
834
|
if (externalRuntimeSnapshot) {
|
|
772
835
|
const resolution = this.sessionActivityAuthorityService.observe(createExternalRuntimeActivityObservation(runtimeSessionId, externalRuntimeSnapshot));
|
|
773
836
|
return {
|
|
774
837
|
...this.mapResolutionToActivityEnvelope(resolution, {
|
|
775
838
|
hasActiveRun: isActiveRuntimeState(externalRuntimeSnapshot.runningState),
|
|
776
|
-
canInterrupt:
|
|
839
|
+
canInterrupt: isActiveRuntimeState(externalRuntimeSnapshot.runningState)
|
|
777
840
|
}),
|
|
778
841
|
sessionId
|
|
779
842
|
};
|
|
@@ -792,7 +855,7 @@ export class SessionLiveRuntimeService {
|
|
|
792
855
|
}
|
|
793
856
|
resolveRuntimeSessionId(sessionId) {
|
|
794
857
|
if (this.providerRuntimeService.getSnapshot(sessionId)
|
|
795
|
-
|| this.
|
|
858
|
+
|| this.getFreshExternalRuntimeSnapshot(sessionId)) {
|
|
796
859
|
return sessionId;
|
|
797
860
|
}
|
|
798
861
|
const listSnapshots = "listSnapshots" in this.providerRuntimeService
|
|
@@ -898,6 +961,12 @@ export class SessionLiveRuntimeService {
|
|
|
898
961
|
};
|
|
899
962
|
}
|
|
900
963
|
async applyExternalRuntimeUpdate(input) {
|
|
964
|
+
if (input.runningState === "running" && this.shouldIgnoreInterruptedExternalRuntime(input.sessionId)) {
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
if (input.runningState !== "running") {
|
|
968
|
+
this.clearExternalRuntimeInterruptSuppression(input.sessionId);
|
|
969
|
+
}
|
|
901
970
|
const userIds = this.authUserRepository.listIds();
|
|
902
971
|
if (userIds.length === 0) {
|
|
903
972
|
return;
|
|
@@ -991,13 +1060,14 @@ export class SessionLiveRuntimeService {
|
|
|
991
1060
|
void this.dispatchNextQueuedMessage(input.sessionId);
|
|
992
1061
|
}
|
|
993
1062
|
}
|
|
994
|
-
async startRuntimeRun(request, userId, mode) {
|
|
1063
|
+
async startRuntimeRun(request, userId, mode, providerBinding) {
|
|
995
1064
|
this.runtimeMessageSeenSessions.delete(request.sessionId);
|
|
996
1065
|
this.runtimeHistoryFallbackSentSessions.delete(request.sessionId);
|
|
1066
|
+
this.clearExternalRuntimeInterruptSuppression(request.sessionId);
|
|
997
1067
|
if (request.provider === "claude-code") {
|
|
998
1068
|
this.clearExternalRuntimeSnapshot(request.sessionId);
|
|
999
1069
|
}
|
|
1000
|
-
const handle = await this.launchRuntimeRun(request, mode);
|
|
1070
|
+
const handle = await this.launchRuntimeRun(request, mode, providerBinding);
|
|
1001
1071
|
const snapshot = handle.getSnapshot();
|
|
1002
1072
|
const currentState = this.sessionStateRepository.findBySessionAndUser(request.sessionId, userId);
|
|
1003
1073
|
this.attachRuntimePersistence(handle, request.sessionId, request.workspaceId, userId);
|
|
@@ -1029,9 +1099,43 @@ export class SessionLiveRuntimeService {
|
|
|
1029
1099
|
const capabilities = await this.sessionHistoryService.getSessionCapabilities(input.sessionId);
|
|
1030
1100
|
const workspace = this.workspaceService.getWorkspaceOrThrow(session.workspaceId);
|
|
1031
1101
|
const runtimeMode = shouldStartNativeSessionOnFirstMessage(session);
|
|
1102
|
+
const existingBinding = this.getSessionBindingOrThrow(session.sessionId);
|
|
1103
|
+
const resolvedProviderBinding = this.resolveRequestedSessionProviderBinding(session, input, existingBinding);
|
|
1104
|
+
const runtimeSessionId = this.resolveRuntimeSessionId(input.sessionId);
|
|
1105
|
+
const activeRun = this.getLiveRuntimeSnapshot(runtimeSessionId);
|
|
1106
|
+
const externalRuntimeSnapshot = this.getFreshExternalRuntimeSnapshot(runtimeSessionId);
|
|
1107
|
+
const hasActiveRun = Boolean(activeRun && isActiveRuntimeState(activeRun.runningState));
|
|
1108
|
+
if (hasActiveRun && activeRun?.provider === "claude-code") {
|
|
1109
|
+
this.clearExternalRuntimeSnapshot(runtimeSessionId);
|
|
1110
|
+
}
|
|
1111
|
+
if (hasActiveRun
|
|
1112
|
+
|| (!activeRun &&
|
|
1113
|
+
session.provider === "claude-code" &&
|
|
1114
|
+
externalRuntimeSnapshot &&
|
|
1115
|
+
isActiveRuntimeState(externalRuntimeSnapshot.runningState))) {
|
|
1116
|
+
this.assertProviderBindingStableDuringActiveRun(existingBinding, resolvedProviderBinding);
|
|
1117
|
+
}
|
|
1118
|
+
if (!activeRun &&
|
|
1119
|
+
session.provider === "claude-code" &&
|
|
1120
|
+
externalRuntimeSnapshot &&
|
|
1121
|
+
isActiveRuntimeState(externalRuntimeSnapshot.runningState)) {
|
|
1122
|
+
throw new AppError({
|
|
1123
|
+
statusCode: 409,
|
|
1124
|
+
errorCode: "SESSION_EXTERNAL_RUN_ACTIVE",
|
|
1125
|
+
detail: "当前 Claude 外部会话仍在运行,不能直接追加;请加入队列或等待当前轮结束",
|
|
1126
|
+
field: "sessionId"
|
|
1127
|
+
});
|
|
1128
|
+
}
|
|
1129
|
+
const providerBinding = hasActiveRun
|
|
1130
|
+
? existingBinding
|
|
1131
|
+
: this.persistResolvedSessionProviderBinding(existingBinding, resolvedProviderBinding);
|
|
1132
|
+
const providerLaunchContext = this.sessionProviderConfigService.resolveLaunchContext(providerBinding);
|
|
1032
1133
|
const syntheticForkRawStoreRef = runtimeMode === "start" && shouldResumeCodexSyntheticForkSession(session)
|
|
1033
1134
|
? session.rawStoreRef
|
|
1034
1135
|
: null;
|
|
1136
|
+
const runtimeRawStoreRef = runtimeMode === "start"
|
|
1137
|
+
? syntheticForkRawStoreRef
|
|
1138
|
+
: await this.resolveCodexRuntimeRequestRawStoreRef(session, providerBinding);
|
|
1035
1139
|
const nextUserSequence = runtimeMode === "start"
|
|
1036
1140
|
? 1
|
|
1037
1141
|
: await this.resolveNextUserSequence(input.sessionId, session.messageCount);
|
|
@@ -1046,7 +1150,9 @@ export class SessionLiveRuntimeService {
|
|
|
1046
1150
|
workspacePath: workspace.path,
|
|
1047
1151
|
provider: session.provider,
|
|
1048
1152
|
providerSessionId: runtimeMode === "start" ? null : session.providerSessionId,
|
|
1049
|
-
rawStoreRef:
|
|
1153
|
+
rawStoreRef: runtimeRawStoreRef,
|
|
1154
|
+
runtimeHomeDir: providerLaunchContext.runtimeHomeDir,
|
|
1155
|
+
runtimeEnv: providerLaunchContext.runtimeEnv,
|
|
1050
1156
|
sequenceBase: nextUserSequence,
|
|
1051
1157
|
options: {
|
|
1052
1158
|
content: input.content,
|
|
@@ -1059,26 +1165,7 @@ export class SessionLiveRuntimeService {
|
|
|
1059
1165
|
attachments: resolvedAttachments.runtimeAttachments
|
|
1060
1166
|
}
|
|
1061
1167
|
};
|
|
1062
|
-
|
|
1063
|
-
const activeRun = this.getLiveRuntimeSnapshot(runtimeSessionId);
|
|
1064
|
-
const externalRuntimeSnapshot = this.externalRuntimeSnapshots.get(runtimeSessionId);
|
|
1065
|
-
if (activeRun &&
|
|
1066
|
-
activeRun.provider === "claude-code" &&
|
|
1067
|
-
isActiveRuntimeState(activeRun.runningState)) {
|
|
1068
|
-
this.clearExternalRuntimeSnapshot(runtimeSessionId);
|
|
1069
|
-
}
|
|
1070
|
-
if (!activeRun &&
|
|
1071
|
-
session.provider === "claude-code" &&
|
|
1072
|
-
externalRuntimeSnapshot &&
|
|
1073
|
-
isActiveRuntimeState(externalRuntimeSnapshot.runningState)) {
|
|
1074
|
-
throw new AppError({
|
|
1075
|
-
statusCode: 409,
|
|
1076
|
-
errorCode: "SESSION_EXTERNAL_RUN_ACTIVE",
|
|
1077
|
-
detail: "当前 Claude 外部会话仍在运行,不能直接追加;请加入队列或等待当前轮结束",
|
|
1078
|
-
field: "sessionId"
|
|
1079
|
-
});
|
|
1080
|
-
}
|
|
1081
|
-
if (activeRun && isActiveRuntimeState(activeRun.runningState)) {
|
|
1168
|
+
if (hasActiveRun) {
|
|
1082
1169
|
const submitStartedAtMs = performance.now();
|
|
1083
1170
|
try {
|
|
1084
1171
|
await this.providerRuntimeService.submitToActiveRun(runtimeSessionId, runtimeRequest.options);
|
|
@@ -1088,13 +1175,23 @@ export class SessionLiveRuntimeService {
|
|
|
1088
1175
|
});
|
|
1089
1176
|
}
|
|
1090
1177
|
catch (error) {
|
|
1091
|
-
const mapped = mapSessionProviderError(error)
|
|
1178
|
+
const mapped = appendSessionProviderErrorContext(mapSessionProviderError(error), this.sessionProviderConfigService.describeBinding({
|
|
1179
|
+
provider: session.provider,
|
|
1180
|
+
providerConfigMode: providerBinding.providerConfigMode,
|
|
1181
|
+
providerPresetId: providerBinding.providerPresetId,
|
|
1182
|
+
runtimeHomeDir: providerBinding.runtimeHomeDir
|
|
1183
|
+
}));
|
|
1092
1184
|
// 运行时句柄还没来得及收尾时,steer 可能会撞上 provider 已终态。
|
|
1093
1185
|
// 这里直接失败只会把一条正常消息变成偶发 409,属于纯粹的坏味道。
|
|
1094
1186
|
if (mapped.errorCode === "SESSION_NOT_RUNNING") {
|
|
1095
1187
|
await this.providerRuntimeService.abandonRun(runtimeSessionId);
|
|
1096
1188
|
const restartRuntimeStartedAtMs = performance.now();
|
|
1097
|
-
await this.startRuntimeRun(runtimeRequest, input.userId, runtimeMode
|
|
1189
|
+
await this.startRuntimeRun(runtimeRequest, input.userId, runtimeMode, {
|
|
1190
|
+
provider: session.provider,
|
|
1191
|
+
providerConfigMode: providerBinding.providerConfigMode,
|
|
1192
|
+
providerPresetId: providerBinding.providerPresetId,
|
|
1193
|
+
runtimeHomeDir: providerBinding.runtimeHomeDir
|
|
1194
|
+
});
|
|
1098
1195
|
this.logSendDebugStep(debugTrace, "restart_runtime_after_stale_active_run", restartRuntimeStartedAtMs, {
|
|
1099
1196
|
runtimeMode
|
|
1100
1197
|
});
|
|
@@ -1106,7 +1203,12 @@ export class SessionLiveRuntimeService {
|
|
|
1106
1203
|
}
|
|
1107
1204
|
else {
|
|
1108
1205
|
const startRuntimeStartedAtMs = performance.now();
|
|
1109
|
-
await this.startRuntimeRun(runtimeRequest, input.userId, runtimeMode
|
|
1206
|
+
await this.startRuntimeRun(runtimeRequest, input.userId, runtimeMode, {
|
|
1207
|
+
provider: session.provider,
|
|
1208
|
+
providerConfigMode: providerBinding.providerConfigMode,
|
|
1209
|
+
providerPresetId: providerBinding.providerPresetId,
|
|
1210
|
+
runtimeHomeDir: providerBinding.runtimeHomeDir
|
|
1211
|
+
});
|
|
1110
1212
|
this.logSendDebugStep(debugTrace, "start_runtime_run", startRuntimeStartedAtMs, {
|
|
1111
1213
|
runtimeMode
|
|
1112
1214
|
});
|
|
@@ -1156,7 +1258,7 @@ export class SessionLiveRuntimeService {
|
|
|
1156
1258
|
this.queueDispatchSessions.add(sessionId);
|
|
1157
1259
|
try {
|
|
1158
1260
|
const runtimeSnapshot = this.getLiveRuntimeSnapshot(sessionId);
|
|
1159
|
-
const externalRuntimeSnapshot = this.
|
|
1261
|
+
const externalRuntimeSnapshot = this.getFreshExternalRuntimeSnapshot(sessionId);
|
|
1160
1262
|
if ((runtimeSnapshot && isActiveRuntimeState(runtimeSnapshot.runningState))
|
|
1161
1263
|
|| (externalRuntimeSnapshot && isActiveRuntimeState(externalRuntimeSnapshot.runningState))) {
|
|
1162
1264
|
return;
|
|
@@ -1222,7 +1324,7 @@ export class SessionLiveRuntimeService {
|
|
|
1222
1324
|
if (runtimeSnapshot && isActiveRuntimeState(runtimeSnapshot.runningState)) {
|
|
1223
1325
|
return true;
|
|
1224
1326
|
}
|
|
1225
|
-
const externalRuntimeSnapshot = this.
|
|
1327
|
+
const externalRuntimeSnapshot = this.getFreshExternalRuntimeSnapshot(session.sessionId);
|
|
1226
1328
|
if (externalRuntimeSnapshot && isActiveRuntimeState(externalRuntimeSnapshot.runningState)) {
|
|
1227
1329
|
return true;
|
|
1228
1330
|
}
|
|
@@ -1259,7 +1361,7 @@ export class SessionLiveRuntimeService {
|
|
|
1259
1361
|
return session;
|
|
1260
1362
|
}
|
|
1261
1363
|
const runtimeSnapshot = this.getLiveRuntimeSnapshot(sessionId);
|
|
1262
|
-
const externalRuntimeSnapshot = this.
|
|
1364
|
+
const externalRuntimeSnapshot = this.getFreshExternalRuntimeSnapshot(sessionId);
|
|
1263
1365
|
if ((runtimeSnapshot && isActiveRuntimeState(runtimeSnapshot.runningState))
|
|
1264
1366
|
|| (externalRuntimeSnapshot && isActiveRuntimeState(externalRuntimeSnapshot.runningState))) {
|
|
1265
1367
|
return session;
|
|
@@ -1268,14 +1370,18 @@ export class SessionLiveRuntimeService {
|
|
|
1268
1370
|
.then((refreshedSession) => refreshedSession ?? session)
|
|
1269
1371
|
.catch(() => session);
|
|
1270
1372
|
}
|
|
1271
|
-
async launchRuntimeRun(request, mode) {
|
|
1373
|
+
async launchRuntimeRun(request, mode, providerBinding) {
|
|
1272
1374
|
try {
|
|
1273
1375
|
return await (mode === "start"
|
|
1274
1376
|
? this.providerRuntimeService.startSession(request)
|
|
1275
1377
|
: this.providerRuntimeService.continueSession(request));
|
|
1276
1378
|
}
|
|
1277
1379
|
catch (error) {
|
|
1278
|
-
|
|
1380
|
+
const mapped = mapSessionProviderError(error);
|
|
1381
|
+
if (!providerBinding) {
|
|
1382
|
+
throw mapped;
|
|
1383
|
+
}
|
|
1384
|
+
throw appendSessionProviderErrorContext(mapped, this.sessionProviderConfigService.describeBinding(providerBinding));
|
|
1279
1385
|
}
|
|
1280
1386
|
}
|
|
1281
1387
|
attachRuntimePersistence(handle, sessionId, workspaceId, userId) {
|
|
@@ -1353,8 +1459,109 @@ export class SessionLiveRuntimeService {
|
|
|
1353
1459
|
});
|
|
1354
1460
|
this.sessionActivityAuthorityService.observe(createRuntimeActivityObservation(input.sessionId, input.snapshot));
|
|
1355
1461
|
}
|
|
1356
|
-
ensurePendingSessionBinding(sessionId, workspaceId, provider) {
|
|
1357
|
-
|
|
1462
|
+
ensurePendingSessionBinding(sessionId, workspaceId, provider, providerBinding) {
|
|
1463
|
+
const snapshot = this.buildBindingSnapshot(sessionId, provider, null, null);
|
|
1464
|
+
const timestamp = nowIso();
|
|
1465
|
+
const existingBinding = this.sessionBindingRepository.findBySessionId(sessionId);
|
|
1466
|
+
this.sessionBindingRepository.upsert({
|
|
1467
|
+
sessionId,
|
|
1468
|
+
workspaceId,
|
|
1469
|
+
provider: snapshot.provider,
|
|
1470
|
+
providerSessionId: snapshot.providerSessionId,
|
|
1471
|
+
rawStoreRef: snapshot.rawStoreRef,
|
|
1472
|
+
providerConfigMode: providerBinding?.providerConfigMode ?? existingBinding?.providerConfigMode ?? "global-default",
|
|
1473
|
+
providerPresetId: providerBinding?.providerPresetId ?? existingBinding?.providerPresetId ?? null,
|
|
1474
|
+
runtimeHomeDir: providerBinding?.runtimeHomeDir ?? existingBinding?.runtimeHomeDir ?? null,
|
|
1475
|
+
createdAt: existingBinding?.createdAt ?? timestamp,
|
|
1476
|
+
updatedAt: timestamp
|
|
1477
|
+
});
|
|
1478
|
+
}
|
|
1479
|
+
resolveEffectiveSessionProviderBinding(session, input) {
|
|
1480
|
+
const existingBinding = this.getSessionBindingOrThrow(session.sessionId);
|
|
1481
|
+
const providerBinding = this.resolveRequestedSessionProviderBinding(session, input, existingBinding);
|
|
1482
|
+
return this.persistResolvedSessionProviderBinding(existingBinding, providerBinding);
|
|
1483
|
+
}
|
|
1484
|
+
getSessionBindingOrThrow(sessionId) {
|
|
1485
|
+
const existingBinding = this.sessionBindingRepository.findBySessionId(sessionId);
|
|
1486
|
+
if (!existingBinding) {
|
|
1487
|
+
throw new AppError({
|
|
1488
|
+
statusCode: 404,
|
|
1489
|
+
errorCode: "SESSION_NOT_FOUND",
|
|
1490
|
+
detail: "session 不存在"
|
|
1491
|
+
});
|
|
1492
|
+
}
|
|
1493
|
+
return existingBinding;
|
|
1494
|
+
}
|
|
1495
|
+
resolveRequestedSessionProviderBinding(session, input, existingBinding) {
|
|
1496
|
+
return this.sessionProviderConfigService.resolveSessionBinding({
|
|
1497
|
+
sessionId: session.sessionId,
|
|
1498
|
+
provider: session.provider,
|
|
1499
|
+
existingBinding,
|
|
1500
|
+
providerConfigMode: input.providerConfigMode,
|
|
1501
|
+
providerPresetId: input.providerPresetId ?? null
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1504
|
+
persistResolvedSessionProviderBinding(existingBinding, providerBinding) {
|
|
1505
|
+
if (!this.hasSessionProviderBindingChanged(existingBinding, providerBinding)) {
|
|
1506
|
+
return existingBinding;
|
|
1507
|
+
}
|
|
1508
|
+
const nextBinding = {
|
|
1509
|
+
...existingBinding,
|
|
1510
|
+
providerConfigMode: providerBinding.providerConfigMode,
|
|
1511
|
+
providerPresetId: providerBinding.providerPresetId,
|
|
1512
|
+
runtimeHomeDir: providerBinding.runtimeHomeDir,
|
|
1513
|
+
updatedAt: nowIso()
|
|
1514
|
+
};
|
|
1515
|
+
this.sessionBindingRepository.upsert(nextBinding);
|
|
1516
|
+
return nextBinding;
|
|
1517
|
+
}
|
|
1518
|
+
assertProviderBindingStableDuringActiveRun(existingBinding, requestedBinding) {
|
|
1519
|
+
if (!this.hasSessionProviderBindingChanged(existingBinding, requestedBinding)) {
|
|
1520
|
+
return;
|
|
1521
|
+
}
|
|
1522
|
+
throw new AppError({
|
|
1523
|
+
statusCode: 409,
|
|
1524
|
+
errorCode: "SESSION_PROVIDER_CONFIG_CHANGE_REQUIRES_NEW_RUN",
|
|
1525
|
+
detail: "当前会话仍在执行,不能中途切换模型配置文件;请等本轮结束后再发起新一轮",
|
|
1526
|
+
field: "sessionId"
|
|
1527
|
+
});
|
|
1528
|
+
}
|
|
1529
|
+
hasSessionProviderBindingChanged(currentBinding, nextBinding) {
|
|
1530
|
+
return (currentBinding.providerConfigMode !== nextBinding.providerConfigMode
|
|
1531
|
+
|| normalizeOptionalBindingValue(currentBinding.providerPresetId)
|
|
1532
|
+
!== normalizeOptionalBindingValue(nextBinding.providerPresetId)
|
|
1533
|
+
|| normalizeOptionalBindingValue(currentBinding.runtimeHomeDir)
|
|
1534
|
+
!== normalizeOptionalBindingValue(nextBinding.runtimeHomeDir));
|
|
1535
|
+
}
|
|
1536
|
+
async resolveCodexRuntimeRequestRawStoreRef(session, providerBinding) {
|
|
1537
|
+
if (session.provider !== "codex") {
|
|
1538
|
+
return session.rawStoreRef;
|
|
1539
|
+
}
|
|
1540
|
+
const currentRawStoreRef = session.rawStoreRef?.trim() || null;
|
|
1541
|
+
if (currentRawStoreRef && existsSync(currentRawStoreRef)) {
|
|
1542
|
+
return currentRawStoreRef;
|
|
1543
|
+
}
|
|
1544
|
+
const messages = await Promise.resolve(this.sessionHistoryService.readAllTextHistoryMessages(session.sessionId)).catch(() => []);
|
|
1545
|
+
if (!Array.isArray(messages) || messages.length === 0) {
|
|
1546
|
+
return currentRawStoreRef;
|
|
1547
|
+
}
|
|
1548
|
+
const baseDir = providerBinding.runtimeHomeDir?.trim()
|
|
1549
|
+
|| path.resolve(path.dirname(this.config.databasePath), "runtime", "codex-resume-history");
|
|
1550
|
+
const syntheticDir = path.join(baseDir, ".codingns-synthetic-resume");
|
|
1551
|
+
const syntheticFilePath = path.join(syntheticDir, `${session.sessionId}.jsonl`);
|
|
1552
|
+
const serialized = messages
|
|
1553
|
+
.map((message) => JSON.stringify({
|
|
1554
|
+
timestamp: message.timestamp,
|
|
1555
|
+
type: "event_msg",
|
|
1556
|
+
payload: {
|
|
1557
|
+
type: message.role === "assistant" ? "agent_message" : "user_message",
|
|
1558
|
+
message: message.content
|
|
1559
|
+
}
|
|
1560
|
+
}))
|
|
1561
|
+
.join("\n");
|
|
1562
|
+
mkdirSync(syntheticDir, { recursive: true });
|
|
1563
|
+
writeFileSync(syntheticFilePath, `${serialized}\n`, "utf8");
|
|
1564
|
+
return syntheticFilePath;
|
|
1358
1565
|
}
|
|
1359
1566
|
buildBindingSnapshot(sessionId, provider, providerSessionId, rawStoreRef) {
|
|
1360
1567
|
const pendingValue = `pending://${provider}/${sessionId}`;
|
|
@@ -1482,6 +1689,112 @@ export class SessionLiveRuntimeService {
|
|
|
1482
1689
|
await listener(event);
|
|
1483
1690
|
}
|
|
1484
1691
|
}
|
|
1692
|
+
async reconcileTerminalRuntimeSnapshot(sessionId, runtime) {
|
|
1693
|
+
const timestamp = runtime.lastEventAt ?? runtime.completedAt ?? runtime.startedAt;
|
|
1694
|
+
const runningState = toStoredRunningState(runtime.runningState);
|
|
1695
|
+
const currentSnapshot = this.sessionStatusSnapshotRepository.findBySessionId(sessionId);
|
|
1696
|
+
for (const userId of this.authUserRepository.listIds()) {
|
|
1697
|
+
const current = this.sessionStateRepository.findBySessionAndUser(sessionId, userId);
|
|
1698
|
+
if (current?.lastEventAt
|
|
1699
|
+
&& current.lastEventAt.localeCompare(timestamp) > 0
|
|
1700
|
+
&& isTerminalSessionRunningState(current.runningState)) {
|
|
1701
|
+
continue;
|
|
1702
|
+
}
|
|
1703
|
+
this.sessionStateRepository.upsert({
|
|
1704
|
+
sessionId,
|
|
1705
|
+
userId,
|
|
1706
|
+
runningState,
|
|
1707
|
+
activitySource: "runtime",
|
|
1708
|
+
favorite: current?.favorite ?? false,
|
|
1709
|
+
lastEventAt: timestamp,
|
|
1710
|
+
completedAt: isTerminalSessionRunningState(runningState)
|
|
1711
|
+
? (runtime.completedAt ?? timestamp)
|
|
1712
|
+
: current?.completedAt ?? null,
|
|
1713
|
+
lastSeenAt: current?.lastSeenAt ?? null,
|
|
1714
|
+
updatedAt: nowIso()
|
|
1715
|
+
});
|
|
1716
|
+
}
|
|
1717
|
+
this.upsertSnapshot(sessionId, {
|
|
1718
|
+
syncStatus: runningState === "failed" ? "error" : "idle",
|
|
1719
|
+
syncCursor: currentSnapshot?.syncCursor ?? null,
|
|
1720
|
+
lastSyncAt: timestamp,
|
|
1721
|
+
lastErrorCode: runningState === "failed" ? runtime.errorCode ?? null : null,
|
|
1722
|
+
lastErrorDetail: runningState === "failed" ? runtime.detail ?? null : null,
|
|
1723
|
+
resumedAt: currentSnapshot?.resumedAt ?? null
|
|
1724
|
+
});
|
|
1725
|
+
this.sessionActivityAuthorityService.observe(createRuntimeActivityObservation(sessionId, runtime));
|
|
1726
|
+
await this.emitExternalRuntimeEnvelope({
|
|
1727
|
+
type: "session.runtime_status",
|
|
1728
|
+
sessionId,
|
|
1729
|
+
status: runtime.runningState,
|
|
1730
|
+
detail: runtime.detail,
|
|
1731
|
+
interruptSource: runtime.interruptSource,
|
|
1732
|
+
timestamp
|
|
1733
|
+
});
|
|
1734
|
+
if (isTerminalSessionRunningState(runningState)) {
|
|
1735
|
+
await this.emitTerminalStateEvent({
|
|
1736
|
+
sessionId,
|
|
1737
|
+
status: runningState,
|
|
1738
|
+
timestamp,
|
|
1739
|
+
detail: runtime.detail,
|
|
1740
|
+
source: "runtime"
|
|
1741
|
+
});
|
|
1742
|
+
void this.dispatchNextQueuedMessage(sessionId);
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
async forceInterruptInactiveSession(sessionId) {
|
|
1746
|
+
const timestamp = nowIso();
|
|
1747
|
+
const currentSnapshot = this.sessionStatusSnapshotRepository.findBySessionId(sessionId);
|
|
1748
|
+
for (const userId of this.authUserRepository.listIds()) {
|
|
1749
|
+
const current = this.sessionStateRepository.findBySessionAndUser(sessionId, userId);
|
|
1750
|
+
if (!current || !isPendingSessionRunningState(current.runningState)) {
|
|
1751
|
+
continue;
|
|
1752
|
+
}
|
|
1753
|
+
this.sessionStateRepository.upsert({
|
|
1754
|
+
...current,
|
|
1755
|
+
runningState: "interrupted",
|
|
1756
|
+
activitySource: "runtime",
|
|
1757
|
+
completedAt: timestamp,
|
|
1758
|
+
updatedAt: timestamp
|
|
1759
|
+
});
|
|
1760
|
+
}
|
|
1761
|
+
this.clearExternalRuntimeSnapshot(sessionId);
|
|
1762
|
+
this.upsertSnapshot(sessionId, {
|
|
1763
|
+
syncStatus: "idle",
|
|
1764
|
+
syncCursor: currentSnapshot?.syncCursor ?? null,
|
|
1765
|
+
lastSyncAt: timestamp,
|
|
1766
|
+
lastErrorCode: null,
|
|
1767
|
+
lastErrorDetail: null,
|
|
1768
|
+
resumedAt: currentSnapshot?.resumedAt ?? null
|
|
1769
|
+
});
|
|
1770
|
+
this.sessionActivityAuthorityService.observe({
|
|
1771
|
+
sessionId,
|
|
1772
|
+
runId: null,
|
|
1773
|
+
runningState: "interrupted",
|
|
1774
|
+
source: "authoritative_runtime",
|
|
1775
|
+
confidence: "strong",
|
|
1776
|
+
detail: "检测到会话实际已停止,已自动修正残留运行状态",
|
|
1777
|
+
interruptSource: "runtime",
|
|
1778
|
+
errorCode: null,
|
|
1779
|
+
observedAt: timestamp
|
|
1780
|
+
});
|
|
1781
|
+
await this.emitExternalRuntimeEnvelope({
|
|
1782
|
+
type: "session.runtime_status",
|
|
1783
|
+
sessionId,
|
|
1784
|
+
status: "interrupted",
|
|
1785
|
+
detail: "检测到会话实际已停止,已自动修正残留运行状态",
|
|
1786
|
+
interruptSource: "runtime",
|
|
1787
|
+
timestamp
|
|
1788
|
+
});
|
|
1789
|
+
await this.emitTerminalStateEvent({
|
|
1790
|
+
sessionId,
|
|
1791
|
+
status: "interrupted",
|
|
1792
|
+
timestamp,
|
|
1793
|
+
detail: "检测到会话实际已停止,已自动修正残留运行状态",
|
|
1794
|
+
source: "runtime"
|
|
1795
|
+
});
|
|
1796
|
+
void this.dispatchNextQueuedMessage(sessionId);
|
|
1797
|
+
}
|
|
1485
1798
|
beginPendingSendDebugTrace(input) {
|
|
1486
1799
|
if (!isPerfDebugEnabled()) {
|
|
1487
1800
|
return null;
|
|
@@ -1619,7 +1932,7 @@ export class SessionLiveRuntimeService {
|
|
|
1619
1932
|
}
|
|
1620
1933
|
}
|
|
1621
1934
|
async resolveNextUserSequence(sessionId, messageCount) {
|
|
1622
|
-
let maxSequence =
|
|
1935
|
+
let maxSequence = 0;
|
|
1623
1936
|
const envelope = await Promise.resolve(this.sessionHistoryService.readRecentHistoryEnvelope(sessionId, 10)).catch(() => {
|
|
1624
1937
|
return null;
|
|
1625
1938
|
});
|
|
@@ -1628,6 +1941,9 @@ export class SessionLiveRuntimeService {
|
|
|
1628
1941
|
maxSequence = message.sequence;
|
|
1629
1942
|
}
|
|
1630
1943
|
}
|
|
1944
|
+
if (maxSequence <= 0) {
|
|
1945
|
+
maxSequence = Math.max(messageCount, 0);
|
|
1946
|
+
}
|
|
1631
1947
|
return Math.max(maxSequence + 1, 1);
|
|
1632
1948
|
}
|
|
1633
1949
|
async waitForResolvedStartBinding(sessionId, workspaceId, provider, handle) {
|
|
@@ -1764,6 +2080,39 @@ export class SessionLiveRuntimeService {
|
|
|
1764
2080
|
clearExternalRuntimeSnapshot(sessionId) {
|
|
1765
2081
|
this.externalRuntimeSnapshots.delete(sessionId);
|
|
1766
2082
|
}
|
|
2083
|
+
getFreshExternalRuntimeSnapshot(sessionId) {
|
|
2084
|
+
const snapshot = this.externalRuntimeSnapshots.get(sessionId) ?? null;
|
|
2085
|
+
if (!snapshot) {
|
|
2086
|
+
return null;
|
|
2087
|
+
}
|
|
2088
|
+
if (!isExternalRuntimeSnapshotExpired(snapshot)) {
|
|
2089
|
+
return snapshot;
|
|
2090
|
+
}
|
|
2091
|
+
this.clearExternalRuntimeSnapshot(sessionId);
|
|
2092
|
+
this.sessionActivityAuthorityService.clearSession(sessionId);
|
|
2093
|
+
return null;
|
|
2094
|
+
}
|
|
2095
|
+
suppressInterruptedExternalRuntime(sessionId) {
|
|
2096
|
+
this.externalRuntimeInterruptSuppressions.set(sessionId, Date.now() + EXTERNAL_RUNTIME_INTERRUPT_SUPPRESSION_MS);
|
|
2097
|
+
}
|
|
2098
|
+
clearExternalRuntimeInterruptSuppression(sessionId) {
|
|
2099
|
+
this.externalRuntimeInterruptSuppressions.delete(sessionId);
|
|
2100
|
+
}
|
|
2101
|
+
shouldIgnoreInterruptedExternalRuntime(sessionId) {
|
|
2102
|
+
const expiresAt = this.externalRuntimeInterruptSuppressions.get(sessionId);
|
|
2103
|
+
if (!expiresAt) {
|
|
2104
|
+
return false;
|
|
2105
|
+
}
|
|
2106
|
+
if (Date.now() >= expiresAt) {
|
|
2107
|
+
this.externalRuntimeInterruptSuppressions.delete(sessionId);
|
|
2108
|
+
return false;
|
|
2109
|
+
}
|
|
2110
|
+
return true;
|
|
2111
|
+
}
|
|
2112
|
+
async forceInterruptExternalSession(sessionId) {
|
|
2113
|
+
this.suppressInterruptedExternalRuntime(sessionId);
|
|
2114
|
+
await this.forceInterruptInactiveSession(sessionId);
|
|
2115
|
+
}
|
|
1767
2116
|
async resolveActiveClaudePermissionSession(input) {
|
|
1768
2117
|
const activeSnapshots = this.providerRuntimeService
|
|
1769
2118
|
.listSnapshots()
|
|
@@ -1835,6 +2184,13 @@ function createExternalRuntimeActivityObservation(sessionId, snapshot) {
|
|
|
1835
2184
|
observedAt: snapshot.updatedAt
|
|
1836
2185
|
};
|
|
1837
2186
|
}
|
|
2187
|
+
function isExternalRuntimeSnapshotExpired(snapshot) {
|
|
2188
|
+
const updatedAtMs = Date.parse(snapshot.updatedAt);
|
|
2189
|
+
if (!Number.isFinite(updatedAtMs)) {
|
|
2190
|
+
return true;
|
|
2191
|
+
}
|
|
2192
|
+
return Date.now() - updatedAtMs > EXTERNAL_RUNTIME_SNAPSHOT_MAX_AGE_MS;
|
|
2193
|
+
}
|
|
1838
2194
|
function createRuntimeEventObservation(sessionId, event, startedAt) {
|
|
1839
2195
|
return {
|
|
1840
2196
|
sessionId,
|
|
@@ -2111,21 +2467,33 @@ function createProviderRuntimeAdapters(config, options = {}) {
|
|
|
2111
2467
|
if ("dispose" in claudeAdapter && typeof claudeAdapter.dispose === "function") {
|
|
2112
2468
|
disposables.push(claudeAdapter);
|
|
2113
2469
|
}
|
|
2114
|
-
const codexTransportHelper = process.env.VITEST
|
|
2115
|
-
? null
|
|
2116
|
-
: new CodexAppServerHelperClient(config.codexCliPath, {
|
|
2117
|
-
homeDir: config.codexHomeDir
|
|
2118
|
-
});
|
|
2119
|
-
if (codexTransportHelper) {
|
|
2120
|
-
disposables.push(codexTransportHelper);
|
|
2121
|
-
}
|
|
2122
2470
|
return {
|
|
2123
2471
|
adapters: [
|
|
2124
2472
|
claudeAdapter,
|
|
2473
|
+
new LegnaRuntimeAdapter({
|
|
2474
|
+
homeDir: config.legnaCodeHomeDir,
|
|
2475
|
+
commandPath: config.legnaCodeCliPath,
|
|
2476
|
+
legacyClaudeHomeDir: config.claudeCodeHomeDir
|
|
2477
|
+
}),
|
|
2125
2478
|
new CodexRuntimeAdapter({
|
|
2126
2479
|
homeDir: config.codexHomeDir,
|
|
2127
2480
|
commandPath: config.codexCliPath,
|
|
2128
|
-
transportFactory:
|
|
2481
|
+
transportFactory: process.env.VITEST
|
|
2482
|
+
? undefined
|
|
2483
|
+
: (request) => {
|
|
2484
|
+
const client = new CodexAppServerHelperClient(config.codexCliPath, {
|
|
2485
|
+
homeDir: request.runtimeHomeDir?.trim() || config.codexHomeDir,
|
|
2486
|
+
runtimeEnv: request.runtimeEnv ?? null
|
|
2487
|
+
});
|
|
2488
|
+
const transport = client.createTransport();
|
|
2489
|
+
return {
|
|
2490
|
+
...transport,
|
|
2491
|
+
close() {
|
|
2492
|
+
transport.close();
|
|
2493
|
+
client.dispose();
|
|
2494
|
+
}
|
|
2495
|
+
};
|
|
2496
|
+
},
|
|
2129
2497
|
handleServerRequest: options.handleCodexServerRequest
|
|
2130
2498
|
}),
|
|
2131
2499
|
new GeminiRuntimeAdapter({
|
|
@@ -2150,12 +2518,16 @@ function resolveRuntimeInstructionFilePath(provider, workspacePath, explicitFile
|
|
|
2150
2518
|
const resolvedExplicit = path.resolve(normalizedExplicit);
|
|
2151
2519
|
return existsSync(resolvedExplicit) ? resolvedExplicit : null;
|
|
2152
2520
|
}
|
|
2153
|
-
|
|
2521
|
+
const defaultInstructionPath = provider === "claude-code"
|
|
2522
|
+
? path.join(workspacePath, "CLAUDE.md")
|
|
2523
|
+
: provider === "legna-code"
|
|
2524
|
+
? path.join(workspacePath, "LEGNA.md")
|
|
2525
|
+
: null;
|
|
2526
|
+
if (!defaultInstructionPath) {
|
|
2154
2527
|
return null;
|
|
2155
2528
|
}
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
? path.resolve(defaultClaudeInstructionPath)
|
|
2529
|
+
return existsSync(defaultInstructionPath)
|
|
2530
|
+
? path.resolve(defaultInstructionPath)
|
|
2159
2531
|
: null;
|
|
2160
2532
|
}
|
|
2161
2533
|
function buildClaudeHookBridgeConfig(config) {
|
|
@@ -2215,4 +2587,30 @@ function workspaceSlug(workspacePath) {
|
|
|
2215
2587
|
.replaceAll("\\", "-")
|
|
2216
2588
|
.replaceAll("/", "-");
|
|
2217
2589
|
}
|
|
2590
|
+
function normalizeOptionalBindingValue(value) {
|
|
2591
|
+
const normalized = value?.trim();
|
|
2592
|
+
return normalized && normalized.length > 0 ? normalized : null;
|
|
2593
|
+
}
|
|
2594
|
+
function logOpenCodeOrderEnvelopeDebug(scope, detail) {
|
|
2595
|
+
if (!OPENCODE_ORDER_DEBUG_ENABLED) {
|
|
2596
|
+
return;
|
|
2597
|
+
}
|
|
2598
|
+
console.info(`[opencode-order-envelope] ${scope}`, {
|
|
2599
|
+
timestamp: new Date().toISOString(),
|
|
2600
|
+
...detail
|
|
2601
|
+
});
|
|
2602
|
+
}
|
|
2603
|
+
function summarizeOpenCodeOrderMessage(message) {
|
|
2604
|
+
const content = typeof message.content === "string" ? message.content : "";
|
|
2605
|
+
const normalized = content.replace(/\s+/g, " ").trim();
|
|
2606
|
+
return {
|
|
2607
|
+
messageId: message.messageId ?? null,
|
|
2608
|
+
role: message.role ?? null,
|
|
2609
|
+
kind: message.kind ?? null,
|
|
2610
|
+
sequence: message.sequence ?? null,
|
|
2611
|
+
timestamp: message.timestamp ?? null,
|
|
2612
|
+
rawRef: message.rawRef ?? null,
|
|
2613
|
+
contentPreview: normalized.length > 80 ? `${normalized.slice(0, 80)}...` : normalized
|
|
2614
|
+
};
|
|
2615
|
+
}
|
|
2218
2616
|
//# sourceMappingURL=session-live-runtime-service.js.map
|