@jingyi0605/codingns 0.2.0 → 0.2.5
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/README.md +44 -0
- package/bin/codingns.mjs +640 -53
- package/dist/public/assets/{TerminalPage-BlbQuWi1.js → TerminalPage-BkjqU9NG.js} +19 -19
- package/dist/public/assets/index-C6U8-9jg.css +1 -0
- package/dist/public/assets/index-CKSumuV2.js +109 -0
- package/dist/public/index.html +2 -2
- package/dist/server/config/env.d.ts +1 -0
- package/dist/server/config/env.js +3 -0
- package/dist/server/config/env.js.map +1 -1
- package/dist/server/modules/assistant-capability/assistant-capability-controller.d.ts +89 -0
- package/dist/server/modules/assistant-capability/assistant-capability-controller.js +138 -0
- package/dist/server/modules/assistant-capability/assistant-capability-controller.js.map +1 -0
- package/dist/server/modules/assistant-capability/assistant-capability-service.d.ts +115 -0
- package/dist/server/modules/assistant-capability/assistant-capability-service.js +241 -0
- package/dist/server/modules/assistant-capability/assistant-capability-service.js.map +1 -0
- package/dist/server/modules/butler/butler-control-session-service.js +69 -30
- package/dist/server/modules/butler/butler-control-session-service.js.map +1 -1
- package/dist/server/modules/butler/butler-follow-up-scheduler.d.ts +9 -0
- package/dist/server/modules/butler/butler-follow-up-scheduler.js +47 -11
- package/dist/server/modules/butler/butler-follow-up-scheduler.js.map +1 -1
- package/dist/server/modules/butler/butler-follow-up-service.d.ts +7 -1
- package/dist/server/modules/butler/butler-follow-up-service.js +10 -0
- package/dist/server/modules/butler/butler-follow-up-service.js.map +1 -1
- package/dist/server/modules/butler/butler-session-service.d.ts +2 -1
- package/dist/server/modules/butler/butler-session-service.js +10 -1
- package/dist/server/modules/butler/butler-session-service.js.map +1 -1
- package/dist/server/modules/butler/butler-session-summary-service.d.ts +8 -1
- package/dist/server/modules/butler/butler-session-summary-service.js +34 -7
- package/dist/server/modules/butler/butler-session-summary-service.js.map +1 -1
- package/dist/server/modules/butler/context-aggregator.js +44 -13
- package/dist/server/modules/butler/context-aggregator.js.map +1 -1
- package/dist/server/modules/butler/patrol-scheduler.d.ts +9 -0
- package/dist/server/modules/butler/patrol-scheduler.js +63 -9
- package/dist/server/modules/butler/patrol-scheduler.js.map +1 -1
- package/dist/server/modules/butler/session-summary-scheduler.d.ts +9 -0
- package/dist/server/modules/butler/session-summary-scheduler.js +47 -11
- package/dist/server/modules/butler/session-summary-scheduler.js.map +1 -1
- package/dist/server/modules/debug-target/debug-runtime-reconciliation-scheduler.d.ts +38 -0
- package/dist/server/modules/debug-target/debug-runtime-reconciliation-scheduler.js +99 -0
- package/dist/server/modules/debug-target/debug-runtime-reconciliation-scheduler.js.map +1 -0
- package/dist/server/modules/debug-target/debug-target-controller.d.ts +70 -0
- package/dist/server/modules/debug-target/debug-target-controller.js +113 -0
- package/dist/server/modules/debug-target/debug-target-controller.js.map +1 -0
- package/dist/server/modules/debug-target/debug-target-service.d.ts +102 -0
- package/dist/server/modules/debug-target/debug-target-service.js +1484 -0
- package/dist/server/modules/debug-target/debug-target-service.js.map +1 -0
- package/dist/server/modules/debug-target/framework-compatibility-matrix.d.ts +4 -0
- package/dist/server/modules/debug-target/framework-compatibility-matrix.js +45 -0
- package/dist/server/modules/debug-target/framework-compatibility-matrix.js.map +1 -0
- package/dist/server/modules/debug-target/launch-adapter-registry.d.ts +25 -0
- package/dist/server/modules/debug-target/launch-adapter-registry.js +445 -0
- package/dist/server/modules/debug-target/launch-adapter-registry.js.map +1 -0
- package/dist/server/modules/file/file-content-service.d.ts +2 -1
- package/dist/server/modules/file/file-content-service.js +53 -0
- package/dist/server/modules/file/file-content-service.js.map +1 -1
- package/dist/server/modules/git/commit-orchestrator.d.ts +4 -1
- package/dist/server/modules/git/commit-orchestrator.js +18 -1
- package/dist/server/modules/git/commit-orchestrator.js.map +1 -1
- package/dist/server/modules/git/git-auth.d.ts +25 -0
- package/dist/server/modules/git/git-auth.js +88 -0
- package/dist/server/modules/git/git-auth.js.map +1 -0
- package/dist/server/modules/git/git-controller.d.ts +6 -0
- package/dist/server/modules/git/git-controller.js +5 -1
- package/dist/server/modules/git/git-controller.js.map +1 -1
- package/dist/server/modules/git/git-read-service.d.ts +2 -1
- package/dist/server/modules/git/git-read-service.js +19 -2
- package/dist/server/modules/git/git-read-service.js.map +1 -1
- package/dist/server/modules/git/git-remote-credential-service.d.ts +9 -0
- package/dist/server/modules/git/git-remote-credential-service.js +76 -0
- package/dist/server/modules/git/git-remote-credential-service.js.map +1 -0
- package/dist/server/modules/git/git-write-service.d.ts +5 -2
- package/dist/server/modules/git/git-write-service.js +33 -17
- package/dist/server/modules/git/git-write-service.js.map +1 -1
- package/dist/server/modules/git/types.d.ts +3 -0
- package/dist/server/modules/git/workspace-repo-guard.js +3 -2
- package/dist/server/modules/git/workspace-repo-guard.js.map +1 -1
- package/dist/server/modules/provider/codex-model-options.d.ts +3 -1
- package/dist/server/modules/provider/codex-model-options.js +4 -1
- package/dist/server/modules/provider/codex-model-options.js.map +1 -1
- package/dist/server/modules/provider/opencode-model-options.d.ts +3 -1
- package/dist/server/modules/provider/opencode-model-options.js +5 -1
- package/dist/server/modules/provider/opencode-model-options.js.map +1 -1
- package/dist/server/modules/provider/provider-discovery-helper-client.d.ts +24 -0
- package/dist/server/modules/provider/provider-discovery-helper-client.js +14 -0
- package/dist/server/modules/provider/provider-discovery-helper-client.js.map +1 -1
- package/dist/server/modules/provider/provider-discovery-helper-process.js +54 -0
- package/dist/server/modules/provider/provider-discovery-helper-process.js.map +1 -1
- package/dist/server/modules/sessions/session-controller.d.ts +5 -0
- package/dist/server/modules/sessions/session-controller.js +16 -0
- package/dist/server/modules/sessions/session-controller.js.map +1 -1
- package/dist/server/modules/sessions/session-history-service.d.ts +19 -5
- package/dist/server/modules/sessions/session-history-service.js +322 -39
- package/dist/server/modules/sessions/session-history-service.js.map +1 -1
- package/dist/server/modules/tasks/event-loop-monitor.d.ts +21 -0
- package/dist/server/modules/tasks/event-loop-monitor.js +64 -0
- package/dist/server/modules/tasks/event-loop-monitor.js.map +1 -0
- package/dist/server/modules/tasks/observability-controller.d.ts +30 -0
- package/dist/server/modules/tasks/observability-controller.js +44 -0
- package/dist/server/modules/tasks/observability-controller.js.map +1 -0
- package/dist/server/modules/tasks/observability-service.d.ts +32 -0
- package/dist/server/modules/tasks/observability-service.js +104 -0
- package/dist/server/modules/tasks/observability-service.js.map +1 -0
- package/dist/server/modules/tasks/scheduler-metrics.d.ts +41 -0
- package/dist/server/modules/tasks/scheduler-metrics.js +92 -0
- package/dist/server/modules/tasks/scheduler-metrics.js.map +1 -0
- package/dist/server/modules/tasks/task-activity-log.d.ts +39 -0
- package/dist/server/modules/tasks/task-activity-log.js +43 -0
- package/dist/server/modules/tasks/task-activity-log.js.map +1 -0
- package/dist/server/modules/tasks/task-helper-client.d.ts +11 -0
- package/dist/server/modules/tasks/task-helper-client.js +132 -0
- package/dist/server/modules/tasks/task-helper-client.js.map +1 -0
- package/dist/server/modules/tasks/task-helper-process-handlers.d.ts +16 -0
- package/dist/server/modules/tasks/task-helper-process-handlers.js +14 -0
- package/dist/server/modules/tasks/task-helper-process-handlers.js.map +1 -0
- package/dist/server/modules/tasks/task-helper-process.d.ts +1 -0
- package/dist/server/modules/tasks/task-helper-process.js +49 -0
- package/dist/server/modules/tasks/task-helper-process.js.map +1 -0
- package/dist/server/modules/tasks/task-lane-executors.d.ts +2 -0
- package/dist/server/modules/tasks/task-lane-executors.js +15 -0
- package/dist/server/modules/tasks/task-lane-executors.js.map +1 -0
- package/dist/server/modules/tasks/task-manager.d.ts +15 -0
- package/dist/server/modules/tasks/task-manager.js +36 -0
- package/dist/server/modules/tasks/task-manager.js.map +1 -0
- package/dist/server/modules/tasks/task-metrics.d.ts +9 -0
- package/dist/server/modules/tasks/task-metrics.js +81 -0
- package/dist/server/modules/tasks/task-metrics.js.map +1 -0
- package/dist/server/modules/tasks/task-registry.d.ts +7 -0
- package/dist/server/modules/tasks/task-registry.js +21 -0
- package/dist/server/modules/tasks/task-registry.js.map +1 -0
- package/dist/server/modules/tasks/task-scheduler.d.ts +31 -0
- package/dist/server/modules/tasks/task-scheduler.js +473 -0
- package/dist/server/modules/tasks/task-scheduler.js.map +1 -0
- package/dist/server/modules/tasks/task-types.d.ts +106 -0
- package/dist/server/modules/tasks/task-types.js +23 -0
- package/dist/server/modules/tasks/task-types.js.map +1 -0
- package/dist/server/modules/terminal/command-template-service.d.ts +4 -0
- package/dist/server/modules/terminal/command-template-service.js +5 -3
- package/dist/server/modules/terminal/command-template-service.js.map +1 -1
- package/dist/server/modules/terminal/runtime/terminal-log-spooler.d.ts +7 -3
- package/dist/server/modules/terminal/runtime/terminal-log-spooler.js +95 -15
- package/dist/server/modules/terminal/runtime/terminal-log-spooler.js.map +1 -1
- package/dist/server/modules/terminal/runtime/terminal-log-writer-client.d.ts +21 -0
- package/dist/server/modules/terminal/runtime/terminal-log-writer-client.js +144 -0
- package/dist/server/modules/terminal/runtime/terminal-log-writer-client.js.map +1 -0
- package/dist/server/modules/terminal/runtime/terminal-log-writer-process.d.ts +1 -0
- package/dist/server/modules/terminal/runtime/terminal-log-writer-process.js +187 -0
- package/dist/server/modules/terminal/runtime/terminal-log-writer-process.js.map +1 -0
- package/dist/server/modules/terminal/terminal-service.d.ts +12 -0
- package/dist/server/modules/terminal/terminal-service.js +34 -17
- package/dist/server/modules/terminal/terminal-service.js.map +1 -1
- package/dist/server/modules/workbench/workbench-service.d.ts +23 -2
- package/dist/server/modules/workbench/workbench-service.js +126 -15
- package/dist/server/modules/workbench/workbench-service.js.map +1 -1
- package/dist/server/modules/workbench/workspace-panel-snapshot-service.d.ts +5 -1
- package/dist/server/modules/workbench/workspace-panel-snapshot-service.js +88 -19
- package/dist/server/modules/workbench/workspace-panel-snapshot-service.js.map +1 -1
- package/dist/server/modules/workspace/workspace-code-composition.d.ts +2 -0
- package/dist/server/modules/workspace/workspace-code-composition.js +154 -0
- package/dist/server/modules/workspace/workspace-code-composition.js.map +1 -0
- package/dist/server/modules/workspace/workspace-controller.d.ts +14 -0
- package/dist/server/modules/workspace/workspace-controller.js +19 -0
- package/dist/server/modules/workspace/workspace-controller.js.map +1 -1
- package/dist/server/modules/workspace/workspace-service.d.ts +21 -14
- package/dist/server/modules/workspace/workspace-service.js +183 -234
- package/dist/server/modules/workspace/workspace-service.js.map +1 -1
- package/dist/server/modules/worktree/worktree-cleanup-service.d.ts +35 -0
- package/dist/server/modules/worktree/worktree-cleanup-service.js +210 -0
- package/dist/server/modules/worktree/worktree-cleanup-service.js.map +1 -0
- package/dist/server/modules/worktree/worktree-controller.d.ts +44 -0
- package/dist/server/modules/worktree/worktree-controller.js +40 -0
- package/dist/server/modules/worktree/worktree-controller.js.map +1 -0
- package/dist/server/modules/worktree/worktree-manager.d.ts +34 -0
- package/dist/server/modules/worktree/worktree-manager.js +292 -0
- package/dist/server/modules/worktree/worktree-manager.js.map +1 -0
- package/dist/server/modules/worktree/worktree-merge-service.d.ts +52 -0
- package/dist/server/modules/worktree/worktree-merge-service.js +293 -0
- package/dist/server/modules/worktree/worktree-merge-service.js.map +1 -0
- package/dist/server/modules/worktree/worktree-sync-service.d.ts +23 -0
- package/dist/server/modules/worktree/worktree-sync-service.js +166 -0
- package/dist/server/modules/worktree/worktree-sync-service.js.map +1 -0
- package/dist/server/routes/assistant.d.ts +3 -0
- package/dist/server/routes/assistant.js +15 -0
- package/dist/server/routes/assistant.js.map +1 -0
- package/dist/server/routes/debug-targets.d.ts +3 -0
- package/dist/server/routes/debug-targets.js +15 -0
- package/dist/server/routes/debug-targets.js.map +1 -0
- package/dist/server/routes/git.js +1 -0
- package/dist/server/routes/git.js.map +1 -1
- package/dist/server/routes/observability.d.ts +3 -0
- package/dist/server/routes/observability.js +7 -0
- package/dist/server/routes/observability.js.map +1 -0
- package/dist/server/routes/workspaces.js +2 -0
- package/dist/server/routes/workspaces.js.map +1 -1
- package/dist/server/routes/worktrees.d.ts +3 -0
- package/dist/server/routes/worktrees.js +8 -0
- package/dist/server/routes/worktrees.js.map +1 -0
- package/dist/server/server/create-server.d.ts +34 -0
- package/dist/server/server/create-server.js +100 -10
- package/dist/server/server/create-server.js.map +1 -1
- package/dist/server/shared/utils/secret-box.d.ts +2 -0
- package/dist/server/shared/utils/secret-box.js +29 -0
- package/dist/server/shared/utils/secret-box.js.map +1 -0
- package/dist/server/shared/utils/terminal-debug-log.js +5 -3
- package/dist/server/shared/utils/terminal-debug-log.js.map +1 -1
- package/dist/server/storage/repositories/ai-fallback-edit-repository.d.ts +11 -0
- package/dist/server/storage/repositories/ai-fallback-edit-repository.js +118 -0
- package/dist/server/storage/repositories/ai-fallback-edit-repository.js.map +1 -0
- package/dist/server/storage/repositories/debug-runtime-session-repository.d.ts +11 -0
- package/dist/server/storage/repositories/debug-runtime-session-repository.js +100 -0
- package/dist/server/storage/repositories/debug-runtime-session-repository.js.map +1 -0
- package/dist/server/storage/repositories/debug-service-repository.d.ts +9 -0
- package/dist/server/storage/repositories/debug-service-repository.js +99 -0
- package/dist/server/storage/repositories/debug-service-repository.js.map +1 -0
- package/dist/server/storage/repositories/debug-target-repository.d.ts +11 -0
- package/dist/server/storage/repositories/debug-target-repository.js +100 -0
- package/dist/server/storage/repositories/debug-target-repository.js.map +1 -0
- package/dist/server/storage/repositories/framework-analysis-result-repository.d.ts +9 -0
- package/dist/server/storage/repositories/framework-analysis-result-repository.js +98 -0
- package/dist/server/storage/repositories/framework-analysis-result-repository.js.map +1 -0
- package/dist/server/storage/repositories/git-remote-credential-repository.d.ts +9 -0
- package/dist/server/storage/repositories/git-remote-credential-repository.js +51 -0
- package/dist/server/storage/repositories/git-remote-credential-repository.js.map +1 -0
- package/dist/server/storage/repositories/port-lease-repository.d.ts +12 -0
- package/dist/server/storage/repositories/port-lease-repository.js +124 -0
- package/dist/server/storage/repositories/port-lease-repository.js.map +1 -0
- package/dist/server/storage/repositories/runtime-binding-repository.d.ts +10 -0
- package/dist/server/storage/repositories/runtime-binding-repository.js +89 -0
- package/dist/server/storage/repositories/runtime-binding-repository.js.map +1 -0
- package/dist/server/storage/repositories/terminal-command-template-repository.js +77 -4
- package/dist/server/storage/repositories/terminal-command-template-repository.js.map +1 -1
- package/dist/server/storage/repositories/terminal-instance-repository.js +89 -7
- package/dist/server/storage/repositories/terminal-instance-repository.js.map +1 -1
- package/dist/server/storage/repositories/workspace-navigation-state-repository.d.ts +9 -0
- package/dist/server/storage/repositories/workspace-navigation-state-repository.js +49 -0
- package/dist/server/storage/repositories/workspace-navigation-state-repository.js.map +1 -0
- package/dist/server/storage/repositories/workspace-repository.d.ts +7 -1
- package/dist/server/storage/repositories/workspace-repository.js +32 -8
- package/dist/server/storage/repositories/workspace-repository.js.map +1 -1
- package/dist/server/storage/repositories/workspace-worktree-repository.d.ts +13 -0
- package/dist/server/storage/repositories/workspace-worktree-repository.js +158 -0
- package/dist/server/storage/repositories/workspace-worktree-repository.js.map +1 -0
- package/dist/server/storage/sqlite/client.js +301 -0
- package/dist/server/storage/sqlite/client.js.map +1 -1
- package/dist/server/storage/sqlite/schema.sql +238 -0
- package/dist/server/types/domain.d.ts +231 -0
- package/dist/server/ws/workbench-ws-hub.js +33 -9
- package/dist/server/ws/workbench-ws-hub.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.js +18 -6
- package/node_modules/@codingns/session-sync-core/dist/providers/claude-code.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/codex.js +14 -2
- package/node_modules/@codingns/session-sync-core/dist/providers/codex.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/opencode.js +25 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/opencode.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/types.d.ts +6 -0
- package/package.json +1 -1
- package/dist/public/assets/index-1VIm8lVL.css +0 -1
- package/dist/public/assets/index-Dti93O2S.js +0 -109
|
@@ -4,6 +4,7 @@ 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";
|
|
6
6
|
import { logPerformance } from "../../shared/utils/perf-log.js";
|
|
7
|
+
import { isTerminalDebugEnabled, logTerminalDebug, terminalDebugNowMs } from "../../shared/utils/terminal-debug-log.js";
|
|
7
8
|
import { nowIso } from "../../shared/utils/time.js";
|
|
8
9
|
import { isCommandAvailable } from "../../shared/utils/command-availability.js";
|
|
9
10
|
import { inspectSessionActivity } from "./session-activity-inspector.js";
|
|
@@ -11,8 +12,11 @@ import { SessionActivityAuthorityService } from "./session-activity-authority-se
|
|
|
11
12
|
import { mapSessionProviderError } from "./session-provider-error-mapper.js";
|
|
12
13
|
import { SessionForkRepository } from "../../storage/repositories/session-fork-repository.js";
|
|
13
14
|
import { enrichClaudeCapabilities } from "../provider/claude-model-options.js";
|
|
14
|
-
import { CodexModelOptionsService, enrichCodexCapabilities } from "../provider/codex-model-options.js";
|
|
15
|
-
import { OpenCodeModelOptionsService, enrichOpenCodeCapabilities } from "../provider/opencode-model-options.js";
|
|
15
|
+
import { CodexModelOptionsService, createFallbackCodexModelOptions, enrichCodexCapabilities } from "../provider/codex-model-options.js";
|
|
16
|
+
import { OpenCodeModelOptionsService, createFallbackOpenCodeModelOptions, enrichOpenCodeCapabilities } from "../provider/opencode-model-options.js";
|
|
17
|
+
import { ProviderDiscoveryHelperClient } from "../provider/provider-discovery-helper-client.js";
|
|
18
|
+
import { createTaskManager } from "../tasks/task-manager.js";
|
|
19
|
+
import { HOST_TASK_TYPES } from "../tasks/task-types.js";
|
|
16
20
|
import { CodexAppServerHelperClient } from "./codex-app-server-helper-client.js";
|
|
17
21
|
const RECONSTRUCTED_FORK_TARGET_PROVIDERS = new Set(["codex", "claude-code", "opencode"]);
|
|
18
22
|
const FORK_RECONSTRUCTION_PAGE_SIZE = 200;
|
|
@@ -25,6 +29,9 @@ const SESSION_START_DEFERRED_PROVIDERS = new Set([
|
|
|
25
29
|
"kimi"
|
|
26
30
|
]);
|
|
27
31
|
const MUTABLE_HISTORY_TAIL_REFRESH_INTERVAL_MS = 1_200;
|
|
32
|
+
const WORKSPACE_DISCOVERY_BACKGROUND_MAX_AGE_MS = 15_000;
|
|
33
|
+
const PROVIDER_CAPABILITY_CACHE_MAX_AGE_MS = 5_000;
|
|
34
|
+
const WORKSPACE_DISCOVERY_PERSIST_BATCH_SIZE = 25;
|
|
28
35
|
export class SessionHistoryService {
|
|
29
36
|
db;
|
|
30
37
|
workspaceRepository;
|
|
@@ -45,11 +52,14 @@ export class SessionHistoryService {
|
|
|
45
52
|
openCodeModelOptionsService;
|
|
46
53
|
providerCliCommandPaths;
|
|
47
54
|
providerCliAvailability;
|
|
55
|
+
providerDiscoveryHelperClient = new ProviderDiscoveryHelperClient();
|
|
56
|
+
providerSessionDiscoveryConfig;
|
|
57
|
+
taskManager;
|
|
48
58
|
workspaceDiscoveryStatuses = new Map();
|
|
49
|
-
workspaceDiscoveryInflight = new Map();
|
|
50
59
|
workspaceStateRefreshInflight = new Map();
|
|
60
|
+
providerCapabilityCache = new Map();
|
|
51
61
|
workspaceSessionRelations = new Map();
|
|
52
|
-
constructor(db, workspaceRepository, sessionBindingRepository, sessionChangedFileService, sessionIndexRepository, sessionMessageAttachmentService, sessionStateRepository, sessionStatusSnapshotRepository, config, sessionActivityAuthorityService = new SessionActivityAuthorityService(), sessionMessageOriginRepository = null, sessionForkRepository = null, adapterOverrides = {}) {
|
|
62
|
+
constructor(db, workspaceRepository, sessionBindingRepository, sessionChangedFileService, sessionIndexRepository, sessionMessageAttachmentService, sessionStateRepository, sessionStatusSnapshotRepository, config, sessionActivityAuthorityService = new SessionActivityAuthorityService(), sessionMessageOriginRepository = null, sessionForkRepository = null, adapterOverrides = {}, taskManager = createTaskManager()) {
|
|
53
63
|
this.db = db;
|
|
54
64
|
this.workspaceRepository = workspaceRepository;
|
|
55
65
|
this.sessionBindingRepository = sessionBindingRepository;
|
|
@@ -61,6 +71,7 @@ export class SessionHistoryService {
|
|
|
61
71
|
this.sessionMessageOriginRepository = sessionMessageOriginRepository;
|
|
62
72
|
this.sessionActivityAuthorityService = sessionActivityAuthorityService;
|
|
63
73
|
this.sessionForkRepository = sessionForkRepository ?? new SessionForkRepository(db);
|
|
74
|
+
this.taskManager = taskManager;
|
|
64
75
|
this.claudeCodeHomeDir = config.claudeCodeHomeDir;
|
|
65
76
|
this.providerCliCommandPaths = {
|
|
66
77
|
"claude-code": process.platform === "win32" ? "claude.cmd" : "claude",
|
|
@@ -70,6 +81,18 @@ export class SessionHistoryService {
|
|
|
70
81
|
};
|
|
71
82
|
// CLI 是否可用只在 Host 启动时探测一次;后续统一读缓存,更新 CLI 后重启 Host 生效。
|
|
72
83
|
this.providerCliAvailability = buildProviderCliAvailabilitySnapshot(this.providerCliCommandPaths);
|
|
84
|
+
this.providerSessionDiscoveryConfig = {
|
|
85
|
+
claudeCodeHomeDir: config.claudeCodeHomeDir,
|
|
86
|
+
codexCliPath: config.codexCliPath,
|
|
87
|
+
codexHomeDir: config.codexHomeDir,
|
|
88
|
+
geminiCliPath: config.geminiCliPath,
|
|
89
|
+
geminiHomeDir: config.geminiHomeDir,
|
|
90
|
+
kimiDefaultModel: config.kimiDefaultModel,
|
|
91
|
+
kimiHomeDir: config.kimiHomeDir,
|
|
92
|
+
opencodeBaseUrl: config.opencodeBaseUrl,
|
|
93
|
+
opencodeDataDir: config.opencodeDataDir,
|
|
94
|
+
opencodeDbPath: config.opencodeDbPath
|
|
95
|
+
};
|
|
73
96
|
this.providerRegistry = new ProviderRegistry([
|
|
74
97
|
new ClaudeCodeAdapter({ homeDir: config.claudeCodeHomeDir }),
|
|
75
98
|
new CodexAdapter({
|
|
@@ -102,6 +125,32 @@ export class SessionHistoryService {
|
|
|
102
125
|
baseUrlResolver: config.opencodeBaseUrlResolver?.resolve.bind(config.opencodeBaseUrlResolver),
|
|
103
126
|
commandPath: config.opencodeCliPath
|
|
104
127
|
});
|
|
128
|
+
this.registerBackgroundTasks();
|
|
129
|
+
}
|
|
130
|
+
observeBackgroundTaskMetrics() {
|
|
131
|
+
return this.taskManager.observe();
|
|
132
|
+
}
|
|
133
|
+
registerBackgroundTasks() {
|
|
134
|
+
if (!this.taskManager.has(HOST_TASK_TYPES.workspaceDiscovery)) {
|
|
135
|
+
this.taskManager.register({
|
|
136
|
+
taskType: HOST_TASK_TYPES.workspaceDiscovery,
|
|
137
|
+
executionLane: "helper_process",
|
|
138
|
+
run: async ({ workspaceId, userId, refreshStateMode }) => this.runDiscoverWorkspaceSessions(workspaceId, userId, refreshStateMode)
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
if (!this.taskManager.has(HOST_TASK_TYPES.providerCapabilityRefresh)) {
|
|
142
|
+
this.taskManager.register({
|
|
143
|
+
taskType: HOST_TASK_TYPES.providerCapabilityRefresh,
|
|
144
|
+
executionLane: "external_process",
|
|
145
|
+
run: async ({ capabilities, workspacePath }) => {
|
|
146
|
+
const value = await this.enrichProviderCapabilities(capabilities, workspacePath);
|
|
147
|
+
this.providerCapabilityCache.set(buildProviderCapabilityCacheKey(capabilities.provider, workspacePath), {
|
|
148
|
+
refreshedAt: Date.now(),
|
|
149
|
+
value
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
105
154
|
}
|
|
106
155
|
async discoverWorkspaceSessions(workspaceId, userId, options) {
|
|
107
156
|
const maxAgeMs = options?.maxAgeMs ?? 0;
|
|
@@ -112,17 +161,47 @@ export class SessionHistoryService {
|
|
|
112
161
|
discoveryStatus?.isComplete === true &&
|
|
113
162
|
maxAgeMs > 0 &&
|
|
114
163
|
Date.now() - lastRefreshedAt <= maxAgeMs) {
|
|
164
|
+
this.taskManager.recordCacheHit(HOST_TASK_TYPES.workspaceDiscovery, workspaceId);
|
|
115
165
|
return this.listWorkspaceSessions(workspaceId, userId);
|
|
116
166
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
167
|
+
return this.taskManager.enqueue(HOST_TASK_TYPES.workspaceDiscovery, {
|
|
168
|
+
key: workspaceId,
|
|
169
|
+
source: "session_history.discover_workspace_sessions",
|
|
170
|
+
input: {
|
|
171
|
+
workspaceId,
|
|
172
|
+
userId,
|
|
173
|
+
refreshStateMode: options?.refreshStateMode ?? "inline"
|
|
174
|
+
}
|
|
175
|
+
}).promise;
|
|
176
|
+
}
|
|
177
|
+
requestWorkspaceDiscovery(workspaceId, userId, options) {
|
|
178
|
+
const maxAgeMs = options?.maxAgeMs ?? WORKSPACE_DISCOVERY_BACKGROUND_MAX_AGE_MS;
|
|
179
|
+
const force = options?.force ?? false;
|
|
180
|
+
if (!force && !this.needsWorkspaceDiscovery(workspaceId, maxAgeMs)) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const task = this.taskManager.enqueue(HOST_TASK_TYPES.workspaceDiscovery, {
|
|
184
|
+
key: workspaceId,
|
|
185
|
+
source: "session_history.request_workspace_discovery",
|
|
186
|
+
input: {
|
|
187
|
+
workspaceId,
|
|
188
|
+
userId,
|
|
189
|
+
refreshStateMode: options?.refreshStateMode ?? "deferred"
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
if (task.deduped) {
|
|
193
|
+
return;
|
|
120
194
|
}
|
|
121
|
-
|
|
122
|
-
|
|
195
|
+
void task.promise.catch((error) => {
|
|
196
|
+
logPerformance("workspace.discover_sessions.background_failed", 0, {
|
|
197
|
+
workspaceId,
|
|
198
|
+
error: error instanceof Error ? error.message : "unknown"
|
|
199
|
+
}, {
|
|
200
|
+
thresholdMs: 0,
|
|
201
|
+
force: true
|
|
202
|
+
});
|
|
203
|
+
return this.listWorkspaceSessions(workspaceId, userId);
|
|
123
204
|
});
|
|
124
|
-
this.workspaceDiscoveryInflight.set(workspaceId, task);
|
|
125
|
-
return task;
|
|
126
205
|
}
|
|
127
206
|
needsWorkspaceDiscovery(workspaceId, maxAgeMs) {
|
|
128
207
|
if (maxAgeMs <= 0) {
|
|
@@ -246,13 +325,13 @@ export class SessionHistoryService {
|
|
|
246
325
|
const binding = this.getBindingOrThrow(sessionId);
|
|
247
326
|
await this.syncSessionTitleFromProvider(sessionId, binding);
|
|
248
327
|
}
|
|
249
|
-
async syncWorkspaceSessionTitles(workspaceId, userId) {
|
|
328
|
+
async syncWorkspaceSessionTitles(workspaceId, userId, concurrency = 1) {
|
|
250
329
|
const sessions = this.sessionIndexRepository.listByWorkspace(workspaceId, userId);
|
|
251
|
-
|
|
330
|
+
await runWithConcurrency(sessions, concurrency, async (session) => {
|
|
252
331
|
await this.syncSessionTitle(session.sessionId).catch(() => {
|
|
253
332
|
return;
|
|
254
333
|
});
|
|
255
|
-
}
|
|
334
|
+
});
|
|
256
335
|
}
|
|
257
336
|
async listSessionChangedFiles(sessionId, userId) {
|
|
258
337
|
this.getSession(sessionId, userId);
|
|
@@ -266,7 +345,7 @@ export class SessionHistoryService {
|
|
|
266
345
|
}
|
|
267
346
|
getProviderCapabilitiesSnapshot(provider) {
|
|
268
347
|
try {
|
|
269
|
-
return this.applyProviderCliAvailability(this.capabilityService.getProviderCapabilities(provider));
|
|
348
|
+
return this.resolveProviderCapabilitiesImmediate(this.applyProviderCliAvailability(this.capabilityService.getProviderCapabilities(provider)), null);
|
|
270
349
|
}
|
|
271
350
|
catch (error) {
|
|
272
351
|
throw mapSessionProviderError(error);
|
|
@@ -275,7 +354,9 @@ export class SessionHistoryService {
|
|
|
275
354
|
async getProviderCapabilities(provider, workspaceId) {
|
|
276
355
|
try {
|
|
277
356
|
const workspacePath = workspaceId ? this.getWorkspaceOrThrow(workspaceId).path : null;
|
|
278
|
-
|
|
357
|
+
const baseCapabilities = this.applyProviderCliAvailability(this.capabilityService.getProviderCapabilities(provider));
|
|
358
|
+
this.scheduleProviderCapabilityRefresh(baseCapabilities, workspacePath);
|
|
359
|
+
return this.resolveProviderCapabilitiesImmediate(baseCapabilities, workspacePath);
|
|
279
360
|
}
|
|
280
361
|
catch (error) {
|
|
281
362
|
throw mapSessionProviderError(error);
|
|
@@ -284,9 +365,14 @@ export class SessionHistoryService {
|
|
|
284
365
|
async getSessionCapabilities(sessionId) {
|
|
285
366
|
const binding = this.getBindingOrThrow(sessionId);
|
|
286
367
|
const workspace = this.getWorkspaceOrThrow(binding.workspaceId);
|
|
368
|
+
const workspacePath = workspace.path;
|
|
287
369
|
return this.capabilityService
|
|
288
370
|
.getSessionCapabilities(binding.provider, binding.providerSessionId)
|
|
289
|
-
.then((capabilities) =>
|
|
371
|
+
.then((capabilities) => {
|
|
372
|
+
const normalizedCapabilities = this.applyProviderCliAvailability(capabilities);
|
|
373
|
+
this.scheduleProviderCapabilityRefresh(normalizedCapabilities, workspacePath);
|
|
374
|
+
return this.resolveProviderCapabilitiesImmediate(normalizedCapabilities, workspacePath);
|
|
375
|
+
})
|
|
290
376
|
.catch((error) => {
|
|
291
377
|
throw mapSessionProviderError(error);
|
|
292
378
|
});
|
|
@@ -299,6 +385,48 @@ export class SessionHistoryService {
|
|
|
299
385
|
const codexEnriched = await enrichCodexCapabilities(claudeEnriched, this.codexModelOptionsService);
|
|
300
386
|
return enrichOpenCodeCapabilities(codexEnriched, this.openCodeModelOptionsService, workspacePath);
|
|
301
387
|
}
|
|
388
|
+
resolveProviderCapabilitiesImmediate(capabilities, workspacePath) {
|
|
389
|
+
const cacheKey = buildProviderCapabilityCacheKey(capabilities.provider, workspacePath);
|
|
390
|
+
const cached = this.providerCapabilityCache.get(cacheKey);
|
|
391
|
+
if (cached) {
|
|
392
|
+
this.taskManager.recordCacheHit(HOST_TASK_TYPES.providerCapabilityRefresh, cacheKey);
|
|
393
|
+
return cached.value;
|
|
394
|
+
}
|
|
395
|
+
const claudeEnriched = enrichClaudeCapabilities(capabilities, {
|
|
396
|
+
claudeHomeDir: this.claudeCodeHomeDir,
|
|
397
|
+
workspacePath
|
|
398
|
+
});
|
|
399
|
+
return applyImmediateModelOptionFallbacks(claudeEnriched, this.codexModelOptionsService.peekSnapshot(), this.openCodeModelOptionsService.peekSnapshot(workspacePath));
|
|
400
|
+
}
|
|
401
|
+
scheduleProviderCapabilityRefresh(capabilities, workspacePath) {
|
|
402
|
+
const cacheKey = buildProviderCapabilityCacheKey(capabilities.provider, workspacePath);
|
|
403
|
+
const cached = this.providerCapabilityCache.get(cacheKey);
|
|
404
|
+
if (cached &&
|
|
405
|
+
Date.now() - cached.refreshedAt <= PROVIDER_CAPABILITY_CACHE_MAX_AGE_MS) {
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
const task = this.taskManager.enqueue(HOST_TASK_TYPES.providerCapabilityRefresh, {
|
|
409
|
+
key: cacheKey,
|
|
410
|
+
source: "session_history.provider_capability_refresh",
|
|
411
|
+
input: {
|
|
412
|
+
capabilities,
|
|
413
|
+
workspacePath
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
if (task.deduped) {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
void task.promise.catch((error) => {
|
|
420
|
+
logPerformance("provider.capabilities.background_failed", 0, {
|
|
421
|
+
provider: capabilities.provider,
|
|
422
|
+
workspacePath,
|
|
423
|
+
error: error instanceof Error ? error.message : "unknown"
|
|
424
|
+
}, {
|
|
425
|
+
thresholdMs: 0,
|
|
426
|
+
force: true
|
|
427
|
+
});
|
|
428
|
+
});
|
|
429
|
+
}
|
|
302
430
|
applyProviderCliAvailability(capabilities) {
|
|
303
431
|
if (!isProviderCliBacked(capabilities.provider)) {
|
|
304
432
|
return capabilities;
|
|
@@ -472,6 +600,7 @@ export class SessionHistoryService {
|
|
|
472
600
|
rawStoreRef: binding.rawStoreRef,
|
|
473
601
|
sourceType: input.sourceType,
|
|
474
602
|
sourceMessageId,
|
|
603
|
+
sourceMessageSnapshot: input.sourceMessageSnapshot ?? null,
|
|
475
604
|
strategy: input.strategy ?? "auto"
|
|
476
605
|
});
|
|
477
606
|
const sessionId = createId();
|
|
@@ -561,7 +690,7 @@ export class SessionHistoryService {
|
|
|
561
690
|
throw mapSessionProviderError(new Error("FORK_TARGET_PROVIDER_NOT_SUPPORTED"));
|
|
562
691
|
}
|
|
563
692
|
const sourceIndex = this.sessionIndexRepository.findIndexRecordBySessionId(input.sessionId);
|
|
564
|
-
const inheritedMessages = await this.readForkSourceMessages(input.sessionId, sourceBinding, input.sourceType, sourceMessageId);
|
|
693
|
+
const inheritedMessages = await this.readForkSourceMessages(input.sessionId, sourceBinding, input.sourceType, sourceMessageId, input.sourceMessageSnapshot ?? null);
|
|
565
694
|
const reconstructedMessages = inheritedMessages.filter((message) => (message.role === "user" || message.role === "assistant")
|
|
566
695
|
&& message.kind === "text"
|
|
567
696
|
&& message.content.trim().length > 0);
|
|
@@ -624,7 +753,7 @@ export class SessionHistoryService {
|
|
|
624
753
|
this.workspaceSessionRelations.set(sourceBinding.workspaceId, relationMap);
|
|
625
754
|
return this.getSessionListItemOrThrow(startedSession.sessionId, input.userId);
|
|
626
755
|
}
|
|
627
|
-
async readForkSourceMessages(sessionId, binding, sourceType, sourceMessageId) {
|
|
756
|
+
async readForkSourceMessages(sessionId, binding, sourceType, sourceMessageId, sourceMessageSnapshot = null) {
|
|
628
757
|
const messages = [];
|
|
629
758
|
let cursor = null;
|
|
630
759
|
while (true) {
|
|
@@ -642,7 +771,21 @@ export class SessionHistoryService {
|
|
|
642
771
|
if (targetIndex < 0) {
|
|
643
772
|
throw mapSessionProviderError(new Error("FORK_SOURCE_MESSAGE_NOT_FOUND"));
|
|
644
773
|
}
|
|
645
|
-
|
|
774
|
+
const inheritedMessages = messages.slice(0, targetIndex + 1);
|
|
775
|
+
if (!sourceMessageSnapshot) {
|
|
776
|
+
return inheritedMessages;
|
|
777
|
+
}
|
|
778
|
+
const targetMessage = inheritedMessages[targetIndex];
|
|
779
|
+
if (!targetMessage) {
|
|
780
|
+
return inheritedMessages;
|
|
781
|
+
}
|
|
782
|
+
inheritedMessages[targetIndex] = {
|
|
783
|
+
...targetMessage,
|
|
784
|
+
role: sourceMessageSnapshot.role,
|
|
785
|
+
kind: sourceMessageSnapshot.kind,
|
|
786
|
+
content: sourceMessageSnapshot.content
|
|
787
|
+
};
|
|
788
|
+
return inheritedMessages;
|
|
646
789
|
}
|
|
647
790
|
assertForkDepthWithinLimit(parentSessionId) {
|
|
648
791
|
const nextDepth = this.getSessionForkDepth(parentSessionId) + 1;
|
|
@@ -969,16 +1112,29 @@ export class SessionHistoryService {
|
|
|
969
1112
|
}
|
|
970
1113
|
async runDiscoverWorkspaceSessions(workspaceId, userId, refreshStateMode = "inline") {
|
|
971
1114
|
const startedAt = Date.now();
|
|
1115
|
+
const debugStartedAtMs = terminalDebugNowMs();
|
|
972
1116
|
const workspace = this.getWorkspaceOrThrow(workspaceId);
|
|
973
1117
|
let discoverDurationMs = 0;
|
|
974
1118
|
let persistDurationMs = 0;
|
|
1119
|
+
let persistPass1DurationMs = 0;
|
|
1120
|
+
let persistPass1BatchCount = 0;
|
|
1121
|
+
let persistPass1MaxBatchMs = 0;
|
|
1122
|
+
let relationMapDurationMs = 0;
|
|
1123
|
+
let persistPass2DurationMs = 0;
|
|
1124
|
+
let persistPass2BatchCount = 0;
|
|
1125
|
+
let persistPass2MaxBatchMs = 0;
|
|
1126
|
+
let cleanupDurationMs = 0;
|
|
1127
|
+
let listItemsDurationMs = 0;
|
|
1128
|
+
let refreshStateDurationMs = 0;
|
|
975
1129
|
const refreshStateCount = 10;
|
|
976
1130
|
try {
|
|
977
1131
|
const discoverStartedAt = Date.now();
|
|
978
1132
|
const existingWorkspaceSessions = this.sessionIndexRepository.listByWorkspace(workspaceId, userId);
|
|
979
1133
|
const knownSessions = this.buildKnownSessionSummaries(existingWorkspaceSessions, workspace.path);
|
|
980
|
-
const discovery = await this.
|
|
981
|
-
.discoverWorkspaceSessions(
|
|
1134
|
+
const discovery = await this.providerDiscoveryHelperClient
|
|
1135
|
+
.discoverWorkspaceSessions({
|
|
1136
|
+
config: this.providerSessionDiscoveryConfig,
|
|
1137
|
+
workspacePath: workspace.path,
|
|
982
1138
|
knownSessions
|
|
983
1139
|
})
|
|
984
1140
|
.catch((error) => {
|
|
@@ -990,10 +1146,9 @@ export class SessionHistoryService {
|
|
|
990
1146
|
const discoveredSessionIds = new Map();
|
|
991
1147
|
const persistedSessions = [];
|
|
992
1148
|
const claimedPendingSessionIds = new Set();
|
|
993
|
-
const
|
|
994
|
-
for (const session of
|
|
1149
|
+
const persistPass1Transaction = this.db.transaction((batch) => {
|
|
1150
|
+
for (const session of batch) {
|
|
995
1151
|
const exactExisting = this.sessionBindingRepository.findByProviderSession(session.provider, session.providerSessionId) ?? this.sessionBindingRepository.findByRawStoreRef(session.provider, session.rawStoreRef);
|
|
996
|
-
// discover 只能补全当前工作区,不能把别的工作区已有会话偷过来重绑。
|
|
997
1152
|
if (exactExisting && exactExisting.workspaceId !== workspaceId) {
|
|
998
1153
|
continue;
|
|
999
1154
|
}
|
|
@@ -1065,8 +1220,17 @@ export class SessionHistoryService {
|
|
|
1065
1220
|
existingIndex
|
|
1066
1221
|
});
|
|
1067
1222
|
}
|
|
1068
|
-
|
|
1069
|
-
|
|
1223
|
+
});
|
|
1224
|
+
const persistPass1StartedAt = Date.now();
|
|
1225
|
+
const persistPass1Stats = await runBatchedTransactions(sessions, WORKSPACE_DISCOVERY_PERSIST_BATCH_SIZE, persistPass1Transaction);
|
|
1226
|
+
persistPass1DurationMs = Date.now() - persistPass1StartedAt;
|
|
1227
|
+
persistPass1BatchCount = persistPass1Stats.batchCount;
|
|
1228
|
+
persistPass1MaxBatchMs = persistPass1Stats.maxBatchMs;
|
|
1229
|
+
const relationMapStartedAt = Date.now();
|
|
1230
|
+
const relationMap = this.buildWorkspaceSessionRelationMap(sessions, discoveredSessionIds);
|
|
1231
|
+
relationMapDurationMs = Date.now() - relationMapStartedAt;
|
|
1232
|
+
const persistPass2Transaction = this.db.transaction((batch) => {
|
|
1233
|
+
for (const persistedSession of batch) {
|
|
1070
1234
|
const relation = relationMap.get(persistedSession.sessionId);
|
|
1071
1235
|
const resolvedParentSessionId = relation?.parentSessionId
|
|
1072
1236
|
?? persistedSession.existingIndex?.parentSessionId
|
|
@@ -1104,26 +1268,56 @@ export class SessionHistoryService {
|
|
|
1104
1268
|
});
|
|
1105
1269
|
}
|
|
1106
1270
|
});
|
|
1107
|
-
const
|
|
1108
|
-
|
|
1109
|
-
|
|
1271
|
+
const persistPass2StartedAt = Date.now();
|
|
1272
|
+
const persistPass2Stats = await runBatchedTransactions(persistedSessions, WORKSPACE_DISCOVERY_PERSIST_BATCH_SIZE, persistPass2Transaction);
|
|
1273
|
+
persistPass2DurationMs = Date.now() - persistPass2StartedAt;
|
|
1274
|
+
persistPass2BatchCount = persistPass2Stats.batchCount;
|
|
1275
|
+
persistPass2MaxBatchMs = persistPass2Stats.maxBatchMs;
|
|
1276
|
+
persistDurationMs = persistPass1DurationMs + relationMapDurationMs + persistPass2DurationMs;
|
|
1110
1277
|
if (discovery.isComplete) {
|
|
1111
|
-
|
|
1278
|
+
const cleanupStartedAt = Date.now();
|
|
1279
|
+
await this.cleanupStaleHiddenSessions(workspaceId, userId, sessions);
|
|
1280
|
+
cleanupDurationMs = Date.now() - cleanupStartedAt;
|
|
1112
1281
|
}
|
|
1113
|
-
this.workspaceSessionRelations.set(workspaceId,
|
|
1282
|
+
this.workspaceSessionRelations.set(workspaceId, relationMap);
|
|
1283
|
+
const listItemsStartedAt = Date.now();
|
|
1114
1284
|
const items = this.sessionIndexRepository.listByWorkspace(workspaceId, userId);
|
|
1285
|
+
listItemsDurationMs = Date.now() - listItemsStartedAt;
|
|
1115
1286
|
const refreshCandidates = buildSessionStateRefreshCandidates(items, refreshStateCount);
|
|
1116
1287
|
this.workspaceDiscoveryStatuses.set(workspaceId, {
|
|
1117
1288
|
refreshedAt: Date.now(),
|
|
1118
1289
|
isComplete: discovery.isComplete
|
|
1119
1290
|
});
|
|
1291
|
+
const refreshStateStartedAt = Date.now();
|
|
1120
1292
|
if (refreshStateMode === "inline") {
|
|
1121
1293
|
await this.refreshRecentSessionStates(refreshCandidates, userId);
|
|
1122
1294
|
}
|
|
1123
1295
|
else {
|
|
1124
1296
|
this.scheduleWorkspaceStateRefresh(workspaceId, userId, refreshCandidates);
|
|
1125
1297
|
}
|
|
1298
|
+
refreshStateDurationMs = Date.now() - refreshStateStartedAt;
|
|
1126
1299
|
const nextItems = this.listWorkspaceSessions(workspaceId, userId);
|
|
1300
|
+
if (isTerminalDebugEnabled()) {
|
|
1301
|
+
logTerminalDebug("workspace.discovery.completed", {
|
|
1302
|
+
workspaceId,
|
|
1303
|
+
sessionCount: sessions.length,
|
|
1304
|
+
returnedSessionCount: nextItems.length,
|
|
1305
|
+
discoverMs: discoverDurationMs,
|
|
1306
|
+
persistMs: persistDurationMs,
|
|
1307
|
+
persistPass1Ms: persistPass1DurationMs,
|
|
1308
|
+
persistPass1BatchCount,
|
|
1309
|
+
persistPass1MaxBatchMs,
|
|
1310
|
+
relationMapMs: relationMapDurationMs,
|
|
1311
|
+
persistPass2Ms: persistPass2DurationMs,
|
|
1312
|
+
persistPass2BatchCount,
|
|
1313
|
+
persistPass2MaxBatchMs,
|
|
1314
|
+
cleanupMs: cleanupDurationMs,
|
|
1315
|
+
listItemsMs: listItemsDurationMs,
|
|
1316
|
+
refreshStateMs: refreshStateDurationMs,
|
|
1317
|
+
refreshStateDeferred: refreshStateMode !== "inline",
|
|
1318
|
+
durationMs: terminalDebugNowMs() - debugStartedAtMs
|
|
1319
|
+
});
|
|
1320
|
+
}
|
|
1127
1321
|
logPerformance("workspace.discover_sessions", Date.now() - startedAt, {
|
|
1128
1322
|
workspaceId,
|
|
1129
1323
|
workspacePath: workspace.path,
|
|
@@ -1135,6 +1329,16 @@ export class SessionHistoryService {
|
|
|
1135
1329
|
refreshedStates: refreshCandidates.length,
|
|
1136
1330
|
discoverMs: discoverDurationMs,
|
|
1137
1331
|
persistMs: persistDurationMs,
|
|
1332
|
+
persistPass1Ms: persistPass1DurationMs,
|
|
1333
|
+
persistPass1BatchCount,
|
|
1334
|
+
persistPass1MaxBatchMs,
|
|
1335
|
+
relationMapMs: relationMapDurationMs,
|
|
1336
|
+
persistPass2Ms: persistPass2DurationMs,
|
|
1337
|
+
persistPass2BatchCount,
|
|
1338
|
+
persistPass2MaxBatchMs,
|
|
1339
|
+
cleanupMs: cleanupDurationMs,
|
|
1340
|
+
listItemsMs: listItemsDurationMs,
|
|
1341
|
+
refreshStateMs: refreshStateDurationMs,
|
|
1138
1342
|
refreshStateDeferred: refreshStateMode !== "inline"
|
|
1139
1343
|
}, {
|
|
1140
1344
|
thresholdMs: 500
|
|
@@ -1147,6 +1351,16 @@ export class SessionHistoryService {
|
|
|
1147
1351
|
workspacePath: workspace.path,
|
|
1148
1352
|
discoverMs: discoverDurationMs,
|
|
1149
1353
|
persistMs: persistDurationMs,
|
|
1354
|
+
persistPass1Ms: persistPass1DurationMs,
|
|
1355
|
+
persistPass1BatchCount,
|
|
1356
|
+
persistPass1MaxBatchMs,
|
|
1357
|
+
relationMapMs: relationMapDurationMs,
|
|
1358
|
+
persistPass2Ms: persistPass2DurationMs,
|
|
1359
|
+
persistPass2BatchCount,
|
|
1360
|
+
persistPass2MaxBatchMs,
|
|
1361
|
+
cleanupMs: cleanupDurationMs,
|
|
1362
|
+
listItemsMs: listItemsDurationMs,
|
|
1363
|
+
refreshStateMs: refreshStateDurationMs,
|
|
1150
1364
|
refreshStateDeferred: refreshStateMode !== "inline",
|
|
1151
1365
|
error: error instanceof Error ? error.message : "unknown"
|
|
1152
1366
|
}, {
|
|
@@ -1391,7 +1605,12 @@ export class SessionHistoryService {
|
|
|
1391
1605
|
if (shouldSkipClaudePendingBinding(binding)) {
|
|
1392
1606
|
return;
|
|
1393
1607
|
}
|
|
1394
|
-
const nextTitle = (await this.
|
|
1608
|
+
const nextTitle = (await this.providerDiscoveryHelperClient.readSessionTitle({
|
|
1609
|
+
config: this.providerSessionDiscoveryConfig,
|
|
1610
|
+
provider: binding.provider,
|
|
1611
|
+
providerSessionId: binding.providerSessionId,
|
|
1612
|
+
rawStoreRef: binding.rawStoreRef
|
|
1613
|
+
})).trim();
|
|
1395
1614
|
const resolvedTitle = resolvePersistedSessionTitle(binding.provider, nextTitle, currentIndex.title);
|
|
1396
1615
|
if (resolvedTitle.length === 0 || resolvedTitle === currentIndex.title) {
|
|
1397
1616
|
return;
|
|
@@ -1548,7 +1767,7 @@ export class SessionHistoryService {
|
|
|
1548
1767
|
});
|
|
1549
1768
|
this.workspaceStateRefreshInflight.set(inflightKey, task);
|
|
1550
1769
|
}
|
|
1551
|
-
cleanupStaleHiddenSessions(workspaceId, userId, sessions) {
|
|
1770
|
+
async cleanupStaleHiddenSessions(workspaceId, userId, sessions) {
|
|
1552
1771
|
const discoveredProviderSessionIds = new Set(sessions.map((session) => buildProviderSessionKey(session.provider, session.providerSessionId)));
|
|
1553
1772
|
const discoveredRawStoreRefs = new Set(sessions.map((session) => session.rawStoreRef));
|
|
1554
1773
|
const staleHiddenSessions = this.sessionIndexRepository
|
|
@@ -1568,15 +1787,12 @@ export class SessionHistoryService {
|
|
|
1568
1787
|
if (staleHiddenSessions.length === 0) {
|
|
1569
1788
|
return;
|
|
1570
1789
|
}
|
|
1571
|
-
this.
|
|
1572
|
-
}
|
|
1573
|
-
deleteSessionsByIds(sessionIds) {
|
|
1574
|
-
const remove = this.db.transaction((ids) => {
|
|
1790
|
+
const deleteTransaction = this.db.transaction((ids) => {
|
|
1575
1791
|
for (const sessionId of ids) {
|
|
1576
1792
|
this.deleteSessionById(sessionId);
|
|
1577
1793
|
}
|
|
1578
1794
|
});
|
|
1579
|
-
|
|
1795
|
+
await runBatchedTransactions(staleHiddenSessions.map((session) => session.sessionId), WORKSPACE_DISCOVERY_PERSIST_BATCH_SIZE, deleteTransaction);
|
|
1580
1796
|
}
|
|
1581
1797
|
findPendingBindingDuplicate(sessionId, workspaceId, currentBinding, snapshot) {
|
|
1582
1798
|
if (!currentBinding || !isPendingBindingValue(currentBinding.providerSessionId)) {
|
|
@@ -2620,4 +2836,71 @@ function buildReconstructedForkPrompt(input) {
|
|
|
2620
2836
|
}
|
|
2621
2837
|
return lines.join("\n").trim();
|
|
2622
2838
|
}
|
|
2839
|
+
function buildProviderCapabilityCacheKey(provider, workspacePath) {
|
|
2840
|
+
return `${provider}::${workspacePath ?? ""}`;
|
|
2841
|
+
}
|
|
2842
|
+
async function runWithConcurrency(items, concurrency, worker) {
|
|
2843
|
+
const normalizedConcurrency = Math.max(1, Math.floor(concurrency) || 1);
|
|
2844
|
+
const queue = [...items];
|
|
2845
|
+
const runners = Array.from({
|
|
2846
|
+
length: Math.min(normalizedConcurrency, queue.length || 1)
|
|
2847
|
+
}, async () => {
|
|
2848
|
+
while (queue.length > 0) {
|
|
2849
|
+
const current = queue.shift();
|
|
2850
|
+
if (current === undefined) {
|
|
2851
|
+
return;
|
|
2852
|
+
}
|
|
2853
|
+
await worker(current);
|
|
2854
|
+
}
|
|
2855
|
+
});
|
|
2856
|
+
await Promise.all(runners);
|
|
2857
|
+
}
|
|
2858
|
+
async function runBatchedTransactions(items, batchSize, transaction) {
|
|
2859
|
+
const normalizedBatchSize = Math.max(1, Math.floor(batchSize) || 1);
|
|
2860
|
+
let batchCount = 0;
|
|
2861
|
+
let maxBatchMs = 0;
|
|
2862
|
+
for (let index = 0; index < items.length; index += normalizedBatchSize) {
|
|
2863
|
+
const batch = items.slice(index, index + normalizedBatchSize);
|
|
2864
|
+
const batchStartedAt = Date.now();
|
|
2865
|
+
transaction(batch);
|
|
2866
|
+
const batchDurationMs = Date.now() - batchStartedAt;
|
|
2867
|
+
batchCount += 1;
|
|
2868
|
+
maxBatchMs = Math.max(maxBatchMs, batchDurationMs);
|
|
2869
|
+
if (index + normalizedBatchSize < items.length) {
|
|
2870
|
+
await delay(0);
|
|
2871
|
+
}
|
|
2872
|
+
}
|
|
2873
|
+
return {
|
|
2874
|
+
batchCount,
|
|
2875
|
+
maxBatchMs
|
|
2876
|
+
};
|
|
2877
|
+
}
|
|
2878
|
+
function applyImmediateModelOptionFallbacks(capabilities, codexSnapshot, openCodeSnapshot) {
|
|
2879
|
+
if (capabilities.provider === "codex") {
|
|
2880
|
+
return {
|
|
2881
|
+
...capabilities,
|
|
2882
|
+
modelOptions: codexSnapshot?.modelOptions ?? createFallbackCodexModelOptions(null),
|
|
2883
|
+
defaultReasoningLevel: codexSnapshot?.defaultReasoningLevel ?? null,
|
|
2884
|
+
limitations: codexSnapshot
|
|
2885
|
+
? capabilities.limitations
|
|
2886
|
+
: Array.from(new Set([
|
|
2887
|
+
...capabilities.limitations,
|
|
2888
|
+
"当前暂时使用缓存或兜底模型列表,后台会继续刷新 Codex 能力。"
|
|
2889
|
+
]))
|
|
2890
|
+
};
|
|
2891
|
+
}
|
|
2892
|
+
if (capabilities.provider === "opencode") {
|
|
2893
|
+
return {
|
|
2894
|
+
...capabilities,
|
|
2895
|
+
modelOptions: openCodeSnapshot?.modelOptions ?? createFallbackOpenCodeModelOptions(null),
|
|
2896
|
+
limitations: openCodeSnapshot
|
|
2897
|
+
? capabilities.limitations
|
|
2898
|
+
: Array.from(new Set([
|
|
2899
|
+
...capabilities.limitations,
|
|
2900
|
+
"当前暂时使用缓存或兜底模型列表,后台会继续刷新 OpenCode 能力。"
|
|
2901
|
+
]))
|
|
2902
|
+
};
|
|
2903
|
+
}
|
|
2904
|
+
return capabilities;
|
|
2905
|
+
}
|
|
2623
2906
|
//# sourceMappingURL=session-history-service.js.map
|