@jingyi0605/codingns 0.6.0 → 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-uFwDdN-F.js → AdaptiveButlerPage-Dw72U3hG.js} +3 -3
- package/dist/public/assets/{App-BZvapsi8.js → App-Dsf3ooXU.js} +3 -3
- package/dist/public/assets/{BootstrapPage-gHSoa4JN.js → BootstrapPage-CE0m1qSR.js} +1 -1
- package/dist/public/assets/ConversationPage-8wOY7SX-.js +4 -0
- package/dist/public/assets/{DesktopDetachPreviewPage-4eMRxiBW.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-Bwv8Ovm_.js → MobileTopHeaderFrame-C5rIKQT6.js} +1 -1
- package/dist/public/assets/MobileWorkspaceSwitcherHeader-CfUnHgv_.js +1 -0
- package/dist/public/assets/{RelayConnectEntryPage-D_4YL-YH.js → RelayConnectEntryPage-CgMvVZwa.js} +1 -1
- package/dist/public/assets/{ServerSettingsModal-CMSm3BZU.js → ServerSettingsModal-CFul__z1.js} +1 -1
- 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-DaooFaJ4.js → TerminalPage-DWHv6mlu.js} +1 -1
- package/dist/public/assets/TerminalRuntimeFallbackModal-B29YxbQe.js +1 -0
- package/dist/public/assets/{ToolFilesPage-CGxBvYG0.js → ToolFilesPage-Dx9cv9hu.js} +1 -1
- 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-0tPIIhca.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-BZpL17fc.js → client-runtime-manager-DROQJ9v3.js} +1 -1
- package/dist/public/assets/{file-tree-icon-Db5LXC8h.js → file-tree-icon-Bp3Ntt7u.js} +1 -1
- 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-1mxe_Oh8.js → login-direct-candidate-resolver-DotM530R.js} +1 -1
- package/dist/public/assets/model-switch-api-Bh9nYslz.js +1 -0
- package/dist/public/assets/{preferences-service-DWnzl5a0.js → preferences-service-BG6GKG29.js} +1 -1
- package/dist/public/assets/{relay-entry-C5_Iay0I.js → relay-entry-pmr-c42O.js} +1 -1
- package/dist/public/assets/session-runtime-machine-YN84QBlr.js +21 -0
- package/dist/public/assets/{terminal-runtime-meta-cdtWVfCm.js → terminal-runtime-meta-8_uRZf7h.js} +1 -1
- package/dist/public/assets/useRegisteredDebugTemplates-DWX7LXQu.js +1 -0
- package/dist/public/index.html +2 -2
- package/dist/server/config/env.d.ts +2 -0
- package/dist/server/config/env.js +7 -0
- package/dist/server/config/env.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 +4 -0
- package/dist/server/modules/parallel-sessions/parallel-session-controller.js +7 -0
- package/dist/server/modules/parallel-sessions/parallel-session-controller.js.map +1 -1
- package/dist/server/modules/parallel-sessions/parallel-session-group-service.d.ts +6 -1
- package/dist/server/modules/parallel-sessions/parallel-session-group-service.js +36 -2
- package/dist/server/modules/parallel-sessions/parallel-session-group-service.js.map +1 -1
- 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/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 +1 -0
- package/dist/server/modules/sessions/codex-app-server-helper-client.js +10 -0
- package/dist/server/modules/sessions/codex-app-server-helper-client.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 +12 -2
- package/dist/server/modules/sessions/session-history-service.js +284 -16
- package/dist/server/modules/sessions/session-history-service.js.map +1 -1
- package/dist/server/modules/sessions/session-live-runtime-service.d.ts +15 -2
- package/dist/server/modules/sessions/session-live-runtime-service.js +265 -50
- 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/server/create-server.js +11 -8
- package/dist/server/server/create-server.js.map +1 -1
- 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/sqlite/client.js +19 -0
- package/dist/server/storage/sqlite/client.js.map +1 -1
- package/dist/server/storage/sqlite/schema.sql +5 -0
- package/dist/server/types/domain.d.ts +6 -0
- 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/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/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 +41 -21
- 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 +167 -10
- 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/ConversationPage-z3sXtKZ7.js +0 -4
- package/dist/public/assets/DesktopWindowPage-CZcoGApB.js +0 -2
- package/dist/public/assets/FileContextPanel-C3qex8bb.js +0 -1
- package/dist/public/assets/GitSidebar-BK6H16XU.js +0 -6
- package/dist/public/assets/MobileCreateSessionSheet-BYfbvK8o.js +0 -1
- package/dist/public/assets/MobileSheet-Ckug8hTb.js +0 -1
- package/dist/public/assets/MobileWorkspaceSwitcherHeader-RqWrBdn2.js +0 -1
- package/dist/public/assets/SessionIndexPage-DuK10DL5.js +0 -1
- package/dist/public/assets/SettingsPage-fyD-xaHL.js +0 -1
- package/dist/public/assets/TerminalManagerPanel-CCLr1Ypk.js +0 -1
- package/dist/public/assets/TerminalRuntimeFallbackModal-aUzjEBwP.js +0 -1
- package/dist/public/assets/ToolGitPage-C264yjS9.js +0 -1
- package/dist/public/assets/ToolProcessesPage-BOP4A1cb.js +0 -1
- package/dist/public/assets/ToolsHomePage-CQxGiKQA.js +0 -1
- package/dist/public/assets/WorkbenchLandingPage-CvAY68ca.js +0 -1
- package/dist/public/assets/WorkbenchLayout-DGm8Tc5M.js +0 -3
- package/dist/public/assets/WorkbenchShellRoute-BF0nHWOk.css +0 -1
- package/dist/public/assets/WorkbenchShellRoute-DBBOsJo9.js +0 -1
- package/dist/public/assets/WorkspaceDebugDetailPage-CDerFYd2.js +0 -1
- package/dist/public/assets/WorkspaceDetailPage-BlJc1CHE.js +0 -1
- package/dist/public/assets/WorkspaceHomePage-BUsKJ3lv.js +0 -1
- package/dist/public/assets/default-session-permission-mode-DT4SGiwp.js +0 -1
- package/dist/public/assets/index-BZLcEHW3.js +0 -42
- package/dist/public/assets/index-BbspQPC2.css +0 -1
- package/dist/public/assets/session-runtime-machine-DdLeDqQr.js +0 -17
- package/dist/public/assets/useRegisteredDebugTemplates-oFAQNIqh.js +0 -1
|
@@ -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";
|
|
@@ -25,15 +25,18 @@ const RECONSTRUCTED_FORK_TARGET_PROVIDERS = new Set(["codex", "claude-code", "op
|
|
|
25
25
|
const FORK_RECONSTRUCTION_PAGE_SIZE = 200;
|
|
26
26
|
const MAX_FORK_DEPTH = 4;
|
|
27
27
|
const SYNTHETIC_CODEX_SESSION_CLEANUP_GRACE_MS = 120_000;
|
|
28
|
+
const GEMINI_RUNTIME_CHAT_DISCOVERY_GRACE_MS = 30_000;
|
|
28
29
|
const SESSION_START_DEFERRED_PROVIDERS = new Set([
|
|
29
30
|
"codex",
|
|
30
31
|
"claude-code",
|
|
32
|
+
"legna-code",
|
|
31
33
|
"opencode",
|
|
32
34
|
"gemini",
|
|
33
35
|
"kimi"
|
|
34
36
|
]);
|
|
35
37
|
const MUTABLE_HISTORY_TAIL_PROVIDERS = new Set([
|
|
36
38
|
"claude-code",
|
|
39
|
+
"legna-code",
|
|
37
40
|
"codex",
|
|
38
41
|
"gemini",
|
|
39
42
|
"kimi",
|
|
@@ -75,6 +78,7 @@ export class SessionHistoryService {
|
|
|
75
78
|
sessionIsolatedWorkspaceRepository;
|
|
76
79
|
providerDiscoveryHelperClient = getSharedProviderDiscoveryHelperClient();
|
|
77
80
|
providerSessionDiscoveryConfig;
|
|
81
|
+
sessionProviderConfigService;
|
|
78
82
|
taskManager;
|
|
79
83
|
workspaceDiscoveryStatuses = new Map();
|
|
80
84
|
workspaceStateRefreshStatuses = new Map();
|
|
@@ -84,7 +88,7 @@ export class SessionHistoryService {
|
|
|
84
88
|
sessionDeletedObservers = new Set();
|
|
85
89
|
workspaceSessionRelations = new Map();
|
|
86
90
|
workspaceStateRefreshTaskSequence = 0;
|
|
87
|
-
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) {
|
|
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) {
|
|
88
92
|
this.db = db;
|
|
89
93
|
this.workspaceRepository = workspaceRepository;
|
|
90
94
|
this.sessionBindingRepository = sessionBindingRepository;
|
|
@@ -102,9 +106,11 @@ export class SessionHistoryService {
|
|
|
102
106
|
this.parallelSessionGroupRepository = parallelSessionGroupRepository;
|
|
103
107
|
this.parallelSessionMemberRepository = parallelSessionMemberRepository;
|
|
104
108
|
this.sessionIsolatedWorkspaceRepository = sessionIsolatedWorkspaceRepository;
|
|
109
|
+
this.sessionProviderConfigService = sessionProviderConfigService;
|
|
105
110
|
this.claudeCodeHomeDir = config.claudeCodeHomeDir;
|
|
106
111
|
this.providerCliCommandPaths = {
|
|
107
112
|
"claude-code": process.platform === "win32" ? "claude.cmd" : "claude",
|
|
113
|
+
"legna-code": config.legnaCodeCliPath,
|
|
108
114
|
codex: config.codexCliPath,
|
|
109
115
|
gemini: config.geminiCliPath,
|
|
110
116
|
kimi: config.kimiCliPath
|
|
@@ -113,8 +119,10 @@ export class SessionHistoryService {
|
|
|
113
119
|
this.providerCliAvailability = buildProviderCliAvailabilitySnapshot(this.providerCliCommandPaths);
|
|
114
120
|
this.providerSessionDiscoveryConfig = {
|
|
115
121
|
claudeCodeHomeDir: config.claudeCodeHomeDir,
|
|
122
|
+
legnaCodeHomeDir: config.legnaCodeHomeDir,
|
|
116
123
|
codexCliPath: config.codexCliPath,
|
|
117
124
|
codexHomeDir: config.codexHomeDir,
|
|
125
|
+
legnaCodeCliPath: config.legnaCodeCliPath,
|
|
118
126
|
geminiCliPath: config.geminiCliPath,
|
|
119
127
|
geminiHomeDir: config.geminiHomeDir,
|
|
120
128
|
kimiDefaultModel: config.kimiDefaultModel,
|
|
@@ -125,6 +133,10 @@ export class SessionHistoryService {
|
|
|
125
133
|
};
|
|
126
134
|
this.providerRegistry = new ProviderRegistry([
|
|
127
135
|
new ClaudeCodeAdapter({ homeDir: config.claudeCodeHomeDir }),
|
|
136
|
+
new LegnaCodeAdapter({
|
|
137
|
+
homeDir: config.legnaCodeHomeDir,
|
|
138
|
+
legacyClaudeHomeDir: config.claudeCodeHomeDir
|
|
139
|
+
}),
|
|
128
140
|
new CodexAdapter({
|
|
129
141
|
homeDir: config.codexHomeDir,
|
|
130
142
|
forkTransportFactory: adapterOverrides.codexForkTransportFactory
|
|
@@ -323,8 +335,8 @@ export class SessionHistoryService {
|
|
|
323
335
|
? current?.syncCursor ?? page.cursor
|
|
324
336
|
: page.cursor,
|
|
325
337
|
lastSyncAt: nowIso(),
|
|
326
|
-
lastErrorCode: current?.lastErrorCode ?? null,
|
|
327
|
-
lastErrorDetail: current?.lastErrorDetail ?? null,
|
|
338
|
+
lastErrorCode: clearSuccessfulProviderReadErrorCode(current?.lastErrorCode ?? null),
|
|
339
|
+
lastErrorDetail: clearSuccessfulProviderReadErrorDetail(current?.lastErrorCode ?? null, current?.lastErrorDetail ?? null),
|
|
328
340
|
resumedAt: current?.resumedAt ?? null
|
|
329
341
|
});
|
|
330
342
|
snapshotIdleMs = Date.now() - snapshotIdleStartedAt;
|
|
@@ -455,6 +467,15 @@ export class SessionHistoryService {
|
|
|
455
467
|
try {
|
|
456
468
|
const workspacePath = workspaceId ? this.getWorkspaceOrThrow(workspaceId).path : null;
|
|
457
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
|
+
}
|
|
458
479
|
this.scheduleProviderCapabilityRefresh(baseCapabilities, workspacePath);
|
|
459
480
|
return this.resolveProviderCapabilitiesImmediate(baseCapabilities, workspacePath);
|
|
460
481
|
}
|
|
@@ -470,6 +491,17 @@ export class SessionHistoryService {
|
|
|
470
491
|
.getSessionCapabilities(binding.provider, binding.providerSessionId)
|
|
471
492
|
.then((capabilities) => {
|
|
472
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
|
+
}
|
|
473
505
|
this.scheduleProviderCapabilityRefresh(normalizedCapabilities, workspacePath);
|
|
474
506
|
return this.resolveProviderCapabilitiesImmediate(normalizedCapabilities, workspacePath);
|
|
475
507
|
})
|
|
@@ -610,11 +642,17 @@ export class SessionHistoryService {
|
|
|
610
642
|
async startSessionDirect(input) {
|
|
611
643
|
const workspace = this.getWorkspaceOrThrow(input.workspaceId);
|
|
612
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
|
+
});
|
|
613
652
|
try {
|
|
614
|
-
const result = await this.
|
|
653
|
+
const result = await this.startProviderSessionWithBinding(input.provider, workspace.path, providerBinding.runtimeHomeDir, {
|
|
615
654
|
initialPrompt: input.initialPrompt
|
|
616
655
|
});
|
|
617
|
-
const sessionId = createId();
|
|
618
656
|
const timestamp = nowIso();
|
|
619
657
|
const persist = this.db.transaction(() => {
|
|
620
658
|
this.sessionBindingRepository.upsert({
|
|
@@ -623,6 +661,9 @@ export class SessionHistoryService {
|
|
|
623
661
|
provider: result.session.provider,
|
|
624
662
|
providerSessionId: result.session.providerSessionId,
|
|
625
663
|
rawStoreRef: result.session.rawStoreRef,
|
|
664
|
+
providerConfigMode: providerBinding.providerConfigMode,
|
|
665
|
+
providerPresetId: providerBinding.providerPresetId,
|
|
666
|
+
runtimeHomeDir: providerBinding.runtimeHomeDir,
|
|
626
667
|
createdAt: timestamp,
|
|
627
668
|
updatedAt: timestamp
|
|
628
669
|
});
|
|
@@ -690,10 +731,18 @@ export class SessionHistoryService {
|
|
|
690
731
|
});
|
|
691
732
|
}
|
|
692
733
|
this.assertForkDepthWithinLimit(input.sessionId);
|
|
693
|
-
|
|
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)) {
|
|
694
741
|
return this.forkSessionAcrossProviders({
|
|
695
742
|
...input,
|
|
696
|
-
targetProvider
|
|
743
|
+
targetProvider,
|
|
744
|
+
providerConfigMode: requestedTargetSelection.providerConfigMode,
|
|
745
|
+
providerPresetId: requestedTargetSelection.providerPresetId
|
|
697
746
|
}, binding, sourceMessageId);
|
|
698
747
|
}
|
|
699
748
|
try {
|
|
@@ -713,6 +762,9 @@ export class SessionHistoryService {
|
|
|
713
762
|
provider: result.session.provider,
|
|
714
763
|
providerSessionId: result.session.providerSessionId,
|
|
715
764
|
rawStoreRef: result.session.rawStoreRef,
|
|
765
|
+
providerConfigMode: binding.providerConfigMode,
|
|
766
|
+
providerPresetId: binding.providerPresetId,
|
|
767
|
+
runtimeHomeDir: binding.runtimeHomeDir,
|
|
716
768
|
createdAt: timestamp,
|
|
717
769
|
updatedAt: timestamp
|
|
718
770
|
});
|
|
@@ -807,6 +859,8 @@ export class SessionHistoryService {
|
|
|
807
859
|
userId: input.userId,
|
|
808
860
|
provider: input.targetProvider,
|
|
809
861
|
initialPrompt: inheritedPrompt,
|
|
862
|
+
providerConfigMode: input.providerConfigMode ?? null,
|
|
863
|
+
providerPresetId: input.providerPresetId ?? null,
|
|
810
864
|
parentSessionId: input.sessionId,
|
|
811
865
|
sessionKind: input.sessionKind ?? "default",
|
|
812
866
|
annotationSourceMessageId: input.annotationSourceMessageId ?? null,
|
|
@@ -854,6 +908,40 @@ export class SessionHistoryService {
|
|
|
854
908
|
this.workspaceSessionRelations.set(input.targetWorkspaceId?.trim() || sourceBinding.workspaceId, relationMap);
|
|
855
909
|
return this.getSessionListItemOrThrow(startedSession.sessionId, input.userId);
|
|
856
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
|
+
}
|
|
857
945
|
async readForkSourceMessages(sessionId, binding, sourceType, sourceMessageId, sourceMessageSnapshot = null) {
|
|
858
946
|
const messages = [];
|
|
859
947
|
let cursor = null;
|
|
@@ -1024,13 +1112,14 @@ export class SessionHistoryService {
|
|
|
1024
1112
|
return null;
|
|
1025
1113
|
}
|
|
1026
1114
|
await this.syncSessionTitleFromProvider(sessionId, binding);
|
|
1115
|
+
const snapshot = this.sessionStatusSnapshotRepository.findBySessionId(sessionId);
|
|
1027
1116
|
this.upsertSnapshot(sessionId, {
|
|
1028
1117
|
syncStatus: "idle",
|
|
1029
1118
|
syncCursor: page.cursor,
|
|
1030
1119
|
lastSyncAt: nowIso(),
|
|
1031
|
-
lastErrorCode:
|
|
1032
|
-
lastErrorDetail:
|
|
1033
|
-
resumedAt:
|
|
1120
|
+
lastErrorCode: clearSuccessfulProviderReadErrorCode(snapshot?.lastErrorCode ?? null),
|
|
1121
|
+
lastErrorDetail: clearSuccessfulProviderReadErrorDetail(snapshot?.lastErrorCode ?? null, snapshot?.lastErrorDetail ?? null),
|
|
1122
|
+
resumedAt: snapshot?.resumedAt ?? null
|
|
1034
1123
|
});
|
|
1035
1124
|
return {
|
|
1036
1125
|
type: "session.delta",
|
|
@@ -1244,6 +1333,15 @@ export class SessionHistoryService {
|
|
|
1244
1333
|
provider: resolvedSnapshot.provider,
|
|
1245
1334
|
providerSessionId: resolvedSnapshot.providerSessionId,
|
|
1246
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,
|
|
1247
1345
|
createdAt: pickEarlierIso(currentBinding?.createdAt ?? null, duplicateBinding?.createdAt ?? null)
|
|
1248
1346
|
?? timestamp,
|
|
1249
1347
|
updatedAt: timestamp
|
|
@@ -1335,6 +1433,9 @@ export class SessionHistoryService {
|
|
|
1335
1433
|
provider: session.provider,
|
|
1336
1434
|
providerSessionId: session.providerSessionId,
|
|
1337
1435
|
rawStoreRef: session.rawStoreRef,
|
|
1436
|
+
providerConfigMode: existing?.providerConfigMode ?? "global-default",
|
|
1437
|
+
providerPresetId: existing?.providerPresetId ?? null,
|
|
1438
|
+
runtimeHomeDir: existing?.runtimeHomeDir ?? null,
|
|
1338
1439
|
createdAt,
|
|
1339
1440
|
updatedAt: timestamp
|
|
1340
1441
|
};
|
|
@@ -1614,9 +1715,24 @@ export class SessionHistoryService {
|
|
|
1614
1715
|
total: 0
|
|
1615
1716
|
};
|
|
1616
1717
|
}
|
|
1718
|
+
if (this.shouldTreatMissingGeminiRuntimeHistoryAsEmpty(sessionId, provider, error)) {
|
|
1719
|
+
return {
|
|
1720
|
+
messages: [],
|
|
1721
|
+
cursor,
|
|
1722
|
+
nextCursor: null,
|
|
1723
|
+
total: 0
|
|
1724
|
+
};
|
|
1725
|
+
}
|
|
1617
1726
|
throw mapSessionProviderError(error);
|
|
1618
1727
|
});
|
|
1619
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
|
+
}
|
|
1620
1736
|
enrichMessagesWithOrigin(sessionId, messages) {
|
|
1621
1737
|
return this.resolveMessageOrigins(sessionId, messages);
|
|
1622
1738
|
}
|
|
@@ -1909,8 +2025,8 @@ export class SessionHistoryService {
|
|
|
1909
2025
|
syncStatus: "idle",
|
|
1910
2026
|
syncCursor: page.cursor,
|
|
1911
2027
|
lastSyncAt: nowIso(),
|
|
1912
|
-
lastErrorCode: snapshot?.lastErrorCode ?? null,
|
|
1913
|
-
lastErrorDetail: snapshot?.lastErrorDetail ?? null,
|
|
2028
|
+
lastErrorCode: clearSuccessfulProviderReadErrorCode(snapshot?.lastErrorCode ?? null),
|
|
2029
|
+
lastErrorDetail: clearSuccessfulProviderReadErrorDetail(snapshot?.lastErrorCode ?? null, snapshot?.lastErrorDetail ?? null),
|
|
1914
2030
|
resumedAt: snapshot?.resumedAt ?? null
|
|
1915
2031
|
});
|
|
1916
2032
|
await onEnvelope({
|
|
@@ -1936,7 +2052,12 @@ export class SessionHistoryService {
|
|
|
1936
2052
|
provider: binding.provider,
|
|
1937
2053
|
providerSessionId: binding.providerSessionId,
|
|
1938
2054
|
rawStoreRef: binding.rawStoreRef
|
|
1939
|
-
}, signal)
|
|
2055
|
+
}, signal).catch((error) => {
|
|
2056
|
+
if (this.shouldTreatMissingGeminiRuntimeHistoryAsEmpty(sessionId, binding.provider, error)) {
|
|
2057
|
+
return "";
|
|
2058
|
+
}
|
|
2059
|
+
throw error;
|
|
2060
|
+
})).trim();
|
|
1940
2061
|
const resolvedTitle = resolvePersistedSessionTitle(binding.provider, nextTitle, currentIndex.title);
|
|
1941
2062
|
if (resolvedTitle.length === 0 || resolvedTitle === currentIndex.title) {
|
|
1942
2063
|
return;
|
|
@@ -2371,6 +2492,9 @@ export class SessionHistoryService {
|
|
|
2371
2492
|
provider: input.provider,
|
|
2372
2493
|
providerSessionId: buildPendingBindingValue(input.provider, input.targetSessionId),
|
|
2373
2494
|
rawStoreRef: buildPendingBindingValue(input.provider, input.targetSessionId),
|
|
2495
|
+
providerConfigMode: sourceBinding.providerConfigMode,
|
|
2496
|
+
providerPresetId: sourceBinding.providerPresetId,
|
|
2497
|
+
runtimeHomeDir: sourceBinding.runtimeHomeDir,
|
|
2374
2498
|
createdAt: sourceBinding.createdAt,
|
|
2375
2499
|
updatedAt: input.timestamp
|
|
2376
2500
|
});
|
|
@@ -2452,6 +2576,9 @@ export class SessionHistoryService {
|
|
|
2452
2576
|
provider: sourceBinding.provider,
|
|
2453
2577
|
providerSessionId: buildAliasBindingValue(input.provider, input.targetSessionId, input.sourceSessionId),
|
|
2454
2578
|
rawStoreRef: buildAliasBindingValue(input.provider, input.targetSessionId, input.sourceSessionId),
|
|
2579
|
+
providerConfigMode: sourceBinding.providerConfigMode,
|
|
2580
|
+
providerPresetId: sourceBinding.providerPresetId,
|
|
2581
|
+
runtimeHomeDir: sourceBinding.runtimeHomeDir,
|
|
2455
2582
|
createdAt: sourceBinding.createdAt,
|
|
2456
2583
|
updatedAt: input.timestamp
|
|
2457
2584
|
});
|
|
@@ -2690,7 +2817,9 @@ export class SessionHistoryService {
|
|
|
2690
2817
|
const liveObservation = this.resolveLiveActivityObservation(sessionId);
|
|
2691
2818
|
const inspection = liveObservation
|
|
2692
2819
|
? null
|
|
2693
|
-
:
|
|
2820
|
+
: binding.provider === "gemini"
|
|
2821
|
+
? await this.inspectGeminiHistoryActivity(sessionId, binding)
|
|
2822
|
+
: inspectSessionActivity(binding.provider, binding.rawStoreRef);
|
|
2694
2823
|
if (inspection) {
|
|
2695
2824
|
const nowMs = Date.parse(timestamp);
|
|
2696
2825
|
if (shouldClearStaleRuntimeWithoutInspection(current, inspection, nowMs)) {
|
|
@@ -2753,6 +2882,15 @@ export class SessionHistoryService {
|
|
|
2753
2882
|
});
|
|
2754
2883
|
return nextRecord;
|
|
2755
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
|
+
}
|
|
2756
2894
|
async repairCodexDirtyBindingBeforeHistoryRead(sessionId, userId, binding) {
|
|
2757
2895
|
if (!shouldRepairCodexDirtyBinding(binding)) {
|
|
2758
2896
|
this.codexDirtyBindingRepairStates.delete(sessionId);
|
|
@@ -2829,7 +2967,11 @@ export class SessionHistoryService {
|
|
|
2829
2967
|
}
|
|
2830
2968
|
}
|
|
2831
2969
|
function isProviderCliBacked(provider) {
|
|
2832
|
-
return provider === "claude-code"
|
|
2970
|
+
return provider === "claude-code"
|
|
2971
|
+
|| provider === "legna-code"
|
|
2972
|
+
|| provider === "codex"
|
|
2973
|
+
|| provider === "gemini"
|
|
2974
|
+
|| provider === "kimi";
|
|
2833
2975
|
}
|
|
2834
2976
|
function buildProviderCliAvailabilitySnapshot(commandPaths) {
|
|
2835
2977
|
return Object.freeze(Object.fromEntries(Object.entries(commandPaths).map(([provider, commandPath]) => [
|
|
@@ -2841,6 +2983,8 @@ function buildProviderCliUnavailableMessage(provider) {
|
|
|
2841
2983
|
switch (provider) {
|
|
2842
2984
|
case "claude-code":
|
|
2843
2985
|
return "未检测到 Claude CLI";
|
|
2986
|
+
case "legna-code":
|
|
2987
|
+
return "未检测到 Legna CLI";
|
|
2844
2988
|
case "codex":
|
|
2845
2989
|
return "未检测到 Codex CLI";
|
|
2846
2990
|
case "gemini":
|
|
@@ -2900,6 +3044,46 @@ function hasInspectionEvidence(inspection) {
|
|
|
2900
3044
|
|| !!inspection.lastEventAt
|
|
2901
3045
|
|| !!inspection.completedAtCandidate;
|
|
2902
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
|
+
}
|
|
2903
3087
|
function applySessionActivityResolution(item, resolution) {
|
|
2904
3088
|
const rawResolvedRunningState = resolution.runningState === "unknown" && item.runningState === null
|
|
2905
3089
|
? null
|
|
@@ -3453,6 +3637,40 @@ function shouldTreatMissingSyntheticHistoryAsEmpty(provider, rawStoreRef, error)
|
|
|
3453
3637
|
const detail = error instanceof Error ? error.message : String(error);
|
|
3454
3638
|
return detail.includes("ENOENT");
|
|
3455
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
|
+
}
|
|
3456
3674
|
function shouldShortCircuitMissingSyntheticCodexHistory(provider, rawStoreRef) {
|
|
3457
3675
|
return provider === "codex" && isSyntheticCodexRawStoreRef(rawStoreRef) && !existsSync(rawStoreRef);
|
|
3458
3676
|
}
|
|
@@ -3599,6 +3817,9 @@ function isSyntheticCodexSessionTitle(title) {
|
|
|
3599
3817
|
return (/^rollout-\d{4}-\d{2}-\d{2}t/i.test(title) ||
|
|
3600
3818
|
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(title));
|
|
3601
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
|
+
}
|
|
3602
3823
|
function shouldSyncSessionTitleFromProvider(provider, currentTitle) {
|
|
3603
3824
|
const normalizedTitle = currentTitle?.trim() ?? "";
|
|
3604
3825
|
if (normalizedTitle.length === 0) {
|
|
@@ -3607,6 +3828,9 @@ function shouldSyncSessionTitleFromProvider(provider, currentTitle) {
|
|
|
3607
3828
|
if (provider === "codex" && isSyntheticCodexSessionTitle(normalizedTitle)) {
|
|
3608
3829
|
return true;
|
|
3609
3830
|
}
|
|
3831
|
+
if (provider === "gemini" && isSyntheticGeminiSessionTitle(normalizedTitle)) {
|
|
3832
|
+
return true;
|
|
3833
|
+
}
|
|
3610
3834
|
return false;
|
|
3611
3835
|
}
|
|
3612
3836
|
function shouldRemoveHiddenClaudeDebugSession(session) {
|
|
@@ -3618,6 +3842,7 @@ function shouldRemoveHiddenClaudeDebugSession(session) {
|
|
|
3618
3842
|
/\/agent-[^/]+\.jsonl$/i.test(normalizedRawStoreRef));
|
|
3619
3843
|
}
|
|
3620
3844
|
const STALE_RUNTIME_WITHOUT_INSPECTION_GRACE_MS = 120_000;
|
|
3845
|
+
const GEMINI_ACTIVITY_INFERENCE_HISTORY_LIMIT = 80;
|
|
3621
3846
|
function shouldClearStaleRuntimeWithoutInspection(current, inspection, nowMs) {
|
|
3622
3847
|
if (!current || current.activitySource !== "runtime") {
|
|
3623
3848
|
return false;
|
|
@@ -3795,8 +4020,51 @@ function areEquivalentSessionBindings(current, next) {
|
|
|
3795
4020
|
current.provider === next.provider &&
|
|
3796
4021
|
current.providerSessionId === next.providerSessionId &&
|
|
3797
4022
|
current.rawStoreRef === next.rawStoreRef &&
|
|
4023
|
+
current.providerConfigMode === next.providerConfigMode &&
|
|
4024
|
+
current.providerPresetId === next.providerPresetId &&
|
|
4025
|
+
current.runtimeHomeDir === next.runtimeHomeDir &&
|
|
3798
4026
|
current.createdAt === next.createdAt);
|
|
3799
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
|
+
}
|
|
3800
4068
|
function areEquivalentSessionIndexRecords(current, next) {
|
|
3801
4069
|
if (!current) {
|
|
3802
4070
|
return false;
|