@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,5 +1,5 @@
|
|
|
1
1
|
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
2
|
-
import { CapabilityService, ClaudeCodeAdapter, CodexAdapter, GeminiAdapter, KimiAdapter, OpenCodeAdapter, ProviderRegistry, SessionSyncService } from "@codingns/session-sync-core";
|
|
2
|
+
import { CapabilityService, ClaudeCodeAdapter, CodexAdapter, GeminiAdapter, KimiAdapter, LegnaCodeAdapter, OpenCodeAdapter, ProviderRegistry, SessionSyncService } from "@codingns/session-sync-core";
|
|
3
3
|
import { AppError } from "../../shared/errors/app-error.js";
|
|
4
4
|
import { hashContent } from "../../shared/utils/hash.js";
|
|
5
5
|
import { createId } from "../../shared/utils/id.js";
|
|
@@ -11,6 +11,7 @@ import { inspectSessionActivity } from "./session-activity-inspector.js";
|
|
|
11
11
|
import { SessionActivityAuthorityService } from "./session-activity-authority-service.js";
|
|
12
12
|
import { mapSessionProviderError } from "./session-provider-error-mapper.js";
|
|
13
13
|
import { SessionForkRepository } from "../../storage/repositories/session-fork-repository.js";
|
|
14
|
+
import { buildParallelGroupColorToken, resolveParallelDisplayParentSessionId } from "../parallel-sessions/parallel-session-group-service.js";
|
|
14
15
|
import { enrichClaudeCapabilities } from "../provider/claude-model-options.js";
|
|
15
16
|
import { CodexModelOptionsService, createFallbackCodexModelOptions, enrichCodexCapabilities } from "../provider/codex-model-options.js";
|
|
16
17
|
import { OpenCodeModelOptionsService, createFallbackOpenCodeModelOptions, enrichOpenCodeCapabilities } from "../provider/opencode-model-options.js";
|
|
@@ -24,13 +25,23 @@ const RECONSTRUCTED_FORK_TARGET_PROVIDERS = new Set(["codex", "claude-code", "op
|
|
|
24
25
|
const FORK_RECONSTRUCTION_PAGE_SIZE = 200;
|
|
25
26
|
const MAX_FORK_DEPTH = 4;
|
|
26
27
|
const SYNTHETIC_CODEX_SESSION_CLEANUP_GRACE_MS = 120_000;
|
|
28
|
+
const GEMINI_RUNTIME_CHAT_DISCOVERY_GRACE_MS = 30_000;
|
|
27
29
|
const SESSION_START_DEFERRED_PROVIDERS = new Set([
|
|
28
30
|
"codex",
|
|
29
31
|
"claude-code",
|
|
32
|
+
"legna-code",
|
|
30
33
|
"opencode",
|
|
31
34
|
"gemini",
|
|
32
35
|
"kimi"
|
|
33
36
|
]);
|
|
37
|
+
const MUTABLE_HISTORY_TAIL_PROVIDERS = new Set([
|
|
38
|
+
"claude-code",
|
|
39
|
+
"legna-code",
|
|
40
|
+
"codex",
|
|
41
|
+
"gemini",
|
|
42
|
+
"kimi",
|
|
43
|
+
"opencode"
|
|
44
|
+
]);
|
|
34
45
|
const MUTABLE_HISTORY_TAIL_REFRESH_INTERVAL_MS = 1_200;
|
|
35
46
|
const WORKSPACE_DISCOVERY_BACKGROUND_MAX_AGE_MS = 15_000;
|
|
36
47
|
const WORKSPACE_DISCOVERY_SCAN_CONCURRENCY = 2;
|
|
@@ -62,8 +73,12 @@ export class SessionHistoryService {
|
|
|
62
73
|
openCodeModelOptionsService;
|
|
63
74
|
providerCliCommandPaths;
|
|
64
75
|
providerCliAvailability;
|
|
76
|
+
parallelSessionGroupRepository;
|
|
77
|
+
parallelSessionMemberRepository;
|
|
78
|
+
sessionIsolatedWorkspaceRepository;
|
|
65
79
|
providerDiscoveryHelperClient = getSharedProviderDiscoveryHelperClient();
|
|
66
80
|
providerSessionDiscoveryConfig;
|
|
81
|
+
sessionProviderConfigService;
|
|
67
82
|
taskManager;
|
|
68
83
|
workspaceDiscoveryStatuses = new Map();
|
|
69
84
|
workspaceStateRefreshStatuses = new Map();
|
|
@@ -73,7 +88,7 @@ export class SessionHistoryService {
|
|
|
73
88
|
sessionDeletedObservers = new Set();
|
|
74
89
|
workspaceSessionRelations = new Map();
|
|
75
90
|
workspaceStateRefreshTaskSequence = 0;
|
|
76
|
-
constructor(db, workspaceRepository, sessionBindingRepository, sessionChangedFileService, sessionIndexRepository, sessionMessageAttachmentService, sessionStateRepository, sessionStatusSnapshotRepository, config, sessionActivityAuthorityService = new SessionActivityAuthorityService(), sessionMessageOriginRepository = null, sessionForkRepository = null, adapterOverrides = {}, taskManager = createTaskManager()) {
|
|
91
|
+
constructor(db, workspaceRepository, sessionBindingRepository, sessionChangedFileService, sessionIndexRepository, sessionMessageAttachmentService, sessionStateRepository, sessionStatusSnapshotRepository, config, sessionActivityAuthorityService = new SessionActivityAuthorityService(), sessionMessageOriginRepository = null, sessionForkRepository = null, adapterOverrides = {}, taskManager = createTaskManager(), parallelSessionGroupRepository = null, parallelSessionMemberRepository = null, sessionIsolatedWorkspaceRepository = null, sessionProviderConfigService = null) {
|
|
77
92
|
this.db = db;
|
|
78
93
|
this.workspaceRepository = workspaceRepository;
|
|
79
94
|
this.sessionBindingRepository = sessionBindingRepository;
|
|
@@ -88,9 +103,14 @@ export class SessionHistoryService {
|
|
|
88
103
|
this.providerSessionDeleteCli =
|
|
89
104
|
adapterOverrides.providerSessionDeleteCli ?? new CodingnsProviderSessionDeleteCli(config);
|
|
90
105
|
this.taskManager = taskManager;
|
|
106
|
+
this.parallelSessionGroupRepository = parallelSessionGroupRepository;
|
|
107
|
+
this.parallelSessionMemberRepository = parallelSessionMemberRepository;
|
|
108
|
+
this.sessionIsolatedWorkspaceRepository = sessionIsolatedWorkspaceRepository;
|
|
109
|
+
this.sessionProviderConfigService = sessionProviderConfigService;
|
|
91
110
|
this.claudeCodeHomeDir = config.claudeCodeHomeDir;
|
|
92
111
|
this.providerCliCommandPaths = {
|
|
93
112
|
"claude-code": process.platform === "win32" ? "claude.cmd" : "claude",
|
|
113
|
+
"legna-code": config.legnaCodeCliPath,
|
|
94
114
|
codex: config.codexCliPath,
|
|
95
115
|
gemini: config.geminiCliPath,
|
|
96
116
|
kimi: config.kimiCliPath
|
|
@@ -99,8 +119,10 @@ export class SessionHistoryService {
|
|
|
99
119
|
this.providerCliAvailability = buildProviderCliAvailabilitySnapshot(this.providerCliCommandPaths);
|
|
100
120
|
this.providerSessionDiscoveryConfig = {
|
|
101
121
|
claudeCodeHomeDir: config.claudeCodeHomeDir,
|
|
122
|
+
legnaCodeHomeDir: config.legnaCodeHomeDir,
|
|
102
123
|
codexCliPath: config.codexCliPath,
|
|
103
124
|
codexHomeDir: config.codexHomeDir,
|
|
125
|
+
legnaCodeCliPath: config.legnaCodeCliPath,
|
|
104
126
|
geminiCliPath: config.geminiCliPath,
|
|
105
127
|
geminiHomeDir: config.geminiHomeDir,
|
|
106
128
|
kimiDefaultModel: config.kimiDefaultModel,
|
|
@@ -111,6 +133,10 @@ export class SessionHistoryService {
|
|
|
111
133
|
};
|
|
112
134
|
this.providerRegistry = new ProviderRegistry([
|
|
113
135
|
new ClaudeCodeAdapter({ homeDir: config.claudeCodeHomeDir }),
|
|
136
|
+
new LegnaCodeAdapter({
|
|
137
|
+
homeDir: config.legnaCodeHomeDir,
|
|
138
|
+
legacyClaudeHomeDir: config.claudeCodeHomeDir
|
|
139
|
+
}),
|
|
114
140
|
new CodexAdapter({
|
|
115
141
|
homeDir: config.codexHomeDir,
|
|
116
142
|
forkTransportFactory: adapterOverrides.codexForkTransportFactory
|
|
@@ -309,8 +335,8 @@ export class SessionHistoryService {
|
|
|
309
335
|
? current?.syncCursor ?? page.cursor
|
|
310
336
|
: page.cursor,
|
|
311
337
|
lastSyncAt: nowIso(),
|
|
312
|
-
lastErrorCode: current?.lastErrorCode ?? null,
|
|
313
|
-
lastErrorDetail: current?.lastErrorDetail ?? null,
|
|
338
|
+
lastErrorCode: clearSuccessfulProviderReadErrorCode(current?.lastErrorCode ?? null),
|
|
339
|
+
lastErrorDetail: clearSuccessfulProviderReadErrorDetail(current?.lastErrorCode ?? null, current?.lastErrorDetail ?? null),
|
|
314
340
|
resumedAt: current?.resumedAt ?? null
|
|
315
341
|
});
|
|
316
342
|
snapshotIdleMs = Date.now() - snapshotIdleStartedAt;
|
|
@@ -423,9 +449,11 @@ export class SessionHistoryService {
|
|
|
423
449
|
return this.sessionChangedFileService.listBySessionId(sessionId);
|
|
424
450
|
}
|
|
425
451
|
listWorkspaceSessions(workspaceId, userId) {
|
|
426
|
-
|
|
452
|
+
const directItems = this.sessionIndexRepository
|
|
427
453
|
.listByWorkspace(workspaceId, userId)
|
|
428
|
-
.filter((item) => !this.isPendingSessionAlias(item))
|
|
454
|
+
.filter((item) => !this.isPendingSessionAlias(item));
|
|
455
|
+
const projectedItems = this.listProjectedIsolatedWorkspaceSessions(workspaceId, userId);
|
|
456
|
+
return this.enrichSessionItems(workspaceId, sortSessionListItemsByRecentActivity(mergeSessionListItemsBySessionId([...directItems, ...projectedItems])));
|
|
429
457
|
}
|
|
430
458
|
getProviderCapabilitiesSnapshot(provider) {
|
|
431
459
|
try {
|
|
@@ -439,6 +467,15 @@ export class SessionHistoryService {
|
|
|
439
467
|
try {
|
|
440
468
|
const workspacePath = workspaceId ? this.getWorkspaceOrThrow(workspaceId).path : null;
|
|
441
469
|
const baseCapabilities = this.applyProviderCliAvailability(this.capabilityService.getProviderCapabilities(provider));
|
|
470
|
+
if (baseCapabilities.provider === "opencode" && workspacePath) {
|
|
471
|
+
const refreshed = await this.enrichProviderCapabilities(baseCapabilities, workspacePath);
|
|
472
|
+
const cacheKey = buildProviderCapabilityCacheKey(baseCapabilities.provider, workspacePath);
|
|
473
|
+
this.providerCapabilityCache.set(cacheKey, {
|
|
474
|
+
refreshedAt: Date.now(),
|
|
475
|
+
value: refreshed
|
|
476
|
+
});
|
|
477
|
+
return refreshed;
|
|
478
|
+
}
|
|
442
479
|
this.scheduleProviderCapabilityRefresh(baseCapabilities, workspacePath);
|
|
443
480
|
return this.resolveProviderCapabilitiesImmediate(baseCapabilities, workspacePath);
|
|
444
481
|
}
|
|
@@ -454,6 +491,17 @@ export class SessionHistoryService {
|
|
|
454
491
|
.getSessionCapabilities(binding.provider, binding.providerSessionId)
|
|
455
492
|
.then((capabilities) => {
|
|
456
493
|
const normalizedCapabilities = this.applyProviderCliAvailability(capabilities);
|
|
494
|
+
if (normalizedCapabilities.provider === "opencode") {
|
|
495
|
+
return this.enrichProviderCapabilities(normalizedCapabilities, workspacePath)
|
|
496
|
+
.then((refreshed) => {
|
|
497
|
+
const cacheKey = buildProviderCapabilityCacheKey(normalizedCapabilities.provider, workspacePath);
|
|
498
|
+
this.providerCapabilityCache.set(cacheKey, {
|
|
499
|
+
refreshedAt: Date.now(),
|
|
500
|
+
value: refreshed
|
|
501
|
+
});
|
|
502
|
+
return refreshed;
|
|
503
|
+
});
|
|
504
|
+
}
|
|
457
505
|
this.scheduleProviderCapabilityRefresh(normalizedCapabilities, workspacePath);
|
|
458
506
|
return this.resolveProviderCapabilitiesImmediate(normalizedCapabilities, workspacePath);
|
|
459
507
|
})
|
|
@@ -594,11 +642,17 @@ export class SessionHistoryService {
|
|
|
594
642
|
async startSessionDirect(input) {
|
|
595
643
|
const workspace = this.getWorkspaceOrThrow(input.workspaceId);
|
|
596
644
|
this.assertProviderCapabilityEnabled(input.provider, "canStartSession", "当前 provider 不支持创建会话");
|
|
645
|
+
const sessionId = createId();
|
|
646
|
+
const providerBinding = this.prepareDirectSessionBinding({
|
|
647
|
+
sessionId,
|
|
648
|
+
provider: input.provider,
|
|
649
|
+
providerConfigMode: input.providerConfigMode ?? null,
|
|
650
|
+
providerPresetId: input.providerPresetId ?? null
|
|
651
|
+
});
|
|
597
652
|
try {
|
|
598
|
-
const result = await this.
|
|
653
|
+
const result = await this.startProviderSessionWithBinding(input.provider, workspace.path, providerBinding.runtimeHomeDir, {
|
|
599
654
|
initialPrompt: input.initialPrompt
|
|
600
655
|
});
|
|
601
|
-
const sessionId = createId();
|
|
602
656
|
const timestamp = nowIso();
|
|
603
657
|
const persist = this.db.transaction(() => {
|
|
604
658
|
this.sessionBindingRepository.upsert({
|
|
@@ -607,6 +661,9 @@ export class SessionHistoryService {
|
|
|
607
661
|
provider: result.session.provider,
|
|
608
662
|
providerSessionId: result.session.providerSessionId,
|
|
609
663
|
rawStoreRef: result.session.rawStoreRef,
|
|
664
|
+
providerConfigMode: providerBinding.providerConfigMode,
|
|
665
|
+
providerPresetId: providerBinding.providerPresetId,
|
|
666
|
+
runtimeHomeDir: providerBinding.runtimeHomeDir,
|
|
610
667
|
createdAt: timestamp,
|
|
611
668
|
updatedAt: timestamp
|
|
612
669
|
});
|
|
@@ -658,7 +715,8 @@ export class SessionHistoryService {
|
|
|
658
715
|
}
|
|
659
716
|
async forkSession(input) {
|
|
660
717
|
const binding = this.getBindingOrThrow(input.sessionId);
|
|
661
|
-
const
|
|
718
|
+
const targetWorkspaceId = input.targetWorkspaceId?.trim() || binding.workspaceId;
|
|
719
|
+
const workspace = this.getWorkspaceOrThrow(targetWorkspaceId);
|
|
662
720
|
const targetProvider = input.targetProvider?.trim() || binding.provider;
|
|
663
721
|
this.assertProviderCapabilityEnabled(targetProvider, "canStartSession", "当前 provider 不支持 fork 创建会话");
|
|
664
722
|
const sourceMessageId = input.sourceType === "message"
|
|
@@ -673,10 +731,18 @@ export class SessionHistoryService {
|
|
|
673
731
|
});
|
|
674
732
|
}
|
|
675
733
|
this.assertForkDepthWithinLimit(input.sessionId);
|
|
676
|
-
|
|
734
|
+
const requestedTargetSelection = resolveRequestedProviderSelection({
|
|
735
|
+
existingBinding: targetProvider === binding.provider ? binding : null,
|
|
736
|
+
providerConfigMode: input.providerConfigMode ?? undefined,
|
|
737
|
+
providerPresetId: input.providerPresetId ?? undefined
|
|
738
|
+
});
|
|
739
|
+
if (targetProvider !== binding.provider
|
|
740
|
+
|| !areEquivalentProviderBindingSelection(binding, requestedTargetSelection)) {
|
|
677
741
|
return this.forkSessionAcrossProviders({
|
|
678
742
|
...input,
|
|
679
|
-
targetProvider
|
|
743
|
+
targetProvider,
|
|
744
|
+
providerConfigMode: requestedTargetSelection.providerConfigMode,
|
|
745
|
+
providerPresetId: requestedTargetSelection.providerPresetId
|
|
680
746
|
}, binding, sourceMessageId);
|
|
681
747
|
}
|
|
682
748
|
try {
|
|
@@ -696,6 +762,9 @@ export class SessionHistoryService {
|
|
|
696
762
|
provider: result.session.provider,
|
|
697
763
|
providerSessionId: result.session.providerSessionId,
|
|
698
764
|
rawStoreRef: result.session.rawStoreRef,
|
|
765
|
+
providerConfigMode: binding.providerConfigMode,
|
|
766
|
+
providerPresetId: binding.providerPresetId,
|
|
767
|
+
runtimeHomeDir: binding.runtimeHomeDir,
|
|
699
768
|
createdAt: timestamp,
|
|
700
769
|
updatedAt: timestamp
|
|
701
770
|
});
|
|
@@ -786,10 +855,12 @@ export class SessionHistoryService {
|
|
|
786
855
|
messages: reconstructedMessages
|
|
787
856
|
});
|
|
788
857
|
const startedSession = await this.startSessionDirect({
|
|
789
|
-
workspaceId: sourceBinding.workspaceId,
|
|
858
|
+
workspaceId: input.targetWorkspaceId?.trim() || sourceBinding.workspaceId,
|
|
790
859
|
userId: input.userId,
|
|
791
860
|
provider: input.targetProvider,
|
|
792
861
|
initialPrompt: inheritedPrompt,
|
|
862
|
+
providerConfigMode: input.providerConfigMode ?? null,
|
|
863
|
+
providerPresetId: input.providerPresetId ?? null,
|
|
793
864
|
parentSessionId: input.sessionId,
|
|
794
865
|
sessionKind: input.sessionKind ?? "default",
|
|
795
866
|
annotationSourceMessageId: input.annotationSourceMessageId ?? null,
|
|
@@ -824,7 +895,7 @@ export class SessionHistoryService {
|
|
|
824
895
|
createdAt: timestamp
|
|
825
896
|
});
|
|
826
897
|
})();
|
|
827
|
-
const relationMap = this.workspaceSessionRelations.get(sourceBinding.workspaceId)
|
|
898
|
+
const relationMap = this.workspaceSessionRelations.get(input.targetWorkspaceId?.trim() || sourceBinding.workspaceId)
|
|
828
899
|
?? new Map();
|
|
829
900
|
relationMap.set(startedSession.sessionId, {
|
|
830
901
|
parentSessionId: input.sessionId,
|
|
@@ -834,9 +905,43 @@ export class SessionHistoryService {
|
|
|
834
905
|
isSubagent: startedSession.isSubagent ?? false,
|
|
835
906
|
subagentLabel: startedSession.subagentLabel ?? null
|
|
836
907
|
});
|
|
837
|
-
this.workspaceSessionRelations.set(sourceBinding.workspaceId, relationMap);
|
|
908
|
+
this.workspaceSessionRelations.set(input.targetWorkspaceId?.trim() || sourceBinding.workspaceId, relationMap);
|
|
838
909
|
return this.getSessionListItemOrThrow(startedSession.sessionId, input.userId);
|
|
839
910
|
}
|
|
911
|
+
prepareDirectSessionBinding(input) {
|
|
912
|
+
if (!this.sessionProviderConfigService) {
|
|
913
|
+
return {
|
|
914
|
+
providerConfigMode: "global-default",
|
|
915
|
+
providerPresetId: null,
|
|
916
|
+
runtimeHomeDir: null
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
return this.sessionProviderConfigService.prepareSessionBinding({
|
|
920
|
+
sessionId: input.sessionId,
|
|
921
|
+
provider: input.provider,
|
|
922
|
+
providerConfigMode: input.providerConfigMode ?? undefined,
|
|
923
|
+
providerPresetId: input.providerPresetId ?? null
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
startProviderSessionWithBinding(provider, workspacePath, runtimeHomeDir, options) {
|
|
927
|
+
const scopedRuntimeHomeDir = runtimeHomeDir?.trim() || null;
|
|
928
|
+
if (!scopedRuntimeHomeDir) {
|
|
929
|
+
return this.sessionSyncService.startSession(provider, workspacePath, options);
|
|
930
|
+
}
|
|
931
|
+
switch (provider) {
|
|
932
|
+
case "claude-code":
|
|
933
|
+
return new ClaudeCodeAdapter({ homeDir: scopedRuntimeHomeDir }).startSession(workspacePath, options);
|
|
934
|
+
case "codex":
|
|
935
|
+
return new CodexAdapter({ homeDir: scopedRuntimeHomeDir }).startSession(workspacePath, options);
|
|
936
|
+
case "gemini":
|
|
937
|
+
return new GeminiAdapter({
|
|
938
|
+
homeDir: scopedRuntimeHomeDir,
|
|
939
|
+
commandPath: this.providerSessionDiscoveryConfig.geminiCliPath
|
|
940
|
+
}).startSession(workspacePath, options);
|
|
941
|
+
default:
|
|
942
|
+
return this.sessionSyncService.startSession(provider, workspacePath, options);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
840
945
|
async readForkSourceMessages(sessionId, binding, sourceType, sourceMessageId, sourceMessageSnapshot = null) {
|
|
841
946
|
const messages = [];
|
|
842
947
|
let cursor = null;
|
|
@@ -1007,13 +1112,14 @@ export class SessionHistoryService {
|
|
|
1007
1112
|
return null;
|
|
1008
1113
|
}
|
|
1009
1114
|
await this.syncSessionTitleFromProvider(sessionId, binding);
|
|
1115
|
+
const snapshot = this.sessionStatusSnapshotRepository.findBySessionId(sessionId);
|
|
1010
1116
|
this.upsertSnapshot(sessionId, {
|
|
1011
1117
|
syncStatus: "idle",
|
|
1012
1118
|
syncCursor: page.cursor,
|
|
1013
1119
|
lastSyncAt: nowIso(),
|
|
1014
|
-
lastErrorCode:
|
|
1015
|
-
lastErrorDetail:
|
|
1016
|
-
resumedAt:
|
|
1120
|
+
lastErrorCode: clearSuccessfulProviderReadErrorCode(snapshot?.lastErrorCode ?? null),
|
|
1121
|
+
lastErrorDetail: clearSuccessfulProviderReadErrorDetail(snapshot?.lastErrorCode ?? null, snapshot?.lastErrorDetail ?? null),
|
|
1122
|
+
resumedAt: snapshot?.resumedAt ?? null
|
|
1017
1123
|
});
|
|
1018
1124
|
return {
|
|
1019
1125
|
type: "session.delta",
|
|
@@ -1125,7 +1231,10 @@ export class SessionHistoryService {
|
|
|
1125
1231
|
async deleteSession(sessionId, userId) {
|
|
1126
1232
|
const binding = this.getBindingOrThrow(sessionId);
|
|
1127
1233
|
const existing = this.getSessionListItemOrThrow(sessionId, userId);
|
|
1128
|
-
|
|
1234
|
+
const resolvedExisting = existing.runningState === "starting" || existing.runningState === "running"
|
|
1235
|
+
? await this.refreshRuntimeFallbackSession(sessionId, userId).catch(() => existing)
|
|
1236
|
+
: existing;
|
|
1237
|
+
if (resolvedExisting.runningState === "starting" || resolvedExisting.runningState === "running") {
|
|
1129
1238
|
throw new AppError({
|
|
1130
1239
|
statusCode: 409,
|
|
1131
1240
|
errorCode: "SESSION_DELETE_RUNNING",
|
|
@@ -1224,6 +1333,15 @@ export class SessionHistoryService {
|
|
|
1224
1333
|
provider: resolvedSnapshot.provider,
|
|
1225
1334
|
providerSessionId: resolvedSnapshot.providerSessionId,
|
|
1226
1335
|
rawStoreRef: resolvedSnapshot.rawStoreRef,
|
|
1336
|
+
providerConfigMode: currentBinding?.providerConfigMode
|
|
1337
|
+
?? duplicateBinding?.providerConfigMode
|
|
1338
|
+
?? "global-default",
|
|
1339
|
+
providerPresetId: currentBinding?.providerPresetId
|
|
1340
|
+
?? duplicateBinding?.providerPresetId
|
|
1341
|
+
?? null,
|
|
1342
|
+
runtimeHomeDir: currentBinding?.runtimeHomeDir
|
|
1343
|
+
?? duplicateBinding?.runtimeHomeDir
|
|
1344
|
+
?? null,
|
|
1227
1345
|
createdAt: pickEarlierIso(currentBinding?.createdAt ?? null, duplicateBinding?.createdAt ?? null)
|
|
1228
1346
|
?? timestamp,
|
|
1229
1347
|
updatedAt: timestamp
|
|
@@ -1315,6 +1433,9 @@ export class SessionHistoryService {
|
|
|
1315
1433
|
provider: session.provider,
|
|
1316
1434
|
providerSessionId: session.providerSessionId,
|
|
1317
1435
|
rawStoreRef: session.rawStoreRef,
|
|
1436
|
+
providerConfigMode: existing?.providerConfigMode ?? "global-default",
|
|
1437
|
+
providerPresetId: existing?.providerPresetId ?? null,
|
|
1438
|
+
runtimeHomeDir: existing?.runtimeHomeDir ?? null,
|
|
1318
1439
|
createdAt,
|
|
1319
1440
|
updatedAt: timestamp
|
|
1320
1441
|
};
|
|
@@ -1594,9 +1715,24 @@ export class SessionHistoryService {
|
|
|
1594
1715
|
total: 0
|
|
1595
1716
|
};
|
|
1596
1717
|
}
|
|
1718
|
+
if (this.shouldTreatMissingGeminiRuntimeHistoryAsEmpty(sessionId, provider, error)) {
|
|
1719
|
+
return {
|
|
1720
|
+
messages: [],
|
|
1721
|
+
cursor,
|
|
1722
|
+
nextCursor: null,
|
|
1723
|
+
total: 0
|
|
1724
|
+
};
|
|
1725
|
+
}
|
|
1597
1726
|
throw mapSessionProviderError(error);
|
|
1598
1727
|
});
|
|
1599
1728
|
}
|
|
1729
|
+
shouldTreatMissingGeminiRuntimeHistoryAsEmpty(sessionId, provider, error) {
|
|
1730
|
+
if (provider !== "gemini" || !isGeminiChatNotFoundError(error)) {
|
|
1731
|
+
return false;
|
|
1732
|
+
}
|
|
1733
|
+
const sessionIndex = this.sessionIndexRepository.findIndexRecordBySessionId(sessionId);
|
|
1734
|
+
return this.listSessionStatesBySessionId(sessionId).some((state) => shouldTreatMissingGeminiRuntimeHistoryStateAsTransient(state, sessionIndex));
|
|
1735
|
+
}
|
|
1600
1736
|
enrichMessagesWithOrigin(sessionId, messages) {
|
|
1601
1737
|
return this.resolveMessageOrigins(sessionId, messages);
|
|
1602
1738
|
}
|
|
@@ -1715,13 +1851,14 @@ export class SessionHistoryService {
|
|
|
1715
1851
|
}
|
|
1716
1852
|
enrichSessionItems(workspaceId, items) {
|
|
1717
1853
|
const relationMap = this.workspaceSessionRelations.get(workspaceId);
|
|
1854
|
+
const projectionBySessionId = this.buildParallelProjectionBySessionId(items);
|
|
1718
1855
|
if (!relationMap) {
|
|
1719
|
-
return items.map((item) => this.enrichSessionItem(item));
|
|
1856
|
+
return items.map((item) => this.enrichSessionItem(item, projectionBySessionId.get(item.sessionId)));
|
|
1720
1857
|
}
|
|
1721
1858
|
return items.map((item) => {
|
|
1722
1859
|
const relation = relationMap.get(item.sessionId);
|
|
1723
1860
|
if (!relation) {
|
|
1724
|
-
return this.enrichSessionItem(item);
|
|
1861
|
+
return this.enrichSessionItem(item, projectionBySessionId.get(item.sessionId));
|
|
1725
1862
|
}
|
|
1726
1863
|
return this.enrichSessionItem({
|
|
1727
1864
|
...item,
|
|
@@ -1731,10 +1868,12 @@ export class SessionHistoryService {
|
|
|
1731
1868
|
annotationSourceText: relation.annotationSourceText,
|
|
1732
1869
|
isSubagent: relation.isSubagent,
|
|
1733
1870
|
subagentLabel: relation.subagentLabel
|
|
1734
|
-
});
|
|
1871
|
+
}, projectionBySessionId.get(item.sessionId));
|
|
1735
1872
|
});
|
|
1736
1873
|
}
|
|
1737
|
-
enrichSessionItem(item) {
|
|
1874
|
+
enrichSessionItem(item, projection) {
|
|
1875
|
+
const resolvedProjection = projection
|
|
1876
|
+
?? this.buildParallelProjectionBySessionId([item]).get(item.sessionId);
|
|
1738
1877
|
const relation = this.workspaceSessionRelations.get(item.workspaceId)?.get(item.sessionId);
|
|
1739
1878
|
const nextItem = relation
|
|
1740
1879
|
? {
|
|
@@ -1756,7 +1895,90 @@ export class SessionHistoryService {
|
|
|
1756
1895
|
subagentLabel: item.subagentLabel ?? null
|
|
1757
1896
|
};
|
|
1758
1897
|
const resolution = this.sessionActivityAuthorityService.resolvePersistedSession(nextItem);
|
|
1759
|
-
return applySessionActivityResolution(
|
|
1898
|
+
return applySessionActivityResolution({
|
|
1899
|
+
...nextItem,
|
|
1900
|
+
parallelGroup: resolvedProjection?.parallelGroup ?? null,
|
|
1901
|
+
displayParentSessionId: resolvedProjection?.displayParentSessionId ?? null,
|
|
1902
|
+
sessionIsolatedWorkspace: resolvedProjection?.sessionIsolatedWorkspace ?? null
|
|
1903
|
+
}, resolution);
|
|
1904
|
+
}
|
|
1905
|
+
buildParallelProjectionBySessionId(items) {
|
|
1906
|
+
const projectionBySessionId = new Map();
|
|
1907
|
+
if (!this.parallelSessionGroupRepository
|
|
1908
|
+
|| !this.parallelSessionMemberRepository
|
|
1909
|
+
|| !this.sessionIsolatedWorkspaceRepository
|
|
1910
|
+
|| items.length === 0) {
|
|
1911
|
+
return projectionBySessionId;
|
|
1912
|
+
}
|
|
1913
|
+
const sessionIds = items.map((item) => item.sessionId);
|
|
1914
|
+
const members = this.parallelSessionMemberRepository
|
|
1915
|
+
.listBySessionIds(sessionIds)
|
|
1916
|
+
.filter((member) => member.deletedAt === null);
|
|
1917
|
+
if (members.length === 0) {
|
|
1918
|
+
return projectionBySessionId;
|
|
1919
|
+
}
|
|
1920
|
+
const groupIds = [...new Set(members.map((member) => member.groupId))];
|
|
1921
|
+
const groups = this.parallelSessionGroupRepository
|
|
1922
|
+
.listByIds(groupIds)
|
|
1923
|
+
.filter((group) => group.status !== "deleted");
|
|
1924
|
+
const groupById = new Map(groups.map((group) => [group.id, group]));
|
|
1925
|
+
const activeMembersByGroupId = new Map();
|
|
1926
|
+
for (const member of this.parallelSessionMemberRepository.listByGroupIds(groupIds)) {
|
|
1927
|
+
if (member.deletedAt !== null) {
|
|
1928
|
+
continue;
|
|
1929
|
+
}
|
|
1930
|
+
const groupMembers = activeMembersByGroupId.get(member.groupId) ?? [];
|
|
1931
|
+
groupMembers.push(member);
|
|
1932
|
+
activeMembersByGroupId.set(member.groupId, groupMembers);
|
|
1933
|
+
}
|
|
1934
|
+
const isolatedWorkspaceBySessionId = new Map(this.sessionIsolatedWorkspaceRepository
|
|
1935
|
+
.listByOwnerSessionIds(sessionIds)
|
|
1936
|
+
.map((record) => [record.ownerSessionId, record]));
|
|
1937
|
+
for (const member of members) {
|
|
1938
|
+
const group = groupById.get(member.groupId);
|
|
1939
|
+
if (!group) {
|
|
1940
|
+
continue;
|
|
1941
|
+
}
|
|
1942
|
+
const activeMembers = activeMembersByGroupId.get(member.groupId) ?? [member];
|
|
1943
|
+
const isolatedWorkspace = isolatedWorkspaceBySessionId.get(member.sessionId) ?? null;
|
|
1944
|
+
projectionBySessionId.set(member.sessionId, {
|
|
1945
|
+
parallelGroup: {
|
|
1946
|
+
groupId: group.id,
|
|
1947
|
+
role: member.sessionId === group.anchorSessionId ? "anchor" : "member",
|
|
1948
|
+
memberCount: activeMembers.length,
|
|
1949
|
+
sourceType: group.sourceType,
|
|
1950
|
+
sourceSessionId: group.sourceSessionId,
|
|
1951
|
+
anchorSessionId: group.anchorSessionId,
|
|
1952
|
+
colorToken: buildParallelGroupColorToken(group.id)
|
|
1953
|
+
},
|
|
1954
|
+
displayParentSessionId: resolveParallelDisplayParentSessionId(group, member),
|
|
1955
|
+
sessionIsolatedWorkspace: isolatedWorkspace
|
|
1956
|
+
? {
|
|
1957
|
+
id: isolatedWorkspace.id,
|
|
1958
|
+
workspaceId: isolatedWorkspace.workspaceId,
|
|
1959
|
+
sourceWorkspaceId: isolatedWorkspace.sourceWorkspaceId,
|
|
1960
|
+
branchName: isolatedWorkspace.branchName,
|
|
1961
|
+
lifecycleStatus: isolatedWorkspace.lifecycleStatus,
|
|
1962
|
+
promotedAt: isolatedWorkspace.promotedAt,
|
|
1963
|
+
createdAt: isolatedWorkspace.createdAt,
|
|
1964
|
+
updatedAt: isolatedWorkspace.updatedAt
|
|
1965
|
+
}
|
|
1966
|
+
: null
|
|
1967
|
+
});
|
|
1968
|
+
}
|
|
1969
|
+
return projectionBySessionId;
|
|
1970
|
+
}
|
|
1971
|
+
listProjectedIsolatedWorkspaceSessions(workspaceId, userId) {
|
|
1972
|
+
if (!this.sessionIsolatedWorkspaceRepository) {
|
|
1973
|
+
return [];
|
|
1974
|
+
}
|
|
1975
|
+
return this.sessionIsolatedWorkspaceRepository
|
|
1976
|
+
.listBySourceWorkspaceId(workspaceId)
|
|
1977
|
+
.filter((record) => record.lifecycleStatus === "active"
|
|
1978
|
+
|| record.lifecycleStatus === "removing")
|
|
1979
|
+
.map((record) => this.sessionIndexRepository.findBySessionId(record.ownerSessionId, userId))
|
|
1980
|
+
.filter((item) => Boolean(item))
|
|
1981
|
+
.filter((item) => !this.isPendingSessionAlias(item));
|
|
1760
1982
|
}
|
|
1761
1983
|
async pullSessionHistory(sessionId, cursor, limit, deliveredMessages, onEnvelope, envelopeType, isClosed = () => false) {
|
|
1762
1984
|
let currentCursor = cursor;
|
|
@@ -1803,8 +2025,8 @@ export class SessionHistoryService {
|
|
|
1803
2025
|
syncStatus: "idle",
|
|
1804
2026
|
syncCursor: page.cursor,
|
|
1805
2027
|
lastSyncAt: nowIso(),
|
|
1806
|
-
lastErrorCode: snapshot?.lastErrorCode ?? null,
|
|
1807
|
-
lastErrorDetail: snapshot?.lastErrorDetail ?? null,
|
|
2028
|
+
lastErrorCode: clearSuccessfulProviderReadErrorCode(snapshot?.lastErrorCode ?? null),
|
|
2029
|
+
lastErrorDetail: clearSuccessfulProviderReadErrorDetail(snapshot?.lastErrorCode ?? null, snapshot?.lastErrorDetail ?? null),
|
|
1808
2030
|
resumedAt: snapshot?.resumedAt ?? null
|
|
1809
2031
|
});
|
|
1810
2032
|
await onEnvelope({
|
|
@@ -1830,7 +2052,12 @@ export class SessionHistoryService {
|
|
|
1830
2052
|
provider: binding.provider,
|
|
1831
2053
|
providerSessionId: binding.providerSessionId,
|
|
1832
2054
|
rawStoreRef: binding.rawStoreRef
|
|
1833
|
-
}, signal)
|
|
2055
|
+
}, signal).catch((error) => {
|
|
2056
|
+
if (this.shouldTreatMissingGeminiRuntimeHistoryAsEmpty(sessionId, binding.provider, error)) {
|
|
2057
|
+
return "";
|
|
2058
|
+
}
|
|
2059
|
+
throw error;
|
|
2060
|
+
})).trim();
|
|
1834
2061
|
const resolvedTitle = resolvePersistedSessionTitle(binding.provider, nextTitle, currentIndex.title);
|
|
1835
2062
|
if (resolvedTitle.length === 0 || resolvedTitle === currentIndex.title) {
|
|
1836
2063
|
return;
|
|
@@ -2265,6 +2492,9 @@ export class SessionHistoryService {
|
|
|
2265
2492
|
provider: input.provider,
|
|
2266
2493
|
providerSessionId: buildPendingBindingValue(input.provider, input.targetSessionId),
|
|
2267
2494
|
rawStoreRef: buildPendingBindingValue(input.provider, input.targetSessionId),
|
|
2495
|
+
providerConfigMode: sourceBinding.providerConfigMode,
|
|
2496
|
+
providerPresetId: sourceBinding.providerPresetId,
|
|
2497
|
+
runtimeHomeDir: sourceBinding.runtimeHomeDir,
|
|
2268
2498
|
createdAt: sourceBinding.createdAt,
|
|
2269
2499
|
updatedAt: input.timestamp
|
|
2270
2500
|
});
|
|
@@ -2346,6 +2576,9 @@ export class SessionHistoryService {
|
|
|
2346
2576
|
provider: sourceBinding.provider,
|
|
2347
2577
|
providerSessionId: buildAliasBindingValue(input.provider, input.targetSessionId, input.sourceSessionId),
|
|
2348
2578
|
rawStoreRef: buildAliasBindingValue(input.provider, input.targetSessionId, input.sourceSessionId),
|
|
2579
|
+
providerConfigMode: sourceBinding.providerConfigMode,
|
|
2580
|
+
providerPresetId: sourceBinding.providerPresetId,
|
|
2581
|
+
runtimeHomeDir: sourceBinding.runtimeHomeDir,
|
|
2349
2582
|
createdAt: sourceBinding.createdAt,
|
|
2350
2583
|
updatedAt: input.timestamp
|
|
2351
2584
|
});
|
|
@@ -2584,7 +2817,9 @@ export class SessionHistoryService {
|
|
|
2584
2817
|
const liveObservation = this.resolveLiveActivityObservation(sessionId);
|
|
2585
2818
|
const inspection = liveObservation
|
|
2586
2819
|
? null
|
|
2587
|
-
:
|
|
2820
|
+
: binding.provider === "gemini"
|
|
2821
|
+
? await this.inspectGeminiHistoryActivity(sessionId, binding)
|
|
2822
|
+
: inspectSessionActivity(binding.provider, binding.rawStoreRef);
|
|
2588
2823
|
if (inspection) {
|
|
2589
2824
|
const nowMs = Date.parse(timestamp);
|
|
2590
2825
|
if (shouldClearStaleRuntimeWithoutInspection(current, inspection, nowMs)) {
|
|
@@ -2647,6 +2882,15 @@ export class SessionHistoryService {
|
|
|
2647
2882
|
});
|
|
2648
2883
|
return nextRecord;
|
|
2649
2884
|
}
|
|
2885
|
+
async inspectGeminiHistoryActivity(sessionId, binding) {
|
|
2886
|
+
try {
|
|
2887
|
+
const page = await this.readPage(sessionId, binding.provider, binding.providerSessionId, binding.rawStoreRef, null, GEMINI_ACTIVITY_INFERENCE_HISTORY_LIMIT, "backward", this.sessionIndexRepository.findIndexRecordBySessionId(sessionId)?.messageCount ?? null);
|
|
2888
|
+
return inferGeminiInspectionFromHistory(page.messages);
|
|
2889
|
+
}
|
|
2890
|
+
catch {
|
|
2891
|
+
return inspectSessionActivity(binding.provider, binding.rawStoreRef);
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
2650
2894
|
async repairCodexDirtyBindingBeforeHistoryRead(sessionId, userId, binding) {
|
|
2651
2895
|
if (!shouldRepairCodexDirtyBinding(binding)) {
|
|
2652
2896
|
this.codexDirtyBindingRepairStates.delete(sessionId);
|
|
@@ -2723,7 +2967,11 @@ export class SessionHistoryService {
|
|
|
2723
2967
|
}
|
|
2724
2968
|
}
|
|
2725
2969
|
function isProviderCliBacked(provider) {
|
|
2726
|
-
return provider === "claude-code"
|
|
2970
|
+
return provider === "claude-code"
|
|
2971
|
+
|| provider === "legna-code"
|
|
2972
|
+
|| provider === "codex"
|
|
2973
|
+
|| provider === "gemini"
|
|
2974
|
+
|| provider === "kimi";
|
|
2727
2975
|
}
|
|
2728
2976
|
function buildProviderCliAvailabilitySnapshot(commandPaths) {
|
|
2729
2977
|
return Object.freeze(Object.fromEntries(Object.entries(commandPaths).map(([provider, commandPath]) => [
|
|
@@ -2735,6 +2983,8 @@ function buildProviderCliUnavailableMessage(provider) {
|
|
|
2735
2983
|
switch (provider) {
|
|
2736
2984
|
case "claude-code":
|
|
2737
2985
|
return "未检测到 Claude CLI";
|
|
2986
|
+
case "legna-code":
|
|
2987
|
+
return "未检测到 Legna CLI";
|
|
2738
2988
|
case "codex":
|
|
2739
2989
|
return "未检测到 Codex CLI";
|
|
2740
2990
|
case "gemini":
|
|
@@ -2794,6 +3044,46 @@ function hasInspectionEvidence(inspection) {
|
|
|
2794
3044
|
|| !!inspection.lastEventAt
|
|
2795
3045
|
|| !!inspection.completedAtCandidate;
|
|
2796
3046
|
}
|
|
3047
|
+
function inferGeminiInspectionFromHistory(messages) {
|
|
3048
|
+
let lastEventAt = null;
|
|
3049
|
+
let lastUserAt = null;
|
|
3050
|
+
let latestNonUserMessage = null;
|
|
3051
|
+
const pendingToolCallIds = new Set();
|
|
3052
|
+
for (const message of messages) {
|
|
3053
|
+
lastEventAt = pickLaterIso(lastEventAt, message.timestamp);
|
|
3054
|
+
if (message.role === "user") {
|
|
3055
|
+
lastUserAt = pickLaterIso(lastUserAt, message.timestamp);
|
|
3056
|
+
continue;
|
|
3057
|
+
}
|
|
3058
|
+
latestNonUserMessage = message;
|
|
3059
|
+
if (message.kind === "tool_call" && message.toolCall?.callId) {
|
|
3060
|
+
pendingToolCallIds.add(message.toolCall.callId);
|
|
3061
|
+
continue;
|
|
3062
|
+
}
|
|
3063
|
+
if (message.kind === "tool_result" && message.toolCall?.callId) {
|
|
3064
|
+
pendingToolCallIds.delete(message.toolCall.callId);
|
|
3065
|
+
}
|
|
3066
|
+
}
|
|
3067
|
+
const latestNonUserAt = latestNonUserMessage?.timestamp ?? null;
|
|
3068
|
+
const hasReplyAfterLatestUser = !!latestNonUserAt && (!lastUserAt || latestNonUserAt.localeCompare(lastUserAt) >= 0);
|
|
3069
|
+
const isTerminalReplyKind = latestNonUserMessage?.kind === "text" || latestNonUserMessage?.kind === "tool_result";
|
|
3070
|
+
const completedAtCandidate = hasReplyAfterLatestUser && isTerminalReplyKind && pendingToolCallIds.size === 0
|
|
3071
|
+
? latestNonUserAt
|
|
3072
|
+
: null;
|
|
3073
|
+
const hasOpenTurn = !completedAtCandidate
|
|
3074
|
+
&& hasReplyAfterLatestUser
|
|
3075
|
+
&& (pendingToolCallIds.size > 0
|
|
3076
|
+
|| latestNonUserMessage?.kind === "thinking"
|
|
3077
|
+
|| latestNonUserMessage?.kind === "tool_call");
|
|
3078
|
+
return {
|
|
3079
|
+
runningState: hasOpenTurn ? "running" : "idle",
|
|
3080
|
+
hasPendingTools: pendingToolCallIds.size > 0,
|
|
3081
|
+
lastEventAt,
|
|
3082
|
+
completedAtCandidate,
|
|
3083
|
+
errorCode: null,
|
|
3084
|
+
errorDetail: null
|
|
3085
|
+
};
|
|
3086
|
+
}
|
|
2797
3087
|
function applySessionActivityResolution(item, resolution) {
|
|
2798
3088
|
const rawResolvedRunningState = resolution.runningState === "unknown" && item.runningState === null
|
|
2799
3089
|
? null
|
|
@@ -3289,7 +3579,7 @@ function createDeliveredHistoryMessageState() {
|
|
|
3289
3579
|
};
|
|
3290
3580
|
}
|
|
3291
3581
|
function shouldRefreshMutableHistoryTail(provider, page, cursor, deliveredMessages) {
|
|
3292
|
-
if (provider
|
|
3582
|
+
if (!MUTABLE_HISTORY_TAIL_PROVIDERS.has(provider) || cursor === null || page.messages.length > 0) {
|
|
3293
3583
|
return false;
|
|
3294
3584
|
}
|
|
3295
3585
|
return Date.now() - deliveredMessages.lastMutableTailRefreshAtMs >= MUTABLE_HISTORY_TAIL_REFRESH_INTERVAL_MS;
|
|
@@ -3347,6 +3637,40 @@ function shouldTreatMissingSyntheticHistoryAsEmpty(provider, rawStoreRef, error)
|
|
|
3347
3637
|
const detail = error instanceof Error ? error.message : String(error);
|
|
3348
3638
|
return detail.includes("ENOENT");
|
|
3349
3639
|
}
|
|
3640
|
+
function shouldTreatMissingGeminiRuntimeHistoryStateAsTransient(state, sessionIndex) {
|
|
3641
|
+
if (state.activitySource !== "runtime") {
|
|
3642
|
+
return false;
|
|
3643
|
+
}
|
|
3644
|
+
if (state.runningState === "starting" || state.runningState === "running") {
|
|
3645
|
+
return true;
|
|
3646
|
+
}
|
|
3647
|
+
if ((sessionIndex?.messageCount ?? 0) !== 0) {
|
|
3648
|
+
return false;
|
|
3649
|
+
}
|
|
3650
|
+
return isWithinGeminiRuntimeChatDiscoveryGraceWindow(state.lastEventAt ?? state.updatedAt ?? sessionIndex?.updatedAt ?? sessionIndex?.createdAt ?? null);
|
|
3651
|
+
}
|
|
3652
|
+
function isWithinGeminiRuntimeChatDiscoveryGraceWindow(timestamp) {
|
|
3653
|
+
if (!timestamp) {
|
|
3654
|
+
return false;
|
|
3655
|
+
}
|
|
3656
|
+
const timestampMs = Date.parse(timestamp);
|
|
3657
|
+
if (!Number.isFinite(timestampMs)) {
|
|
3658
|
+
return false;
|
|
3659
|
+
}
|
|
3660
|
+
return Date.now() - timestampMs <= GEMINI_RUNTIME_CHAT_DISCOVERY_GRACE_MS;
|
|
3661
|
+
}
|
|
3662
|
+
function isGeminiChatNotFoundError(error) {
|
|
3663
|
+
if (error instanceof AppError) {
|
|
3664
|
+
return error.errorCode === "GEMINI_CHAT_NOT_FOUND";
|
|
3665
|
+
}
|
|
3666
|
+
return error instanceof Error && error.message === "GEMINI_CHAT_NOT_FOUND";
|
|
3667
|
+
}
|
|
3668
|
+
function clearSuccessfulProviderReadErrorCode(errorCode) {
|
|
3669
|
+
return errorCode === "PROVIDER_READ_FAILED" ? null : errorCode;
|
|
3670
|
+
}
|
|
3671
|
+
function clearSuccessfulProviderReadErrorDetail(errorCode, errorDetail) {
|
|
3672
|
+
return errorCode === "PROVIDER_READ_FAILED" ? null : errorDetail;
|
|
3673
|
+
}
|
|
3350
3674
|
function shouldShortCircuitMissingSyntheticCodexHistory(provider, rawStoreRef) {
|
|
3351
3675
|
return provider === "codex" && isSyntheticCodexRawStoreRef(rawStoreRef) && !existsSync(rawStoreRef);
|
|
3352
3676
|
}
|
|
@@ -3493,6 +3817,9 @@ function isSyntheticCodexSessionTitle(title) {
|
|
|
3493
3817
|
return (/^rollout-\d{4}-\d{2}-\d{2}t/i.test(title) ||
|
|
3494
3818
|
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(title));
|
|
3495
3819
|
}
|
|
3820
|
+
function isSyntheticGeminiSessionTitle(title) {
|
|
3821
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(title);
|
|
3822
|
+
}
|
|
3496
3823
|
function shouldSyncSessionTitleFromProvider(provider, currentTitle) {
|
|
3497
3824
|
const normalizedTitle = currentTitle?.trim() ?? "";
|
|
3498
3825
|
if (normalizedTitle.length === 0) {
|
|
@@ -3501,6 +3828,9 @@ function shouldSyncSessionTitleFromProvider(provider, currentTitle) {
|
|
|
3501
3828
|
if (provider === "codex" && isSyntheticCodexSessionTitle(normalizedTitle)) {
|
|
3502
3829
|
return true;
|
|
3503
3830
|
}
|
|
3831
|
+
if (provider === "gemini" && isSyntheticGeminiSessionTitle(normalizedTitle)) {
|
|
3832
|
+
return true;
|
|
3833
|
+
}
|
|
3504
3834
|
return false;
|
|
3505
3835
|
}
|
|
3506
3836
|
function shouldRemoveHiddenClaudeDebugSession(session) {
|
|
@@ -3512,6 +3842,7 @@ function shouldRemoveHiddenClaudeDebugSession(session) {
|
|
|
3512
3842
|
/\/agent-[^/]+\.jsonl$/i.test(normalizedRawStoreRef));
|
|
3513
3843
|
}
|
|
3514
3844
|
const STALE_RUNTIME_WITHOUT_INSPECTION_GRACE_MS = 120_000;
|
|
3845
|
+
const GEMINI_ACTIVITY_INFERENCE_HISTORY_LIMIT = 80;
|
|
3515
3846
|
function shouldClearStaleRuntimeWithoutInspection(current, inspection, nowMs) {
|
|
3516
3847
|
if (!current || current.activitySource !== "runtime") {
|
|
3517
3848
|
return false;
|
|
@@ -3545,6 +3876,11 @@ function shouldPreserveRuntimeTerminalState(current, inspection) {
|
|
|
3545
3876
|
return inspection.lastEventAt.localeCompare(current.lastEventAt) <= 0;
|
|
3546
3877
|
}
|
|
3547
3878
|
if (current.runningState === "starting" || current.runningState === "running") {
|
|
3879
|
+
if (inspection.completedAtCandidate
|
|
3880
|
+
|| inspection.errorCode
|
|
3881
|
+
|| inspection.runningState === "interrupted") {
|
|
3882
|
+
return false;
|
|
3883
|
+
}
|
|
3548
3884
|
return inspection.lastEventAt.localeCompare(current.lastEventAt) <= 0;
|
|
3549
3885
|
}
|
|
3550
3886
|
return false;
|
|
@@ -3684,8 +4020,51 @@ function areEquivalentSessionBindings(current, next) {
|
|
|
3684
4020
|
current.provider === next.provider &&
|
|
3685
4021
|
current.providerSessionId === next.providerSessionId &&
|
|
3686
4022
|
current.rawStoreRef === next.rawStoreRef &&
|
|
4023
|
+
current.providerConfigMode === next.providerConfigMode &&
|
|
4024
|
+
current.providerPresetId === next.providerPresetId &&
|
|
4025
|
+
current.runtimeHomeDir === next.runtimeHomeDir &&
|
|
3687
4026
|
current.createdAt === next.createdAt);
|
|
3688
4027
|
}
|
|
4028
|
+
function resolveRequestedProviderSelection(input) {
|
|
4029
|
+
const existingSelection = input.existingBinding
|
|
4030
|
+
? {
|
|
4031
|
+
providerConfigMode: input.existingBinding.providerConfigMode,
|
|
4032
|
+
providerPresetId: input.existingBinding.providerPresetId
|
|
4033
|
+
}
|
|
4034
|
+
: null;
|
|
4035
|
+
const normalizedPresetId = input.providerPresetId?.trim() || null;
|
|
4036
|
+
if (input.providerConfigMode === undefined && input.providerPresetId === undefined) {
|
|
4037
|
+
return existingSelection ?? {
|
|
4038
|
+
providerConfigMode: "global-default",
|
|
4039
|
+
providerPresetId: null
|
|
4040
|
+
};
|
|
4041
|
+
}
|
|
4042
|
+
const providerConfigMode = input.providerConfigMode
|
|
4043
|
+
?? (normalizedPresetId ? "cc-switch-preset" : "global-default");
|
|
4044
|
+
if (providerConfigMode === "global-default") {
|
|
4045
|
+
return {
|
|
4046
|
+
providerConfigMode,
|
|
4047
|
+
providerPresetId: null
|
|
4048
|
+
};
|
|
4049
|
+
}
|
|
4050
|
+
const providerPresetId = normalizedPresetId ?? existingSelection?.providerPresetId ?? null;
|
|
4051
|
+
if (!providerPresetId) {
|
|
4052
|
+
throw new AppError({
|
|
4053
|
+
statusCode: 400,
|
|
4054
|
+
errorCode: "INVALID_INPUT",
|
|
4055
|
+
detail: "使用 cc-switch preset 时必须提供 providerPresetId",
|
|
4056
|
+
field: "providerPresetId"
|
|
4057
|
+
});
|
|
4058
|
+
}
|
|
4059
|
+
return {
|
|
4060
|
+
providerConfigMode,
|
|
4061
|
+
providerPresetId
|
|
4062
|
+
};
|
|
4063
|
+
}
|
|
4064
|
+
function areEquivalentProviderBindingSelection(binding, selection) {
|
|
4065
|
+
return (binding.providerConfigMode === selection.providerConfigMode
|
|
4066
|
+
&& binding.providerPresetId === selection.providerPresetId);
|
|
4067
|
+
}
|
|
3689
4068
|
function areEquivalentSessionIndexRecords(current, next) {
|
|
3690
4069
|
if (!current) {
|
|
3691
4070
|
return false;
|
|
@@ -3772,6 +4151,23 @@ async function runBatchedTransactions(items, batchSize, transaction, logOptions)
|
|
|
3772
4151
|
maxBatchMs
|
|
3773
4152
|
};
|
|
3774
4153
|
}
|
|
4154
|
+
function mergeSessionListItemsBySessionId(items) {
|
|
4155
|
+
const itemBySessionId = new Map();
|
|
4156
|
+
for (const item of items) {
|
|
4157
|
+
itemBySessionId.set(item.sessionId, item);
|
|
4158
|
+
}
|
|
4159
|
+
return [...itemBySessionId.values()];
|
|
4160
|
+
}
|
|
4161
|
+
function sortSessionListItemsByRecentActivity(items) {
|
|
4162
|
+
return [...items].sort((left, right) => {
|
|
4163
|
+
const leftPrimary = left.lastMessageAt ?? left.updatedAt;
|
|
4164
|
+
const rightPrimary = right.lastMessageAt ?? right.updatedAt;
|
|
4165
|
+
if (leftPrimary !== rightPrimary) {
|
|
4166
|
+
return rightPrimary.localeCompare(leftPrimary);
|
|
4167
|
+
}
|
|
4168
|
+
return right.updatedAt.localeCompare(left.updatedAt);
|
|
4169
|
+
});
|
|
4170
|
+
}
|
|
3775
4171
|
function applyImmediateModelOptionFallbacks(capabilities, codexSnapshot, openCodeSnapshot) {
|
|
3776
4172
|
if (capabilities.provider === "codex") {
|
|
3777
4173
|
return {
|