@jingyi0605/codingns 0.9.5 → 0.9.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/codingns.mjs +75 -0
- package/dist/public/assets/{AdaptiveButlerPage-kkJDsnCO.js → AdaptiveButlerPage-DclGPzEx.js} +2 -2
- package/dist/public/assets/{App-DrNI9lWA.js → App-BxX5mm9o.js} +6 -6
- package/dist/public/assets/{BootstrapPage-QgVH5Mps.js → BootstrapPage-Bl21SsuW.js} +1 -1
- package/dist/public/assets/{ConversationPage-DVk8VfIj.js → ConversationPage-CmiVCV0q.js} +7 -7
- package/dist/public/assets/{DesktopDetachPreviewPage-BhfP0TpH.js → DesktopDetachPreviewPage-uaOHVsjV.js} +1 -1
- package/dist/public/assets/{DesktopModal-DRmDrv0S.js → DesktopModal-BxsogpLf.js} +1 -1
- package/dist/public/assets/{DesktopWindowPage-DNbJXnSs.js → DesktopWindowPage-Bubfw1nC.js} +1 -1
- package/dist/public/assets/{FileContextPanel---fLO4ve.js → FileContextPanel-DrYWcTkp.js} +1 -1
- package/dist/public/assets/{GitSidebar-sXUE0TqT.js → GitSidebar-CQsfJqun.js} +1 -1
- package/dist/public/assets/{MobileCreateSessionSheet-BftZ5pvb.js → MobileCreateSessionSheet-CqtmfVNo.js} +1 -1
- package/dist/public/assets/{MobileSheet-nw5SCa3N.js → MobileSheet-C5IVmUsO.js} +1 -1
- package/dist/public/assets/{MobileTopHeaderFrame-DH_D02Wy.js → MobileTopHeaderFrame-EoBm3-X0.js} +1 -1
- package/dist/public/assets/{MobileWorkspaceSwitcherHeader-2K406G5p.js → MobileWorkspaceSwitcherHeader-BC8MMQs_.js} +1 -1
- package/dist/public/assets/{PluginAccessOverview-BVJihw3D.js → PluginAccessOverview-CrQiQxxZ.js} +1 -1
- package/dist/public/assets/{PluginContainerPage-CR4vStvr.js → PluginContainerPage-_2u-9thM.js} +1 -1
- package/dist/public/assets/{PluginDetailPage-CrMX0Mnm.js → PluginDetailPage-F9cKjSCp.js} +1 -1
- package/dist/public/assets/{PluginsListPage-FtIL71Yg.js → PluginsListPage-BOhcua_4.js} +1 -1
- package/dist/public/assets/{RelayConnectEntryPage-Bt1apX53.js → RelayConnectEntryPage-Ck_uZLzj.js} +1 -1
- package/dist/public/assets/{ServerSettingsModal-D-guzPrI.js → ServerSettingsModal-ICd82a_x.js} +1 -1
- package/dist/public/assets/SessionIndexPage-Cox6P6dw.js +1 -0
- package/dist/public/assets/SettingsPage-BI5cM3j5.js +2 -0
- package/dist/public/assets/{TerminalManagerPanel-B5MKGPy-.js → TerminalManagerPanel-DiVhBQhf.js} +1 -1
- package/dist/public/assets/{TerminalPage-C2dTNGHK.js → TerminalPage-DUMUO7Ng.js} +1 -1
- package/dist/public/assets/{TerminalRuntimeFallbackModal-DAqOxFD8.js → TerminalRuntimeFallbackModal-DGPR_CMh.js} +1 -1
- package/dist/public/assets/{ToolFilesPage-IsNwyE6T.js → ToolFilesPage-m88CAp-r.js} +1 -1
- package/dist/public/assets/{ToolGitPage-BK1JBERN.js → ToolGitPage-DCYpfTsb.js} +1 -1
- package/dist/public/assets/{ToolProcessesPage-DwTYUQCK.js → ToolProcessesPage-Bk5ulsyq.js} +1 -1
- package/dist/public/assets/{ToolsHomePage-BLOy7lPg.js → ToolsHomePage-BrTwfjI7.js} +1 -1
- package/dist/public/assets/{WorkbenchLandingPage-CqZKR6EA.js → WorkbenchLandingPage-q4AAmdMV.js} +1 -1
- package/dist/public/assets/WorkbenchLayout-DD8b-m2G.js +1027 -0
- package/dist/public/assets/{WorkbenchModal-BM-OeW-b.js → WorkbenchModal-CsZeLArg.js} +1 -1
- package/dist/public/assets/WorkbenchShellRoute-BaiW_vfb.js +1 -0
- package/dist/public/assets/WorkbenchShellRoute-CxKYZ6uF.css +1 -0
- package/dist/public/assets/{WorkspaceDebugDetailPage-BMsEN5iG.js → WorkspaceDebugDetailPage-BcUUDEyw.js} +1 -1
- package/dist/public/assets/WorkspaceDetailPage-zEZ1VARA.js +1 -0
- package/dist/public/assets/{WorkspaceHomePage-DQiXKgiP.js → WorkspaceHomePage-CR0rqS4e.js} +1 -1
- package/dist/public/assets/{client-runtime-manager-CgPJq21V.js → client-runtime-manager-BgGugw8T.js} +1 -1
- package/dist/public/assets/index-CFyk1rgJ.js +50 -0
- package/dist/public/assets/index-CrU73EIV.css +1 -0
- package/dist/public/assets/{login-direct-candidate-resolver-CGaxAXV8.js → login-direct-candidate-resolver-ty2uOY5y.js} +1 -1
- package/dist/public/assets/{plugin-permission-copy-BR9gWy8b.js → plugin-permission-copy-iK3faI3n.js} +1 -1
- package/dist/public/assets/{plugins-api-CdCsrG2e.js → plugins-api-CmV7aDGA.js} +1 -1
- package/dist/public/assets/{preferences-service-lOhnlxzP.js → preferences-service-BoSmT_ny.js} +1 -1
- package/dist/public/assets/{relay-entry-CQpxTS8y.js → relay-entry-C8k5qsl5.js} +1 -1
- package/dist/public/assets/styles-BhKoKfQ_.css +1 -0
- package/dist/public/assets/{terminal-runtime-meta-oteTx66X.js → terminal-runtime-meta-okQIDzfA.js} +1 -1
- package/dist/public/assets/{useRegisteredDebugTemplates-Bu2ykZ6s.js → useRegisteredDebugTemplates-B_vXUtSe.js} +1 -1
- package/dist/public/assets/{workbench-navigation-DlgXuFW2.js → workbench-navigation-DoDaQR4z.js} +1 -1
- package/dist/public/index.html +2 -2
- package/dist/server/modules/affairs-indexer/core/src/repositories/catalog-repository.d.ts +1 -0
- package/dist/server/modules/affairs-indexer/core/src/repositories/catalog-repository.js +31 -0
- package/dist/server/modules/affairs-indexer/core/src/repositories/catalog-repository.js.map +1 -1
- package/dist/server/modules/affairs-indexer/core/src/services/dirty/dirty-scope-resolver.d.ts +1 -0
- package/dist/server/modules/affairs-indexer/core/src/services/dirty/dirty-scope-resolver.js +1 -0
- package/dist/server/modules/affairs-indexer/core/src/services/dirty/dirty-scope-resolver.js.map +1 -1
- package/dist/server/modules/affairs-indexer/core/src/services/export/export-builder.js +4 -1
- package/dist/server/modules/affairs-indexer/core/src/services/export/export-builder.js.map +1 -1
- package/dist/server/modules/affairs-indexer/core/src/services/search/search-index-builder.js +140 -16
- package/dist/server/modules/affairs-indexer/core/src/services/search/search-index-builder.js.map +1 -1
- package/dist/server/modules/assistant-capability/assistant-capability-controller.d.ts +1 -1
- package/dist/server/modules/assistant-capability/assistant-capability-controller.js +8 -7
- package/dist/server/modules/assistant-capability/assistant-capability-controller.js.map +1 -1
- package/dist/server/modules/assistant-capability/assistant-capability-service.d.ts +14 -13
- package/dist/server/modules/assistant-capability/assistant-capability-service.js +27 -24
- package/dist/server/modules/assistant-capability/assistant-capability-service.js.map +1 -1
- package/dist/server/modules/auth/auth-controller.d.ts +27 -1
- package/dist/server/modules/auth/auth-controller.js +20 -0
- package/dist/server/modules/auth/auth-controller.js.map +1 -1
- package/dist/server/modules/auth/auth-service.d.ts +32 -1
- package/dist/server/modules/auth/auth-service.js +217 -2
- package/dist/server/modules/auth/auth-service.js.map +1 -1
- package/dist/server/modules/bootstrap/bootstrap-service.js +1 -0
- package/dist/server/modules/bootstrap/bootstrap-service.js.map +1 -1
- package/dist/server/modules/butler/assistant-automation-service.d.ts +1 -1
- package/dist/server/modules/butler/assistant-automation-service.js +9 -10
- package/dist/server/modules/butler/assistant-automation-service.js.map +1 -1
- package/dist/server/modules/butler/butler-action-context-service.js +2 -2
- package/dist/server/modules/butler/butler-action-context-service.js.map +1 -1
- package/dist/server/modules/butler/butler-control-action-service.d.ts +5 -5
- package/dist/server/modules/butler/butler-control-action-service.js +19 -19
- package/dist/server/modules/butler/butler-control-action-service.js.map +1 -1
- package/dist/server/modules/butler/butler-control-session-service.d.ts +1 -1
- package/dist/server/modules/butler/butler-control-session-service.js +27 -26
- package/dist/server/modules/butler/butler-control-session-service.js.map +1 -1
- package/dist/server/modules/butler/butler-control-timer-service.js +4 -5
- package/dist/server/modules/butler/butler-control-timer-service.js.map +1 -1
- package/dist/server/modules/butler/butler-controller.d.ts +2 -2
- package/dist/server/modules/butler/butler-controller.js +19 -17
- package/dist/server/modules/butler/butler-controller.js.map +1 -1
- package/dist/server/modules/butler/butler-profile-service.d.ts +5 -5
- package/dist/server/modules/butler/butler-profile-service.js +17 -16
- package/dist/server/modules/butler/butler-profile-service.js.map +1 -1
- package/dist/server/modules/butler/butler-project-service.d.ts +7 -6
- package/dist/server/modules/butler/butler-project-service.js +35 -21
- package/dist/server/modules/butler/butler-project-service.js.map +1 -1
- package/dist/server/modules/butler/butler-session-service.d.ts +2 -2
- package/dist/server/modules/butler/butler-session-service.js +33 -27
- package/dist/server/modules/butler/butler-session-service.js.map +1 -1
- package/dist/server/modules/butler/butler-session-summary-service.d.ts +2 -2
- package/dist/server/modules/butler/butler-session-summary-service.js +23 -9
- package/dist/server/modules/butler/butler-session-summary-service.js.map +1 -1
- package/dist/server/modules/butler/context-aggregator.js +9 -9
- package/dist/server/modules/butler/context-aggregator.js.map +1 -1
- package/dist/server/modules/butler/patrol-execution-service.d.ts +0 -1
- package/dist/server/modules/butler/patrol-execution-service.js +6 -12
- package/dist/server/modules/butler/patrol-execution-service.js.map +1 -1
- package/dist/server/modules/provider/provider-discovery-runtime.js +16 -1
- package/dist/server/modules/provider/provider-discovery-runtime.js.map +1 -1
- package/dist/server/modules/sessions/codex-app-server-helper-client.js +14 -0
- package/dist/server/modules/sessions/codex-app-server-helper-client.js.map +1 -1
- package/dist/server/modules/sessions/codex-app-server-helper-process.js +59 -0
- package/dist/server/modules/sessions/codex-app-server-helper-process.js.map +1 -1
- package/dist/server/modules/sessions/codex-session-title-generator.d.ts +19 -0
- package/dist/server/modules/sessions/codex-session-title-generator.js +295 -0
- package/dist/server/modules/sessions/codex-session-title-generator.js.map +1 -0
- package/dist/server/modules/sessions/session-controller.js +3 -3
- package/dist/server/modules/sessions/session-controller.js.map +1 -1
- package/dist/server/modules/sessions/session-history-service.d.ts +13 -3
- package/dist/server/modules/sessions/session-history-service.js +309 -11
- package/dist/server/modules/sessions/session-history-service.js.map +1 -1
- package/dist/server/modules/sessions/session-live-runtime-service.js +25 -15
- package/dist/server/modules/sessions/session-live-runtime-service.js.map +1 -1
- package/dist/server/modules/sessions/session-permission-request-service.js +28 -15
- package/dist/server/modules/sessions/session-permission-request-service.js.map +1 -1
- package/dist/server/modules/tasks/task-types.d.ts +1 -0
- package/dist/server/modules/tasks/task-types.js +1 -0
- package/dist/server/modules/tasks/task-types.js.map +1 -1
- package/dist/server/modules/workbench/workbench-service.js +9 -9
- package/dist/server/modules/workbench/workbench-service.js.map +1 -1
- package/dist/server/modules/workspace/affairs-library-service.d.ts +3 -1
- package/dist/server/modules/workspace/affairs-library-service.js +112 -54
- package/dist/server/modules/workspace/affairs-library-service.js.map +1 -1
- package/dist/server/modules/workspace/affairs-lightweight-session-service.js +13 -9
- package/dist/server/modules/workspace/affairs-lightweight-session-service.js.map +1 -1
- package/dist/server/modules/workspace/affairs-tag-service.d.ts +12 -0
- package/dist/server/modules/workspace/affairs-tag-service.js +527 -2
- package/dist/server/modules/workspace/affairs-tag-service.js.map +1 -1
- package/dist/server/modules/workspace/workspace-controller.d.ts +1 -1
- package/dist/server/modules/workspace/workspace-controller.js +7 -7
- package/dist/server/modules/workspace/workspace-controller.js.map +1 -1
- package/dist/server/modules/workspace/workspace-service.d.ts +7 -0
- package/dist/server/modules/workspace/workspace-service.js +151 -10
- package/dist/server/modules/workspace/workspace-service.js.map +1 -1
- package/dist/server/routes/auth.js +6 -0
- package/dist/server/routes/auth.js.map +1 -1
- package/dist/server/server/create-server.d.ts +4 -0
- package/dist/server/server/create-server.js +26 -0
- package/dist/server/server/create-server.js.map +1 -1
- package/dist/server/server/start-host.js +20 -0
- package/dist/server/server/start-host.js.map +1 -1
- package/dist/server/shared/http/request-diagnostics.d.ts +56 -0
- package/dist/server/shared/http/request-diagnostics.js +256 -0
- package/dist/server/shared/http/request-diagnostics.js.map +1 -0
- package/dist/server/storage/repositories/auth-token-repository.d.ts +1 -0
- package/dist/server/storage/repositories/auth-token-repository.js +8 -0
- package/dist/server/storage/repositories/auth-token-repository.js.map +1 -1
- package/dist/server/storage/repositories/auth-user-repository.d.ts +50 -0
- package/dist/server/storage/repositories/auth-user-repository.js +198 -27
- package/dist/server/storage/repositories/auth-user-repository.js.map +1 -1
- package/dist/server/storage/repositories/butler-control-session-repository.d.ts +4 -1
- package/dist/server/storage/repositories/butler-control-session-repository.js +55 -8
- package/dist/server/storage/repositories/butler-control-session-repository.js.map +1 -1
- package/dist/server/storage/repositories/butler-profile-repository.d.ts +2 -1
- package/dist/server/storage/repositories/butler-profile-repository.js +35 -6
- package/dist/server/storage/repositories/butler-profile-repository.js.map +1 -1
- package/dist/server/storage/repositories/butler-project-repository.d.ts +2 -0
- package/dist/server/storage/repositories/butler-project-repository.js +38 -4
- package/dist/server/storage/repositories/butler-project-repository.js.map +1 -1
- package/dist/server/storage/repositories/butler-session-repository.d.ts +2 -1
- package/dist/server/storage/repositories/butler-session-repository.js +35 -6
- package/dist/server/storage/repositories/butler-session-repository.js.map +1 -1
- package/dist/server/storage/repositories/session-binding-repository.d.ts +3 -0
- package/dist/server/storage/repositories/session-binding-repository.js +70 -2
- package/dist/server/storage/repositories/session-binding-repository.js.map +1 -1
- package/dist/server/storage/repositories/session-index-repository.js +7 -5
- package/dist/server/storage/repositories/session-index-repository.js.map +1 -1
- package/dist/server/storage/repositories/workspace-repository.d.ts +3 -1
- package/dist/server/storage/repositories/workspace-repository.js +24 -10
- package/dist/server/storage/repositories/workspace-repository.js.map +1 -1
- package/dist/server/storage/sqlite/client.js +288 -0
- package/dist/server/storage/sqlite/client.js.map +1 -1
- package/dist/server/storage/sqlite/schema.sql +33 -9
- package/dist/server/types/domain.d.ts +8 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/claude-session-store.js +34 -7
- package/node_modules/@codingns/session-sync-core/dist/providers/claude-session-store.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/providers/codex.d.ts +7 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/codex.js +596 -6
- package/node_modules/@codingns/session-sync-core/dist/providers/codex.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/runtime/claude-runtime.js +3 -7
- 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 +1 -0
- package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js +249 -6
- package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js.map +1 -1
- package/node_modules/@codingns/session-sync-core/dist/types.d.ts +11 -0
- package/package.json +1 -1
- package/dist/public/assets/SessionIndexPage-CX2FppcJ.js +0 -1
- package/dist/public/assets/SettingsPage-BI2Olcvr.js +0 -2
- package/dist/public/assets/WorkbenchLayout-CJHQtwuL.js +0 -1022
- package/dist/public/assets/WorkbenchShellRoute-2bKI6Q9k.js +0 -1
- package/dist/public/assets/WorkbenchShellRoute-BjuZD101.css +0 -1
- package/dist/public/assets/WorkspaceDetailPage-5H9Gosx2.js +0 -1
- package/dist/public/assets/index-BARqMVSw.css +0 -1
- package/dist/public/assets/index-BUoNjVrY.js +0 -50
- package/dist/public/assets/styles-DkbkRgWw.css +0 -1
- /package/dist/public/assets/{styles-JKFlsYFv.js → styles-DwSuZo1w.js} +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
1
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
2
3
|
import { CapabilityService, ClaudeCodeAdapter, CodexAdapter, GeminiAdapter, KimiAdapter, LegnaCodeAdapter, OpenCodeAdapter, ProviderRegistry, SessionSyncService } from "@codingns/session-sync-core";
|
|
3
4
|
import { AppError } from "../../shared/errors/app-error.js";
|
|
4
5
|
import { hashContent } from "../../shared/utils/hash.js";
|
|
@@ -21,6 +22,7 @@ import { ProviderRuntimeStateService } from "../provider/provider-runtime-state-
|
|
|
21
22
|
import { createTaskManager } from "../tasks/task-manager.js";
|
|
22
23
|
import { HOST_TASK_TYPES } from "../tasks/task-types.js";
|
|
23
24
|
import { CodexAppServerHelperClient } from "./codex-app-server-helper-client.js";
|
|
25
|
+
import { CodexSessionTitleGenerator } from "./codex-session-title-generator.js";
|
|
24
26
|
import { CodingnsProviderSessionDeleteCli } from "./provider-session-delete-cli.js";
|
|
25
27
|
const RECONSTRUCTED_FORK_TARGET_PROVIDERS = new Set(["codex", "claude-code", "opencode"]);
|
|
26
28
|
const FORK_RECONSTRUCTION_PAGE_SIZE = 200;
|
|
@@ -79,6 +81,7 @@ export class SessionHistoryService {
|
|
|
79
81
|
providerDiscoveryHelperClient = getSharedProviderDiscoveryHelperClient();
|
|
80
82
|
providerSessionDiscoveryConfig;
|
|
81
83
|
providerRuntimeStateService;
|
|
84
|
+
codexSessionTitleGenerator;
|
|
82
85
|
sessionProviderConfigService;
|
|
83
86
|
providerControlRepository;
|
|
84
87
|
taskManager;
|
|
@@ -112,6 +115,10 @@ export class SessionHistoryService {
|
|
|
112
115
|
this.sessionProviderConfigService = sessionProviderConfigService;
|
|
113
116
|
this.providerRuntimeStateService = providerRuntimeStateService
|
|
114
117
|
?? new ProviderRuntimeStateService(config);
|
|
118
|
+
this.codexSessionTitleGenerator = new CodexSessionTitleGenerator({
|
|
119
|
+
hostDataRootDir: dirname(config.databasePath),
|
|
120
|
+
codexHomeDir: config.codexHomeDir
|
|
121
|
+
});
|
|
115
122
|
this.providerControlRepository = providerControlRepository ?? {
|
|
116
123
|
get: (providerId) => ({
|
|
117
124
|
providerId: providerId.trim(),
|
|
@@ -227,6 +234,14 @@ export class SessionHistoryService {
|
|
|
227
234
|
}
|
|
228
235
|
});
|
|
229
236
|
}
|
|
237
|
+
if (!this.taskManager.has(HOST_TASK_TYPES.sessionCodexTitleGenerate)) {
|
|
238
|
+
this.taskManager.register({
|
|
239
|
+
taskType: HOST_TASK_TYPES.sessionCodexTitleGenerate,
|
|
240
|
+
executionLane: "external_process",
|
|
241
|
+
timeoutMs: 45_000,
|
|
242
|
+
run: async ({ sessionId }, context) => this.runCodexSessionTitleGeneration(sessionId, context.signal)
|
|
243
|
+
});
|
|
244
|
+
}
|
|
230
245
|
}
|
|
231
246
|
async discoverWorkspaceSessions(workspaceId, userId, options) {
|
|
232
247
|
const maxAgeMs = options?.maxAgeMs ?? 0;
|
|
@@ -314,6 +329,7 @@ export class SessionHistoryService {
|
|
|
314
329
|
binding = await this.repairCodexDirtyBindingBeforeHistoryRead(resolvedSessionId, userId, binding);
|
|
315
330
|
repairBindingMs = Date.now() - repairStartedAt;
|
|
316
331
|
}
|
|
332
|
+
binding = this.repairClaudeEmptyBindingBeforeHistoryRead(resolvedSessionId, binding);
|
|
317
333
|
const current = this.sessionStatusSnapshotRepository.findBySessionId(resolvedSessionId);
|
|
318
334
|
const safeLimit = clampLimit(limit);
|
|
319
335
|
const knownTotalLookupStartedAt = Date.now();
|
|
@@ -445,6 +461,7 @@ export class SessionHistoryService {
|
|
|
445
461
|
async syncSessionTitle(sessionId, signal) {
|
|
446
462
|
const binding = this.getBindingOrThrow(sessionId);
|
|
447
463
|
await this.syncSessionTitleFromProvider(sessionId, binding, signal);
|
|
464
|
+
this.requestCodexTitleGenerationIfNeeded(sessionId, "session_history.sync_session_title");
|
|
448
465
|
}
|
|
449
466
|
async syncWorkspaceSessionTitles(workspaceId, userId, concurrency = 1, signal) {
|
|
450
467
|
const sessions = this.sessionIndexRepository.listByWorkspace(workspaceId, userId);
|
|
@@ -495,8 +512,8 @@ export class SessionHistoryService {
|
|
|
495
512
|
throw mapSessionProviderError(error);
|
|
496
513
|
}
|
|
497
514
|
}
|
|
498
|
-
async getSessionCapabilities(sessionId) {
|
|
499
|
-
const binding = this.
|
|
515
|
+
async getSessionCapabilities(sessionId, userId) {
|
|
516
|
+
const binding = this.getBindingForUserOrThrow(sessionId, userId);
|
|
500
517
|
const workspace = this.getWorkspaceOrThrow(binding.workspaceId);
|
|
501
518
|
const workspacePath = workspace.path;
|
|
502
519
|
return this.capabilityService
|
|
@@ -632,8 +649,8 @@ export class SessionHistoryService {
|
|
|
632
649
|
throw mapSessionProviderError(error);
|
|
633
650
|
}
|
|
634
651
|
}
|
|
635
|
-
async resumeSession(sessionId) {
|
|
636
|
-
const binding = this.
|
|
652
|
+
async resumeSession(sessionId, userId) {
|
|
653
|
+
const binding = this.getBindingForUserOrThrow(sessionId, userId);
|
|
637
654
|
this.assertProviderCapabilityEnabled(binding.provider, "canResumeSession", "当前 provider 不支持继续会话");
|
|
638
655
|
try {
|
|
639
656
|
const result = await this.sessionSyncService.resumeSession(binding.provider, binding.providerSessionId, binding.rawStoreRef);
|
|
@@ -670,7 +687,7 @@ export class SessionHistoryService {
|
|
|
670
687
|
return this.startSessionDirect(input);
|
|
671
688
|
}
|
|
672
689
|
async startSessionDirect(input) {
|
|
673
|
-
const workspace = this.
|
|
690
|
+
const workspace = this.getWorkspaceForUserOrThrow(input.workspaceId, input.userId);
|
|
674
691
|
this.assertProviderCapabilityEnabled(input.provider, "canStartSession", "当前 provider 不支持创建会话");
|
|
675
692
|
const sessionId = createId();
|
|
676
693
|
const providerBinding = this.prepareDirectSessionBinding({
|
|
@@ -687,6 +704,7 @@ export class SessionHistoryService {
|
|
|
687
704
|
const persist = this.db.transaction(() => {
|
|
688
705
|
this.sessionBindingRepository.upsert({
|
|
689
706
|
sessionId,
|
|
707
|
+
userId: input.userId,
|
|
690
708
|
workspaceId: workspace.id,
|
|
691
709
|
provider: result.session.provider,
|
|
692
710
|
providerSessionId: result.session.providerSessionId,
|
|
@@ -745,9 +763,9 @@ export class SessionHistoryService {
|
|
|
745
763
|
}
|
|
746
764
|
}
|
|
747
765
|
async forkSession(input) {
|
|
748
|
-
const binding = this.
|
|
766
|
+
const binding = this.getBindingForUserOrThrow(input.sessionId, input.userId);
|
|
749
767
|
const targetWorkspaceId = input.targetWorkspaceId?.trim() || binding.workspaceId;
|
|
750
|
-
const workspace = this.
|
|
768
|
+
const workspace = this.getWorkspaceForUserOrThrow(targetWorkspaceId, input.userId);
|
|
751
769
|
const targetProvider = input.targetProvider?.trim() || binding.provider;
|
|
752
770
|
this.assertProviderCapabilityEnabled(targetProvider, "canStartSession", "当前 provider 不支持 fork 创建会话");
|
|
753
771
|
const sourceMessageId = input.sourceType === "message"
|
|
@@ -789,6 +807,7 @@ export class SessionHistoryService {
|
|
|
789
807
|
this.db.transaction(() => {
|
|
790
808
|
this.sessionBindingRepository.upsert({
|
|
791
809
|
sessionId,
|
|
810
|
+
userId: input.userId,
|
|
792
811
|
workspaceId: workspace.id,
|
|
793
812
|
provider: result.session.provider,
|
|
794
813
|
providerSessionId: result.session.providerSessionId,
|
|
@@ -1037,8 +1056,8 @@ export class SessionHistoryService {
|
|
|
1037
1056
|
}
|
|
1038
1057
|
return depth;
|
|
1039
1058
|
}
|
|
1040
|
-
async sendMessage(sessionId, content, clientRequestId, permissionMode = null) {
|
|
1041
|
-
const binding = this.
|
|
1059
|
+
async sendMessage(sessionId, userId, content, clientRequestId, permissionMode = null) {
|
|
1060
|
+
const binding = this.getBindingForUserOrThrow(sessionId, userId);
|
|
1042
1061
|
this.assertProviderSendEnabled(binding.provider, "sessionId", "当前 provider 不支持继续发送消息");
|
|
1043
1062
|
const result = await this.sessionSyncService
|
|
1044
1063
|
.sendMessage(binding.provider, binding.providerSessionId, binding.rawStoreRef, content, clientRequestId, permissionMode)
|
|
@@ -1148,6 +1167,7 @@ export class SessionHistoryService {
|
|
|
1148
1167
|
return null;
|
|
1149
1168
|
}
|
|
1150
1169
|
await this.syncSessionTitleFromProvider(sessionId, binding);
|
|
1170
|
+
this.requestCodexTitleGenerationIfNeeded(sessionId, "session_history.read_recent_history");
|
|
1151
1171
|
const snapshot = this.sessionStatusSnapshotRepository.findBySessionId(sessionId);
|
|
1152
1172
|
this.upsertSnapshot(sessionId, {
|
|
1153
1173
|
syncStatus: "idle",
|
|
@@ -1235,6 +1255,7 @@ export class SessionHistoryService {
|
|
|
1235
1255
|
});
|
|
1236
1256
|
this.sessionBindingRepository.upsert({
|
|
1237
1257
|
...binding,
|
|
1258
|
+
userId: input.userId,
|
|
1238
1259
|
rawStoreRef: result.rawStoreRef,
|
|
1239
1260
|
updatedAt: timestamp
|
|
1240
1261
|
});
|
|
@@ -1365,6 +1386,10 @@ export class SessionHistoryService {
|
|
|
1365
1386
|
const currentIndex = this.sessionIndexRepository.findIndexRecordBySessionId(sessionId);
|
|
1366
1387
|
this.sessionBindingRepository.upsert({
|
|
1367
1388
|
sessionId,
|
|
1389
|
+
userId: snapshot.userId
|
|
1390
|
+
?? currentBinding?.userId
|
|
1391
|
+
?? duplicateBinding?.userId
|
|
1392
|
+
?? this.resolveWorkspaceOwnerUserId(workspaceId),
|
|
1368
1393
|
workspaceId,
|
|
1369
1394
|
provider: resolvedSnapshot.provider,
|
|
1370
1395
|
providerSessionId: resolvedSnapshot.providerSessionId,
|
|
@@ -1402,7 +1427,7 @@ export class SessionHistoryService {
|
|
|
1402
1427
|
async runDiscoverWorkspaceSessions(workspaceId, userId, refreshStateMode = "inline", signal) {
|
|
1403
1428
|
const startedAt = Date.now();
|
|
1404
1429
|
const debugStartedAtMs = terminalDebugNowMs();
|
|
1405
|
-
const workspace = this.
|
|
1430
|
+
const workspace = this.getWorkspaceForUserOrThrow(workspaceId, userId);
|
|
1406
1431
|
let discoverDurationMs = 0;
|
|
1407
1432
|
let persistDurationMs = 0;
|
|
1408
1433
|
let persistPass1DurationMs = 0;
|
|
@@ -1470,6 +1495,7 @@ export class SessionHistoryService {
|
|
|
1470
1495
|
: null;
|
|
1471
1496
|
const nextBinding = {
|
|
1472
1497
|
sessionId,
|
|
1498
|
+
userId,
|
|
1473
1499
|
workspaceId: workspace.id,
|
|
1474
1500
|
provider: session.provider,
|
|
1475
1501
|
providerSessionId: session.providerSessionId,
|
|
@@ -1614,6 +1640,10 @@ export class SessionHistoryService {
|
|
|
1614
1640
|
cleanupDurationMs = Date.now() - cleanupStartedAt;
|
|
1615
1641
|
}
|
|
1616
1642
|
this.workspaceSessionRelations.set(workspaceId, relationMap);
|
|
1643
|
+
this.observeDiscoveredProviderActivity(sessions, discoveredSessionIds, userId, timestamp);
|
|
1644
|
+
for (const persisted of persistedSessions) {
|
|
1645
|
+
this.requestCodexTitleGenerationIfNeeded(persisted.sessionId, "session_history.discover_workspace_sessions.codex_title");
|
|
1646
|
+
}
|
|
1617
1647
|
const listItemsStartedAt = Date.now();
|
|
1618
1648
|
const items = this.sessionIndexRepository.listByWorkspace(workspaceId, userId);
|
|
1619
1649
|
listItemsDurationMs = Date.now() - listItemsStartedAt;
|
|
@@ -1901,6 +1931,72 @@ export class SessionHistoryService {
|
|
|
1901
1931
|
}
|
|
1902
1932
|
return relationMap;
|
|
1903
1933
|
}
|
|
1934
|
+
observeDiscoveredProviderActivity(sessions, discoveredSessionIds, userId, timestamp) {
|
|
1935
|
+
for (const session of sessions) {
|
|
1936
|
+
const providerObservation = session.activityObservation ?? null;
|
|
1937
|
+
if (!providerObservation) {
|
|
1938
|
+
continue;
|
|
1939
|
+
}
|
|
1940
|
+
const sessionId = discoveredSessionIds.get(buildProviderSessionKey(session.provider, session.providerSessionId));
|
|
1941
|
+
if (!sessionId) {
|
|
1942
|
+
continue;
|
|
1943
|
+
}
|
|
1944
|
+
const observedAt = providerObservation.observedAt ?? timestamp;
|
|
1945
|
+
const resolution = this.sessionActivityAuthorityService.observe({
|
|
1946
|
+
sessionId,
|
|
1947
|
+
runId: providerObservation.runId ?? null,
|
|
1948
|
+
runningState: providerObservation.runningState,
|
|
1949
|
+
source: "authoritative_provider_event",
|
|
1950
|
+
confidence: providerObservation.confidence,
|
|
1951
|
+
detail: providerObservation.detail ?? null,
|
|
1952
|
+
interruptSource: providerObservation.runningState === "interrupted" ? "runtime" : null,
|
|
1953
|
+
errorCode: providerObservation.errorCode ?? null,
|
|
1954
|
+
observedAt
|
|
1955
|
+
});
|
|
1956
|
+
const current = this.sessionStateRepository.findBySessionAndUser(sessionId, userId);
|
|
1957
|
+
this.sessionStateRepository.upsert({
|
|
1958
|
+
sessionId,
|
|
1959
|
+
userId,
|
|
1960
|
+
runningState: mapResolvedRunningStateToStored(resolution.runningState, current),
|
|
1961
|
+
activitySource: "runtime",
|
|
1962
|
+
favorite: current?.favorite ?? false,
|
|
1963
|
+
lastEventAt: resolution.lastObservedAt ?? current?.lastEventAt ?? null,
|
|
1964
|
+
completedAt: isTerminalResolvedRunningState(resolution.runningState)
|
|
1965
|
+
? resolution.terminalAt ?? current?.completedAt ?? observedAt
|
|
1966
|
+
: null,
|
|
1967
|
+
lastSeenAt: current?.lastSeenAt ?? null,
|
|
1968
|
+
updatedAt: timestamp
|
|
1969
|
+
});
|
|
1970
|
+
const currentSnapshot = this.sessionStatusSnapshotRepository.findBySessionId(sessionId);
|
|
1971
|
+
const shouldClearFailure = currentSnapshot?.syncStatus === "error"
|
|
1972
|
+
&& providerObservation.runningState !== "failed";
|
|
1973
|
+
this.sessionStatusSnapshotRepository.upsert({
|
|
1974
|
+
sessionId,
|
|
1975
|
+
syncStatus: providerObservation.runningState === "failed"
|
|
1976
|
+
? "error"
|
|
1977
|
+
: shouldClearFailure
|
|
1978
|
+
? "idle"
|
|
1979
|
+
: currentSnapshot?.syncStatus ?? "idle",
|
|
1980
|
+
syncCursor: currentSnapshot?.syncCursor ?? null,
|
|
1981
|
+
lastSyncAt: resolution.lastObservedAt
|
|
1982
|
+
?? resolution.terminalAt
|
|
1983
|
+
?? currentSnapshot?.lastSyncAt
|
|
1984
|
+
?? null,
|
|
1985
|
+
lastErrorCode: providerObservation.runningState === "failed"
|
|
1986
|
+
? providerObservation.errorCode ?? "CODEX_PROVIDER_EVENT_FAILED"
|
|
1987
|
+
: shouldClearFailure
|
|
1988
|
+
? null
|
|
1989
|
+
: currentSnapshot?.lastErrorCode ?? null,
|
|
1990
|
+
lastErrorDetail: providerObservation.runningState === "failed"
|
|
1991
|
+
? providerObservation.detail ?? "Provider reported session failure"
|
|
1992
|
+
: shouldClearFailure
|
|
1993
|
+
? null
|
|
1994
|
+
: currentSnapshot?.lastErrorDetail ?? null,
|
|
1995
|
+
resumedAt: currentSnapshot?.resumedAt ?? null,
|
|
1996
|
+
updatedAt: timestamp
|
|
1997
|
+
});
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
1904
2000
|
enrichSessionItems(workspaceId, items) {
|
|
1905
2001
|
const relationMap = this.workspaceSessionRelations.get(workspaceId);
|
|
1906
2002
|
const projectionBySessionId = this.buildParallelProjectionBySessionId(items);
|
|
@@ -2125,6 +2221,7 @@ export class SessionHistoryService {
|
|
|
2125
2221
|
return;
|
|
2126
2222
|
}
|
|
2127
2223
|
await this.syncSessionTitleFromProvider(sessionId, binding);
|
|
2224
|
+
this.requestCodexTitleGenerationIfNeeded(sessionId, "session_history.publish_history_envelope");
|
|
2128
2225
|
const snapshot = this.sessionStatusSnapshotRepository.findBySessionId(sessionId);
|
|
2129
2226
|
this.upsertSnapshot(sessionId, {
|
|
2130
2227
|
syncStatus: "idle",
|
|
@@ -2177,6 +2274,83 @@ export class SessionHistoryService {
|
|
|
2177
2274
|
updatedAt: nowIso()
|
|
2178
2275
|
});
|
|
2179
2276
|
}
|
|
2277
|
+
requestCodexTitleGenerationIfNeeded(sessionId, source) {
|
|
2278
|
+
if (!this.shouldRequestCodexTitleGeneration(sessionId)) {
|
|
2279
|
+
return;
|
|
2280
|
+
}
|
|
2281
|
+
const handle = this.taskManager.enqueue(HOST_TASK_TYPES.sessionCodexTitleGenerate, {
|
|
2282
|
+
key: sessionId,
|
|
2283
|
+
source,
|
|
2284
|
+
input: {
|
|
2285
|
+
sessionId
|
|
2286
|
+
}
|
|
2287
|
+
});
|
|
2288
|
+
if (handle.deduped) {
|
|
2289
|
+
return;
|
|
2290
|
+
}
|
|
2291
|
+
void handle.promise.catch((error) => {
|
|
2292
|
+
logPerformance("session.codex_title_generate.background_failed", 0, {
|
|
2293
|
+
sessionId,
|
|
2294
|
+
error: error instanceof Error ? error.message : "unknown"
|
|
2295
|
+
}, {
|
|
2296
|
+
thresholdMs: 0,
|
|
2297
|
+
force: true
|
|
2298
|
+
});
|
|
2299
|
+
});
|
|
2300
|
+
}
|
|
2301
|
+
shouldRequestCodexTitleGeneration(sessionId) {
|
|
2302
|
+
const binding = this.sessionBindingRepository.findBySessionId(sessionId);
|
|
2303
|
+
const index = this.sessionIndexRepository.findIndexRecordBySessionId(sessionId);
|
|
2304
|
+
if (!binding || !index || binding.provider !== "codex") {
|
|
2305
|
+
return false;
|
|
2306
|
+
}
|
|
2307
|
+
if (isPendingBindingValue(binding.providerSessionId) || isPendingBindingValue(binding.rawStoreRef)) {
|
|
2308
|
+
return false;
|
|
2309
|
+
}
|
|
2310
|
+
if (index.messageCount <= 0) {
|
|
2311
|
+
return false;
|
|
2312
|
+
}
|
|
2313
|
+
return true;
|
|
2314
|
+
}
|
|
2315
|
+
async runCodexSessionTitleGeneration(sessionId, signal) {
|
|
2316
|
+
const binding = this.sessionBindingRepository.findBySessionId(sessionId);
|
|
2317
|
+
const index = this.sessionIndexRepository.findIndexRecordBySessionId(sessionId);
|
|
2318
|
+
if (!binding || !index || binding.provider !== "codex") {
|
|
2319
|
+
return { title: null };
|
|
2320
|
+
}
|
|
2321
|
+
if (isPendingBindingValue(binding.providerSessionId) || isPendingBindingValue(binding.rawStoreRef)) {
|
|
2322
|
+
return { title: null };
|
|
2323
|
+
}
|
|
2324
|
+
const page = await this.sessionSyncService.readHistory(binding.provider, binding.providerSessionId, binding.rawStoreRef, null, 16, "forward").catch(() => null);
|
|
2325
|
+
if (!page) {
|
|
2326
|
+
return { title: null };
|
|
2327
|
+
}
|
|
2328
|
+
const firstUserMessage = page.messages.find((message) => message.role === "user")?.content ?? null;
|
|
2329
|
+
if (!shouldGenerateCodexSessionTitle(index.title, firstUserMessage)) {
|
|
2330
|
+
return { title: null };
|
|
2331
|
+
}
|
|
2332
|
+
const title = await this.codexSessionTitleGenerator.generate({
|
|
2333
|
+
currentTitle: index.title,
|
|
2334
|
+
messages: page.messages.map((message) => ({
|
|
2335
|
+
role: message.role,
|
|
2336
|
+
content: message.content
|
|
2337
|
+
})),
|
|
2338
|
+
signal
|
|
2339
|
+
});
|
|
2340
|
+
if (!title || !shouldApplyGeneratedCodexSessionTitle(title, firstUserMessage)) {
|
|
2341
|
+
return { title: null };
|
|
2342
|
+
}
|
|
2343
|
+
await this.sessionSyncService.renameSessionTitle(binding.provider, binding.providerSessionId, binding.rawStoreRef, title);
|
|
2344
|
+
const latestIndex = this.sessionIndexRepository.findIndexRecordBySessionId(sessionId);
|
|
2345
|
+
if (latestIndex && shouldGenerateCodexSessionTitle(latestIndex.title, firstUserMessage)) {
|
|
2346
|
+
this.sessionIndexRepository.upsert({
|
|
2347
|
+
...latestIndex,
|
|
2348
|
+
title,
|
|
2349
|
+
updatedAt: nowIso()
|
|
2350
|
+
});
|
|
2351
|
+
}
|
|
2352
|
+
return { title };
|
|
2353
|
+
}
|
|
2180
2354
|
async readFirstUserMessageTitleForSync(binding) {
|
|
2181
2355
|
const pageSize = 20;
|
|
2182
2356
|
const maxPages = 3;
|
|
@@ -2241,6 +2415,31 @@ export class SessionHistoryService {
|
|
|
2241
2415
|
}
|
|
2242
2416
|
return workspace;
|
|
2243
2417
|
}
|
|
2418
|
+
getWorkspaceForUserOrThrow(workspaceId, userId) {
|
|
2419
|
+
const workspace = this.getWorkspaceOrThrow(workspaceId);
|
|
2420
|
+
if (workspace.ownerUserId !== userId) {
|
|
2421
|
+
throw new AppError({
|
|
2422
|
+
statusCode: 404,
|
|
2423
|
+
errorCode: "WORKSPACE_NOT_FOUND",
|
|
2424
|
+
detail: "工作区不存在"
|
|
2425
|
+
});
|
|
2426
|
+
}
|
|
2427
|
+
return workspace;
|
|
2428
|
+
}
|
|
2429
|
+
getBindingForUserOrThrow(sessionId, userId) {
|
|
2430
|
+
const binding = this.sessionBindingRepository.findBySessionIdForUser(sessionId, userId);
|
|
2431
|
+
if (!binding) {
|
|
2432
|
+
throw new AppError({
|
|
2433
|
+
statusCode: 404,
|
|
2434
|
+
errorCode: "SESSION_NOT_FOUND",
|
|
2435
|
+
detail: "session 不存在"
|
|
2436
|
+
});
|
|
2437
|
+
}
|
|
2438
|
+
return this.resolvePendingSessionAliasBinding(binding) ?? binding;
|
|
2439
|
+
}
|
|
2440
|
+
resolveWorkspaceOwnerUserId(workspaceId) {
|
|
2441
|
+
return this.workspaceRepository.findById(workspaceId)?.ownerUserId ?? null;
|
|
2442
|
+
}
|
|
2244
2443
|
getSessionListItemOrThrow(sessionId, userId) {
|
|
2245
2444
|
const canonicalSessionId = this.resolveCanonicalSessionId(sessionId, userId);
|
|
2246
2445
|
const item = this.findSessionListItem(canonicalSessionId, sessionId, userId)
|
|
@@ -2614,6 +2813,7 @@ export class SessionHistoryService {
|
|
|
2614
2813
|
if (!targetBinding) {
|
|
2615
2814
|
this.sessionBindingRepository.upsert({
|
|
2616
2815
|
sessionId: input.targetSessionId,
|
|
2816
|
+
userId: sourceBinding.userId ?? this.resolveWorkspaceOwnerUserId(input.workspaceId),
|
|
2617
2817
|
workspaceId: input.workspaceId,
|
|
2618
2818
|
provider: input.provider,
|
|
2619
2819
|
providerSessionId: buildPendingBindingValue(input.provider, input.targetSessionId),
|
|
@@ -2698,6 +2898,7 @@ export class SessionHistoryService {
|
|
|
2698
2898
|
// 保留旧 session_id 作为 alias,避免前端或 Butler 还拿着旧 id 时直接炸成 SESSION_NOT_FOUND。
|
|
2699
2899
|
this.sessionBindingRepository.upsert({
|
|
2700
2900
|
sessionId: input.sourceSessionId,
|
|
2901
|
+
userId: sourceBinding.userId ?? this.resolveWorkspaceOwnerUserId(sourceBinding.workspaceId),
|
|
2701
2902
|
workspaceId: sourceBinding.workspaceId,
|
|
2702
2903
|
provider: sourceBinding.provider,
|
|
2703
2904
|
providerSessionId: buildAliasBindingValue(input.provider, input.targetSessionId, input.sourceSessionId),
|
|
@@ -3101,6 +3302,21 @@ export class SessionHistoryService {
|
|
|
3101
3302
|
this.codexDirtyBindingRepairStates.set(sessionId, currentState);
|
|
3102
3303
|
});
|
|
3103
3304
|
}
|
|
3305
|
+
repairClaudeEmptyBindingBeforeHistoryRead(sessionId, binding) {
|
|
3306
|
+
if (!shouldRepairClaudeEmptyHistoryBinding(binding)) {
|
|
3307
|
+
return binding;
|
|
3308
|
+
}
|
|
3309
|
+
const repairedRawStoreRef = findBestClaudeHistoryFileNearBinding(binding);
|
|
3310
|
+
if (!repairedRawStoreRef || repairedRawStoreRef === binding.rawStoreRef) {
|
|
3311
|
+
return binding;
|
|
3312
|
+
}
|
|
3313
|
+
this.persistSessionBinding(sessionId, binding.workspaceId, {
|
|
3314
|
+
provider: binding.provider,
|
|
3315
|
+
providerSessionId: binding.providerSessionId,
|
|
3316
|
+
rawStoreRef: repairedRawStoreRef
|
|
3317
|
+
});
|
|
3318
|
+
return this.getBindingOrThrow(sessionId);
|
|
3319
|
+
}
|
|
3104
3320
|
resolveLiveActivityObservation(sessionId) {
|
|
3105
3321
|
for (const resolver of this.liveActivityObservationResolvers) {
|
|
3106
3322
|
const observation = resolver(sessionId);
|
|
@@ -3596,6 +3812,69 @@ function shouldSkipClaudePendingBinding(binding) {
|
|
|
3596
3812
|
function isPendingBindingValue(value) {
|
|
3597
3813
|
return value.trim().toLowerCase().startsWith("pending://");
|
|
3598
3814
|
}
|
|
3815
|
+
function shouldRepairClaudeEmptyHistoryBinding(binding) {
|
|
3816
|
+
if (binding.provider !== "claude-code") {
|
|
3817
|
+
return false;
|
|
3818
|
+
}
|
|
3819
|
+
if (isPendingBindingValue(binding.providerSessionId) || isPendingBindingValue(binding.rawStoreRef)) {
|
|
3820
|
+
return false;
|
|
3821
|
+
}
|
|
3822
|
+
const currentStats = safeStat(binding.rawStoreRef);
|
|
3823
|
+
return !currentStats || currentStats.size === 0;
|
|
3824
|
+
}
|
|
3825
|
+
function findBestClaudeHistoryFileNearBinding(binding) {
|
|
3826
|
+
const providerSessionId = binding.providerSessionId.trim();
|
|
3827
|
+
if (!providerSessionId || isPendingBindingValue(providerSessionId)) {
|
|
3828
|
+
return null;
|
|
3829
|
+
}
|
|
3830
|
+
const candidates = new Set();
|
|
3831
|
+
for (const projectsRoot of collectClaudeProjectsRootsNearBinding(binding)) {
|
|
3832
|
+
for (const candidate of listClaudeSessionCandidates(projectsRoot, providerSessionId)) {
|
|
3833
|
+
candidates.add(candidate);
|
|
3834
|
+
}
|
|
3835
|
+
}
|
|
3836
|
+
const nonEmptyCandidates = Array.from(candidates)
|
|
3837
|
+
.map((filePath) => ({
|
|
3838
|
+
filePath,
|
|
3839
|
+
stats: safeStat(filePath)
|
|
3840
|
+
}))
|
|
3841
|
+
.filter((candidate) => Boolean(candidate.stats && candidate.stats.size > 0))
|
|
3842
|
+
.sort((left, right) => {
|
|
3843
|
+
if (right.stats.size !== left.stats.size) {
|
|
3844
|
+
return right.stats.size - left.stats.size;
|
|
3845
|
+
}
|
|
3846
|
+
return right.stats.mtimeMs - left.stats.mtimeMs;
|
|
3847
|
+
});
|
|
3848
|
+
return nonEmptyCandidates[0]?.filePath ?? null;
|
|
3849
|
+
}
|
|
3850
|
+
function collectClaudeProjectsRootsNearBinding(binding) {
|
|
3851
|
+
const roots = new Set();
|
|
3852
|
+
const rawStoreRef = binding.rawStoreRef.trim();
|
|
3853
|
+
if (rawStoreRef && !isPendingBindingValue(rawStoreRef)) {
|
|
3854
|
+
// rawStoreRef 通常是 <home>/projects/<workspace-slug>/<session>.jsonl。
|
|
3855
|
+
// 即使 <workspace-slug> 算错了,向上两级仍然能拿到正确的 projects 根。
|
|
3856
|
+
roots.add(dirname(dirname(rawStoreRef)));
|
|
3857
|
+
}
|
|
3858
|
+
const runtimeHomeDir = binding.runtimeHomeDir?.trim() ?? "";
|
|
3859
|
+
if (runtimeHomeDir) {
|
|
3860
|
+
roots.add(join(runtimeHomeDir, "projects"));
|
|
3861
|
+
}
|
|
3862
|
+
return Array.from(roots);
|
|
3863
|
+
}
|
|
3864
|
+
function listClaudeSessionCandidates(projectsRoot, providerSessionId) {
|
|
3865
|
+
if (!projectsRoot || !existsSync(projectsRoot)) {
|
|
3866
|
+
return [];
|
|
3867
|
+
}
|
|
3868
|
+
try {
|
|
3869
|
+
return readdirSync(projectsRoot, { withFileTypes: true })
|
|
3870
|
+
.filter((entry) => entry.isDirectory())
|
|
3871
|
+
.map((entry) => join(projectsRoot, entry.name, `${providerSessionId}.jsonl`))
|
|
3872
|
+
.filter((filePath) => existsSync(filePath));
|
|
3873
|
+
}
|
|
3874
|
+
catch {
|
|
3875
|
+
return [];
|
|
3876
|
+
}
|
|
3877
|
+
}
|
|
3599
3878
|
function isSessionBindingProviderUniqueConflict(error) {
|
|
3600
3879
|
if (!(error instanceof Error)) {
|
|
3601
3880
|
return false;
|
|
@@ -4080,6 +4359,25 @@ function shouldSyncSessionTitleFromProvider(provider, currentTitle, firstUserMes
|
|
|
4080
4359
|
}
|
|
4081
4360
|
return false;
|
|
4082
4361
|
}
|
|
4362
|
+
function shouldGenerateCodexSessionTitle(currentTitle, firstUserMessage) {
|
|
4363
|
+
const normalizedTitle = currentTitle?.trim() ?? "";
|
|
4364
|
+
if (!normalizedTitle) {
|
|
4365
|
+
return true;
|
|
4366
|
+
}
|
|
4367
|
+
if (looksLikeGeneratedSessionTitle(normalizedTitle) || isSyntheticCodexSessionTitle(normalizedTitle)) {
|
|
4368
|
+
return true;
|
|
4369
|
+
}
|
|
4370
|
+
const firstUserTitle = normalizeRuntimePromptTitle(firstUserMessage);
|
|
4371
|
+
return Boolean(firstUserTitle && normalizedTitle === firstUserTitle);
|
|
4372
|
+
}
|
|
4373
|
+
function shouldApplyGeneratedCodexSessionTitle(generatedTitle, firstUserMessage) {
|
|
4374
|
+
const normalizedTitle = generatedTitle.trim();
|
|
4375
|
+
const firstUserTitle = normalizeRuntimePromptTitle(firstUserMessage);
|
|
4376
|
+
if (!normalizedTitle) {
|
|
4377
|
+
return false;
|
|
4378
|
+
}
|
|
4379
|
+
return !firstUserTitle || normalizedTitle !== firstUserTitle;
|
|
4380
|
+
}
|
|
4083
4381
|
function looksLikeSyntheticTitleSourceMessage(provider, content) {
|
|
4084
4382
|
const normalizedProvider = provider.trim().toLowerCase();
|
|
4085
4383
|
if (normalizedProvider === "codex") {
|