@jingyi0605/codingns 0.9.8 → 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/codingns.mjs +14 -0
- package/dist/public/assets/{AdaptiveButlerPage-D-gXre7Y.js → AdaptiveButlerPage-BYETYaIe.js} +2 -2
- package/dist/public/assets/App-CHsm-VrM.js +30 -0
- package/dist/public/assets/App-Z0Zd7gXR.css +1 -0
- package/dist/public/assets/{BootstrapPage-B-yMdfpQ.js → BootstrapPage-Bp0KfySv.js} +1 -1
- package/dist/public/assets/ConversationPage-BCrNml1k.js +9 -0
- package/dist/public/assets/{DesktopDetachPreviewPage-D1DMaGcy.js → DesktopDetachPreviewPage-DlDSb_tf.js} +1 -1
- package/dist/public/assets/{DesktopModal-BnfGW2gk.js → DesktopModal-Csj5AdAN.js} +1 -1
- package/dist/public/assets/DesktopWindowPage-CacXiWjV.js +2 -0
- package/dist/public/assets/FileContextPanel-DzMUQvE5.js +1 -0
- package/dist/public/assets/GitSidebar-C8IC18GH.js +6 -0
- package/dist/public/assets/MobileCreateSessionSheet-BtqR_hKc.js +1 -0
- package/dist/public/assets/{MobileSheet-rkn_CUOY.js → MobileSheet-Co-qPMBD.js} +1 -1
- package/dist/public/assets/PluginAccessOverview-D-KXkcyj.js +1 -0
- package/dist/public/assets/{PluginContainerPage-D-ly3i3H.js → PluginContainerPage-BKwCIs4r.js} +1 -1
- package/dist/public/assets/{PluginDetailPage-CWAHYyyG.js → PluginDetailPage-Djv_swcO.js} +1 -1
- package/dist/public/assets/{PluginsListPage-Cte3vBgR.js → PluginsListPage-DAECNoN6.js} +1 -1
- package/dist/public/assets/PureConversationPage-DP1X7Hix.js +1 -0
- package/dist/public/assets/{RelayConnectEntryPage-sRJlstx9.js → RelayConnectEntryPage-xL_IPH8a.js} +1 -1
- package/dist/public/assets/{ServerSettingsModal-BBft9KEC.js → ServerSettingsModal-CyhMgk10.js} +1 -1
- package/dist/public/assets/SessionIndexPage-CVEz50tc.js +1 -0
- package/dist/public/assets/SettingsPage-CQNCrgaj.js +2 -0
- package/dist/public/assets/TerminalManagerPanel-wVnoRA8u.js +1 -0
- package/dist/public/assets/ToolFilesPage-BospXumK.js +1 -0
- package/dist/public/assets/ToolGitPage-B2zOeCAD.js +1 -0
- package/dist/public/assets/ToolProcessesPage-BDShao4b.js +1 -0
- package/dist/public/assets/{ToolsHomePage-D1n4FU1s.js → ToolsHomePage-s4zH7D9M.js} +1 -1
- package/dist/public/assets/{WorkbenchLandingPage-BaU_dXls.js → WorkbenchLandingPage-D51QCU_u.js} +1 -1
- package/dist/public/assets/{WorkbenchLayout-BksVkkFF.css → WorkbenchLayout-BZdfVest.css} +32 -1
- package/dist/public/assets/WorkbenchLayout-Bo2BbMY6.js +1081 -0
- package/dist/public/assets/{WorkbenchModal-DWsNm2B2.js → WorkbenchModal-YsyEdJ_m.js} +1 -1
- package/dist/public/assets/WorkbenchShellRoute-D3l4aWJS.js +1 -0
- package/dist/public/assets/WorkbenchShellRoute-D5fnyF8z.css +1 -0
- package/dist/public/assets/WorkspaceDebugDetailPage-CMjNLqFq.js +1 -0
- package/dist/public/assets/WorkspaceDetailPage-CKxTbPKh.js +1 -0
- package/dist/public/assets/WorkspaceHomePage-CEy4ShCu.js +1 -0
- package/dist/public/assets/{client-runtime-manager-D9VbgJZ_.js → client-runtime-manager-BFXU9DmS.js} +1 -1
- package/dist/public/assets/host-alias-Zb2xyVrf.js +1 -0
- package/dist/public/assets/index-BilHJjYU.js +50 -0
- package/dist/public/assets/index-OR7OITpQ.css +1 -0
- package/dist/public/assets/{login-direct-candidate-resolver-17wEvjhh.js → login-direct-candidate-resolver-DL8DS-Si.js} +1 -1
- package/dist/public/assets/peer-host-config-sync-d2ZcPC5P.js +1 -0
- package/dist/public/assets/{plugin-permission-copy-apDn8EWG.js → plugin-permission-copy-DrLk22m5.js} +1 -1
- package/dist/public/assets/{plugins-api-CnZYRKoS.js → plugins-api-COF4oh24.js} +1 -1
- package/dist/public/assets/{preferences-service-PZlLLAWH.js → preferences-service-CEWNV1w9.js} +1 -1
- package/dist/public/assets/{relay-entry-DhHwflXl.js → relay-entry-Cmc8vTlE.js} +1 -1
- package/dist/public/assets/useRegisteredDebugTemplates-FdmHG2S4.js +1 -0
- package/dist/public/assets/workbench-navigation-ED0157V-.js +1 -0
- package/dist/public/index.html +2 -2
- package/dist/server/config/env.js +5 -3
- package/dist/server/config/env.js.map +1 -1
- package/dist/server/modules/assistant-capability/assistant-capability-controller.d.ts +3 -0
- package/dist/server/modules/assistant-capability/assistant-capability-controller.js +9 -0
- package/dist/server/modules/assistant-capability/assistant-capability-controller.js.map +1 -1
- package/dist/server/modules/assistant-capability/assistant-capability-service.d.ts +3 -0
- package/dist/server/modules/assistant-capability/assistant-capability-service.js +4 -1
- package/dist/server/modules/assistant-capability/assistant-capability-service.js.map +1 -1
- package/dist/server/modules/butler/butler-session-service.d.ts +1 -0
- package/dist/server/modules/butler/butler-session-service.js +2 -1
- package/dist/server/modules/butler/butler-session-service.js.map +1 -1
- package/dist/server/modules/client/npm-global-package-service.js +3 -0
- package/dist/server/modules/client/npm-global-package-service.js.map +1 -1
- package/dist/server/modules/client/service-update-types.d.ts +3 -0
- package/dist/server/modules/peer-host/peer-host-controller.d.ts +5 -0
- package/dist/server/modules/peer-host/peer-host-controller.js +3 -0
- package/dist/server/modules/peer-host/peer-host-controller.js.map +1 -1
- package/dist/server/modules/peer-host/peer-host-service.d.ts +1 -0
- package/dist/server/modules/peer-host/peer-host-service.js +44 -0
- package/dist/server/modules/peer-host/peer-host-service.js.map +1 -1
- package/dist/server/modules/sessions/session-controller.d.ts +10 -0
- package/dist/server/modules/sessions/session-controller.js +11 -0
- package/dist/server/modules/sessions/session-controller.js.map +1 -1
- package/dist/server/modules/sessions/session-history-service.d.ts +43 -1
- package/dist/server/modules/sessions/session-history-service.js +362 -27
- package/dist/server/modules/sessions/session-history-service.js.map +1 -1
- package/dist/server/modules/tasks/observability-controller.d.ts +2 -0
- package/dist/server/modules/tasks/observability-controller.js +16 -1
- package/dist/server/modules/tasks/observability-controller.js.map +1 -1
- package/dist/server/modules/tasks/observability-service.d.ts +12 -2
- package/dist/server/modules/tasks/observability-service.js +16 -3
- package/dist/server/modules/tasks/observability-service.js.map +1 -1
- package/dist/server/modules/terminal/runtime/terminal-log-spooler.d.ts +5 -0
- package/dist/server/modules/terminal/runtime/terminal-log-spooler.js +54 -7
- package/dist/server/modules/terminal/runtime/terminal-log-spooler.js.map +1 -1
- package/dist/server/modules/workbench/affairs-assistant-session-snapshot-service.js +2 -1
- package/dist/server/modules/workbench/affairs-assistant-session-snapshot-service.js.map +1 -1
- package/dist/server/modules/workbench/workbench-service.d.ts +2 -0
- package/dist/server/modules/workbench/workbench-service.js +173 -20
- package/dist/server/modules/workbench/workbench-service.js.map +1 -1
- package/dist/server/modules/workspace/affairs-library-controller.d.ts +1 -0
- package/dist/server/modules/workspace/affairs-library-controller.js +3 -0
- package/dist/server/modules/workspace/affairs-library-controller.js.map +1 -1
- package/dist/server/modules/workspace/affairs-library-service.d.ts +4 -0
- package/dist/server/modules/workspace/affairs-library-service.js +23 -4
- package/dist/server/modules/workspace/affairs-library-service.js.map +1 -1
- package/dist/server/modules/workspace/affairs-lightweight-session-controller.d.ts +4 -0
- package/dist/server/modules/workspace/affairs-lightweight-session-controller.js +26 -0
- package/dist/server/modules/workspace/affairs-lightweight-session-controller.js.map +1 -1
- package/dist/server/modules/workspace/affairs-lightweight-session-service.d.ts +15 -1
- package/dist/server/modules/workspace/affairs-lightweight-session-service.js +201 -22
- package/dist/server/modules/workspace/affairs-lightweight-session-service.js.map +1 -1
- package/dist/server/modules/workspace/workspace-controller.d.ts +7 -1
- package/dist/server/modules/workspace/workspace-controller.js +11 -1
- package/dist/server/modules/workspace/workspace-controller.js.map +1 -1
- package/dist/server/modules/workspace/workspace-service.d.ts +9 -2
- package/dist/server/modules/workspace/workspace-service.js +45 -10
- package/dist/server/modules/workspace/workspace-service.js.map +1 -1
- package/dist/server/routes/affairs.js +4 -0
- package/dist/server/routes/affairs.js.map +1 -1
- package/dist/server/routes/peer-hosts.js +1 -0
- package/dist/server/routes/peer-hosts.js.map +1 -1
- package/dist/server/routes/sessions.js +2 -0
- package/dist/server/routes/sessions.js.map +1 -1
- package/dist/server/server/create-server.js +2 -2
- package/dist/server/server/create-server.js.map +1 -1
- package/dist/server/storage/repositories/session-discovery-diagnostics-repository.d.ts +10 -0
- package/dist/server/storage/repositories/session-discovery-diagnostics-repository.js +68 -0
- package/dist/server/storage/repositories/session-discovery-diagnostics-repository.js.map +1 -0
- package/dist/server/storage/repositories/session-source-index-repository.d.ts +14 -0
- package/dist/server/storage/repositories/session-source-index-repository.js +164 -0
- package/dist/server/storage/repositories/session-source-index-repository.js.map +1 -0
- package/dist/server/storage/repositories/workspace-navigation-state-repository.js +16 -7
- package/dist/server/storage/repositories/workspace-navigation-state-repository.js.map +1 -1
- package/dist/server/storage/sqlite/client.js +26 -0
- package/dist/server/storage/sqlite/client.js.map +1 -1
- package/dist/server/storage/sqlite/schema.sql +57 -0
- package/dist/server/types/domain.d.ts +45 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/claude-session-store.js +19 -2
- 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 +1 -0
- package/node_modules/@codingns/session-sync-core/dist/providers/codex.js +45 -1
- 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 +11 -4
- package/node_modules/@codingns/session-sync-core/dist/providers/opencode.js.map +1 -1
- package/package.json +3 -2
- package/scripts/node22-runtime.mjs +176 -0
- package/scripts/postinstall.mjs +6 -0
- package/dist/public/assets/App-7zrCMhE-.css +0 -1
- package/dist/public/assets/App-Dl-mcdqy.js +0 -30
- package/dist/public/assets/ConversationPage-DRQ5Sg_d.js +0 -9
- package/dist/public/assets/DesktopWindowPage-2SWAi0xz.js +0 -2
- package/dist/public/assets/FileContextPanel-fbPuE9dO.js +0 -1
- package/dist/public/assets/GitSidebar-BkmesJJR.js +0 -6
- package/dist/public/assets/MobileCreateSessionSheet-CEJcDBZJ.js +0 -1
- package/dist/public/assets/MobileTopHeaderFrame-CU0wsYSS.js +0 -1
- package/dist/public/assets/MobileWorkspaceSwitcherHeader-idl8o1OB.js +0 -1
- package/dist/public/assets/PluginAccessOverview-BBgM6tb0.js +0 -1
- package/dist/public/assets/SessionIndexPage-CN7cEdl9.js +0 -1
- package/dist/public/assets/SettingsPage-BGT-YqG2.js +0 -2
- package/dist/public/assets/TerminalManagerPanel-6-ZJ8vGn.js +0 -1
- package/dist/public/assets/TerminalPage-6GBZ9nXN.css +0 -32
- package/dist/public/assets/TerminalPage-CUXXQYU2.js +0 -55
- package/dist/public/assets/TerminalRuntimeFallbackModal-zc3qqMKJ.js +0 -1
- package/dist/public/assets/ToolFilesPage-QzsZyr0F.js +0 -1
- package/dist/public/assets/ToolGitPage-CXg4ncuT.js +0 -1
- package/dist/public/assets/ToolProcessesPage-BPsOsg4w.js +0 -1
- package/dist/public/assets/WorkbenchLayout-DViAJhHz.js +0 -1027
- package/dist/public/assets/WorkbenchShellRoute-BGfRqBUa.js +0 -1
- package/dist/public/assets/WorkbenchShellRoute-f2jWjHWu.css +0 -1
- package/dist/public/assets/WorkspaceDebugDetailPage-BX0zVSsI.js +0 -1
- package/dist/public/assets/WorkspaceDetailPage-Dx6JX4jx.js +0 -1
- package/dist/public/assets/WorkspaceHomePage-DQVJ042Z.js +0 -1
- package/dist/public/assets/host-alias-0TfFnYxR.js +0 -1
- package/dist/public/assets/index-DREvg1Yu.css +0 -1
- package/dist/public/assets/index-FOhyOpGY.js +0 -50
- package/dist/public/assets/peer-host-config-sync-vYkmqzNz.js +0 -1
- package/dist/public/assets/terminal-runtime-meta-2zvacxvM.js +0 -1
- package/dist/public/assets/useRegisteredDebugTemplates-CJ-o4tFl.js +0 -1
- package/dist/public/assets/workbench-navigation-aqJ1ay4M.js +0 -1
|
@@ -7,6 +7,8 @@ import { createId } from "../../shared/utils/id.js";
|
|
|
7
7
|
import { logPerformance } from "../../shared/utils/perf-log.js";
|
|
8
8
|
import { isTerminalDebugEnabled, logTerminalDebug, terminalDebugNowMs } from "../../shared/utils/terminal-debug-log.js";
|
|
9
9
|
import { nowIso } from "../../shared/utils/time.js";
|
|
10
|
+
import { SessionDiscoveryDiagnosticsRepository } from "../../storage/repositories/session-discovery-diagnostics-repository.js";
|
|
11
|
+
import { SessionSourceIndexRepository } from "../../storage/repositories/session-source-index-repository.js";
|
|
10
12
|
import { inspectSessionActivity } from "./session-activity-inspector.js";
|
|
11
13
|
import { SessionActivityAuthorityService } from "./session-activity-authority-service.js";
|
|
12
14
|
import { buildSessionTitleFromContent, normalizeRuntimePromptTitle } from "./session-title-utils.js";
|
|
@@ -72,6 +74,8 @@ export class SessionHistoryService {
|
|
|
72
74
|
capabilityService;
|
|
73
75
|
sessionActivityAuthorityService;
|
|
74
76
|
sessionForkRepository;
|
|
77
|
+
sessionSourceIndexRepository;
|
|
78
|
+
sessionDiscoveryDiagnosticsRepository;
|
|
75
79
|
providerSessionDeleteCli;
|
|
76
80
|
claudeCodeHomeDir;
|
|
77
81
|
codexModelOptionsService;
|
|
@@ -87,6 +91,7 @@ export class SessionHistoryService {
|
|
|
87
91
|
providerControlRepository;
|
|
88
92
|
taskManager;
|
|
89
93
|
workspaceDiscoveryStatuses = new Map();
|
|
94
|
+
sessionSourceIndexRepairScopes = new Map();
|
|
90
95
|
workspaceStateRefreshStatuses = new Map();
|
|
91
96
|
providerCapabilityCache = new Map();
|
|
92
97
|
codexDirtyBindingRepairStates = new Map();
|
|
@@ -108,6 +113,8 @@ export class SessionHistoryService {
|
|
|
108
113
|
this.sessionMessageOriginRepository = sessionMessageOriginRepository;
|
|
109
114
|
this.sessionActivityAuthorityService = sessionActivityAuthorityService;
|
|
110
115
|
this.sessionForkRepository = sessionForkRepository ?? new SessionForkRepository(db);
|
|
116
|
+
this.sessionSourceIndexRepository = new SessionSourceIndexRepository(db);
|
|
117
|
+
this.sessionDiscoveryDiagnosticsRepository = new SessionDiscoveryDiagnosticsRepository(db);
|
|
111
118
|
this.providerSessionDeleteCli =
|
|
112
119
|
adapterOverrides.providerSessionDeleteCli ?? new CodingnsProviderSessionDeleteCli(config);
|
|
113
120
|
this.taskManager = taskManager;
|
|
@@ -185,6 +192,73 @@ export class SessionHistoryService {
|
|
|
185
192
|
observeBackgroundTaskMetrics() {
|
|
186
193
|
return this.taskManager.observe();
|
|
187
194
|
}
|
|
195
|
+
listWorkspaceDiscoveryDiagnostics(workspaceId, userId, limit = 20) {
|
|
196
|
+
this.getDiscoverableWorkspaceForUserOrThrow(workspaceId, userId);
|
|
197
|
+
const normalizedLimit = Number.isFinite(limit) ? Math.max(1, Math.floor(limit)) : 20;
|
|
198
|
+
return this.sessionDiscoveryDiagnosticsRepository.listByWorkspaceId(workspaceId, normalizedLimit);
|
|
199
|
+
}
|
|
200
|
+
getWorkspaceDiscoveryStatusSummary(workspaceId) {
|
|
201
|
+
const status = this.workspaceDiscoveryStatuses.get(workspaceId);
|
|
202
|
+
if (!status) {
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
phase: status.phase,
|
|
207
|
+
dirtyReasonCount: status.dirtyReasons.size,
|
|
208
|
+
isComplete: status.isComplete,
|
|
209
|
+
lastRequestedAt: status.lastRequestedAt,
|
|
210
|
+
lastStartedAt: status.lastStartedAt,
|
|
211
|
+
lastCompletedAt: status.lastCompletedAt,
|
|
212
|
+
lastFailedAt: status.lastFailedAt,
|
|
213
|
+
nextAllowedAt: status.nextAllowedAt
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
async repairSessionSourceIndex(input) {
|
|
217
|
+
const workspaceId = input.workspaceId.trim();
|
|
218
|
+
const userId = input.userId.trim();
|
|
219
|
+
this.getDiscoverableWorkspaceForUserOrThrow(workspaceId, userId);
|
|
220
|
+
const provider = normalizeOptionalText(input.provider);
|
|
221
|
+
if (provider && !this.providerRegistry.list().some((adapter) => adapter.providerId === provider)) {
|
|
222
|
+
throw new AppError({
|
|
223
|
+
statusCode: 400,
|
|
224
|
+
errorCode: "INVALID_INPUT",
|
|
225
|
+
detail: "provider 不存在或当前不受支持",
|
|
226
|
+
field: "provider"
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
const sourceKeys = normalizeDistinctTexts(input.sourceKeys);
|
|
230
|
+
const rawStoreRefs = normalizeDistinctTexts(input.rawStoreRefs);
|
|
231
|
+
const existingRecords = this.sessionSourceIndexRepository.listByWorkspaceId(workspaceId);
|
|
232
|
+
const matchedRecords = existingRecords.filter((record) => matchesSessionSourceIndexRepairScope(record, provider, sourceKeys, rawStoreRefs));
|
|
233
|
+
const deletedSourceKeys = matchedRecords.map((record) => record.sourceKey);
|
|
234
|
+
const clearedSourceCount = this.sessionSourceIndexRepository.deleteBySourceKeys(deletedSourceKeys);
|
|
235
|
+
this.sessionSourceIndexRepairScopes.set(workspaceId, {
|
|
236
|
+
provider,
|
|
237
|
+
sourceKeys: new Set(sourceKeys),
|
|
238
|
+
rawStoreRefs: new Set(rawStoreRefs)
|
|
239
|
+
});
|
|
240
|
+
const awaitDiscovery = input.awaitDiscovery === true;
|
|
241
|
+
if (awaitDiscovery) {
|
|
242
|
+
await this.discoverWorkspaceSessions(workspaceId, userId, {
|
|
243
|
+
force: true,
|
|
244
|
+
refreshStateMode: "deferred"
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
this.requestWorkspaceDiscovery(workspaceId, userId, {
|
|
249
|
+
force: true,
|
|
250
|
+
refreshStateMode: "deferred"
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
return {
|
|
254
|
+
workspaceId,
|
|
255
|
+
provider,
|
|
256
|
+
sourceKeyCount: sourceKeys.length,
|
|
257
|
+
rawStoreRefCount: rawStoreRefs.length,
|
|
258
|
+
clearedSourceCount,
|
|
259
|
+
awaitDiscovery
|
|
260
|
+
};
|
|
261
|
+
}
|
|
188
262
|
registerLiveActivityObservationResolver(resolver) {
|
|
189
263
|
this.liveActivityObservationResolvers.add(resolver);
|
|
190
264
|
let closed = false;
|
|
@@ -219,7 +293,7 @@ export class SessionHistoryService {
|
|
|
219
293
|
this.taskManager.register({
|
|
220
294
|
taskType: HOST_TASK_TYPES.workspaceDiscovery,
|
|
221
295
|
executionLane: "host_background",
|
|
222
|
-
run: async ({ workspaceId, userId, refreshStateMode }, context) => this.runDiscoverWorkspaceSessions(workspaceId, userId, refreshStateMode, context.signal)
|
|
296
|
+
run: async ({ workspaceId, userId, refreshStateMode }, context) => this.runDiscoverWorkspaceSessions(workspaceId, userId, refreshStateMode, context.signal, context.taskId)
|
|
223
297
|
});
|
|
224
298
|
}
|
|
225
299
|
if (!this.taskManager.has(HOST_TASK_TYPES.workspaceDiscoveryScan)) {
|
|
@@ -255,24 +329,21 @@ export class SessionHistoryService {
|
|
|
255
329
|
}
|
|
256
330
|
}
|
|
257
331
|
async discoverWorkspaceSessions(workspaceId, userId, options) {
|
|
332
|
+
this.getDiscoverableWorkspaceForUserOrThrow(workspaceId, userId);
|
|
333
|
+
this.markWorkspaceDiscoveryRequested(workspaceId, "session_history.discover_workspace_sessions");
|
|
258
334
|
const maxAgeMs = options?.maxAgeMs ?? 0;
|
|
259
335
|
const force = options?.force ?? false;
|
|
260
336
|
const discoveryStatus = this.workspaceDiscoveryStatuses.get(workspaceId);
|
|
261
|
-
const lastRefreshedAt = discoveryStatus?.refreshedAt ?? 0;
|
|
262
337
|
const now = Date.now();
|
|
263
|
-
const isPartialCoolingDown = discoveryStatus
|
|
264
|
-
|
|
265
|
-
now < discoveryStatus.partialCooldownUntil;
|
|
266
|
-
const isCompleteAndFresh = discoveryStatus?.isComplete === true &&
|
|
267
|
-
maxAgeMs > 0 &&
|
|
268
|
-
now - lastRefreshedAt <= maxAgeMs;
|
|
338
|
+
const isPartialCoolingDown = this.isWorkspaceDiscoveryPartialCoolingDown(discoveryStatus, now);
|
|
339
|
+
const isCompleteAndFresh = this.isWorkspaceDiscoveryCompleteAndFresh(discoveryStatus, maxAgeMs, now);
|
|
269
340
|
if (!force &&
|
|
270
341
|
discoveryStatus &&
|
|
271
342
|
(isPartialCoolingDown || isCompleteAndFresh)) {
|
|
272
343
|
this.taskManager.recordCacheHit(HOST_TASK_TYPES.workspaceDiscovery, workspaceId);
|
|
273
344
|
return this.listWorkspaceSessions(workspaceId, userId);
|
|
274
345
|
}
|
|
275
|
-
|
|
346
|
+
const handle = this.taskManager.enqueue(HOST_TASK_TYPES.workspaceDiscovery, {
|
|
276
347
|
key: workspaceId,
|
|
277
348
|
source: "session_history.discover_workspace_sessions",
|
|
278
349
|
input: {
|
|
@@ -280,11 +351,22 @@ export class SessionHistoryService {
|
|
|
280
351
|
userId,
|
|
281
352
|
refreshStateMode: options?.refreshStateMode ?? "inline"
|
|
282
353
|
}
|
|
283
|
-
})
|
|
354
|
+
});
|
|
355
|
+
if (options?.signal) {
|
|
356
|
+
return await awaitTaskHandleWithSignal(handle, options.signal);
|
|
357
|
+
}
|
|
358
|
+
return await handle.promise;
|
|
284
359
|
}
|
|
285
360
|
requestWorkspaceDiscovery(workspaceId, userId, options) {
|
|
286
361
|
const maxAgeMs = options?.maxAgeMs ?? WORKSPACE_DISCOVERY_BACKGROUND_MAX_AGE_MS;
|
|
287
362
|
const force = options?.force ?? false;
|
|
363
|
+
if (!this.isWorkspaceDiscoverableForUser(workspaceId, userId)) {
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
const discoveryStatus = this.markWorkspaceDiscoveryRequested(workspaceId, "session_history.request_workspace_discovery");
|
|
367
|
+
if (!force && discoveryStatus.phase === "running") {
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
288
370
|
if (!force && !this.needsWorkspaceDiscovery(workspaceId, maxAgeMs)) {
|
|
289
371
|
return;
|
|
290
372
|
}
|
|
@@ -312,19 +394,27 @@ export class SessionHistoryService {
|
|
|
312
394
|
});
|
|
313
395
|
}
|
|
314
396
|
needsWorkspaceDiscovery(workspaceId, maxAgeMs) {
|
|
315
|
-
if (maxAgeMs <= 0) {
|
|
316
|
-
return true;
|
|
317
|
-
}
|
|
318
397
|
const discoveryStatus = this.workspaceDiscoveryStatuses.get(workspaceId);
|
|
319
398
|
if (!discoveryStatus) {
|
|
320
399
|
return true;
|
|
321
400
|
}
|
|
401
|
+
if (discoveryStatus.phase === "running") {
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
404
|
+
if (discoveryStatus.phase === "failed") {
|
|
405
|
+
return true;
|
|
406
|
+
}
|
|
407
|
+
if (discoveryStatus.dirtyReasons.size > 0) {
|
|
408
|
+
return true;
|
|
409
|
+
}
|
|
322
410
|
if (!discoveryStatus.isComplete &&
|
|
323
|
-
(discoveryStatus.
|
|
324
|
-
|
|
411
|
+
!this.isWorkspaceDiscoveryPartialCoolingDown(discoveryStatus, Date.now())) {
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
if (maxAgeMs <= 0) {
|
|
325
415
|
return true;
|
|
326
416
|
}
|
|
327
|
-
return Date.now()
|
|
417
|
+
return !this.isWorkspaceDiscoveryCompleteAndFresh(discoveryStatus, maxAgeMs, Date.now());
|
|
328
418
|
}
|
|
329
419
|
async readSessionHistory(sessionId, cursor, limit, direction = "forward", userId) {
|
|
330
420
|
const startedAt = Date.now();
|
|
@@ -1433,10 +1523,14 @@ export class SessionHistoryService {
|
|
|
1433
1523
|
}
|
|
1434
1524
|
}
|
|
1435
1525
|
}
|
|
1436
|
-
async runDiscoverWorkspaceSessions(workspaceId, userId, refreshStateMode = "inline", signal) {
|
|
1526
|
+
async runDiscoverWorkspaceSessions(workspaceId, userId, refreshStateMode = "inline", signal, taskId) {
|
|
1437
1527
|
const startedAt = Date.now();
|
|
1438
1528
|
const debugStartedAtMs = terminalDebugNowMs();
|
|
1439
|
-
const workspace = this.
|
|
1529
|
+
const workspace = this.getDiscoverableWorkspaceForUserOrThrow(workspaceId, userId);
|
|
1530
|
+
const discoveryStatus = this.getOrCreateWorkspaceDiscoveryStatus(workspaceId);
|
|
1531
|
+
discoveryStatus.phase = "running";
|
|
1532
|
+
discoveryStatus.lastStartedAt = startedAt;
|
|
1533
|
+
discoveryStatus.runningTaskId = taskId ?? `workspace.discovery:${workspaceId}:${startedAt}`;
|
|
1440
1534
|
let discoverDurationMs = 0;
|
|
1441
1535
|
let persistDurationMs = 0;
|
|
1442
1536
|
let persistPass1DurationMs = 0;
|
|
@@ -1450,14 +1544,16 @@ export class SessionHistoryService {
|
|
|
1450
1544
|
let listItemsDurationMs = 0;
|
|
1451
1545
|
let refreshStateDurationMs = 0;
|
|
1452
1546
|
const refreshStateCount = 10;
|
|
1547
|
+
const activeRepairScope = this.sessionSourceIndexRepairScopes.get(workspaceId) ?? null;
|
|
1453
1548
|
try {
|
|
1454
1549
|
const discoverStartedAt = Date.now();
|
|
1455
1550
|
const existingWorkspaceSessions = this.sessionIndexRepository.listByWorkspace(workspaceId, userId);
|
|
1551
|
+
const existingWorkspaceSourceIndexes = this.sessionSourceIndexRepository.listByWorkspaceId(workspaceId);
|
|
1456
1552
|
const enabledProviders = this.providerRegistry
|
|
1457
1553
|
.list()
|
|
1458
1554
|
.map((adapter) => adapter.providerId)
|
|
1459
1555
|
.filter((providerId) => this.isProviderEnabled(providerId));
|
|
1460
|
-
const knownSessions = this.buildKnownSessionSummaries(existingWorkspaceSessions.filter((session) => enabledProviders.includes(session.provider)), workspace.path);
|
|
1556
|
+
const knownSessions = this.buildKnownSessionSummaries(existingWorkspaceSessions.filter((session) => enabledProviders.includes(session.provider)), existingWorkspaceSourceIndexes.filter((record) => enabledProviders.includes(record.provider)), workspace.path, activeRepairScope);
|
|
1461
1557
|
const discoveryHandle = this.taskManager.enqueue(HOST_TASK_TYPES.workspaceDiscoveryScan, {
|
|
1462
1558
|
key: workspaceId,
|
|
1463
1559
|
source: "session_history.workspace_discovery.scan",
|
|
@@ -1474,6 +1570,7 @@ export class SessionHistoryService {
|
|
|
1474
1570
|
const sessions = discovery.sessions;
|
|
1475
1571
|
discoverDurationMs = Date.now() - discoverStartedAt;
|
|
1476
1572
|
const timestamp = nowIso();
|
|
1573
|
+
this.persistDiscoveryDiagnostics(workspaceId, "session_history.workspace_discovery.scan", discovery, timestamp);
|
|
1477
1574
|
const discoveredSessionIds = new Map();
|
|
1478
1575
|
const persistedSessions = [];
|
|
1479
1576
|
const claimedPendingSessionIds = new Set();
|
|
@@ -1642,6 +1739,7 @@ export class SessionHistoryService {
|
|
|
1642
1739
|
persistPass2DurationMs = Date.now() - persistPass2StartedAt;
|
|
1643
1740
|
persistPass2BatchCount = persistPass2Stats.batchCount;
|
|
1644
1741
|
persistPass2MaxBatchMs = persistPass2Stats.maxBatchMs;
|
|
1742
|
+
this.persistSessionSourceIndexRecords(workspaceId, workspace.path, sessions, existingWorkspaceSourceIndexes, timestamp);
|
|
1645
1743
|
persistDurationMs = persistPass1DurationMs + relationMapDurationMs + persistPass2DurationMs;
|
|
1646
1744
|
if (discovery.isComplete) {
|
|
1647
1745
|
const cleanupStartedAt = Date.now();
|
|
@@ -1655,11 +1753,19 @@ export class SessionHistoryService {
|
|
|
1655
1753
|
listItemsDurationMs = Date.now() - listItemsStartedAt;
|
|
1656
1754
|
const refreshCandidates = buildSessionStateRefreshCandidates(items, refreshStateCount);
|
|
1657
1755
|
this.workspaceDiscoveryStatuses.set(workspaceId, {
|
|
1756
|
+
...discoveryStatus,
|
|
1757
|
+
phase: discovery.isComplete ? "fresh" : "cooldown",
|
|
1758
|
+
dirtyReasons: new Set(),
|
|
1658
1759
|
refreshedAt: Date.now(),
|
|
1659
1760
|
isComplete: discovery.isComplete,
|
|
1660
1761
|
partialCooldownUntil: discovery.isComplete
|
|
1661
1762
|
? null
|
|
1662
|
-
: Date.now() + WORKSPACE_DISCOVERY_PARTIAL_COOLDOWN_MS
|
|
1763
|
+
: Date.now() + WORKSPACE_DISCOVERY_PARTIAL_COOLDOWN_MS,
|
|
1764
|
+
lastCompletedAt: Date.now(),
|
|
1765
|
+
nextAllowedAt: discovery.isComplete
|
|
1766
|
+
? null
|
|
1767
|
+
: Date.now() + WORKSPACE_DISCOVERY_PARTIAL_COOLDOWN_MS,
|
|
1768
|
+
runningTaskId: null
|
|
1663
1769
|
});
|
|
1664
1770
|
const refreshStateStartedAt = Date.now();
|
|
1665
1771
|
if (refreshStateMode === "inline") {
|
|
@@ -1734,6 +1840,13 @@ export class SessionHistoryService {
|
|
|
1734
1840
|
return nextItems;
|
|
1735
1841
|
}
|
|
1736
1842
|
catch (error) {
|
|
1843
|
+
const failedAt = Date.now();
|
|
1844
|
+
this.workspaceDiscoveryStatuses.set(workspaceId, {
|
|
1845
|
+
...discoveryStatus,
|
|
1846
|
+
phase: "failed",
|
|
1847
|
+
lastFailedAt: failedAt,
|
|
1848
|
+
runningTaskId: null
|
|
1849
|
+
});
|
|
1737
1850
|
logPerformance("workspace.discover_sessions.failed", Date.now() - startedAt, {
|
|
1738
1851
|
workspaceId,
|
|
1739
1852
|
workspacePath: workspace.path,
|
|
@@ -1757,6 +1870,11 @@ export class SessionHistoryService {
|
|
|
1757
1870
|
});
|
|
1758
1871
|
throw error;
|
|
1759
1872
|
}
|
|
1873
|
+
finally {
|
|
1874
|
+
if (activeRepairScope) {
|
|
1875
|
+
this.sessionSourceIndexRepairScopes.delete(workspaceId);
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1760
1878
|
}
|
|
1761
1879
|
async readPage(sessionId, provider, providerSessionId, rawStoreRef, cursor, limit, direction = "forward", knownTotalMessageCount = null) {
|
|
1762
1880
|
if (shouldShortCircuitClaudePendingHistory(provider, providerSessionId, rawStoreRef)) {
|
|
@@ -2450,6 +2568,65 @@ export class SessionHistoryService {
|
|
|
2450
2568
|
}
|
|
2451
2569
|
return workspace;
|
|
2452
2570
|
}
|
|
2571
|
+
getOrCreateWorkspaceDiscoveryStatus(workspaceId) {
|
|
2572
|
+
const existing = this.workspaceDiscoveryStatuses.get(workspaceId);
|
|
2573
|
+
if (existing) {
|
|
2574
|
+
return existing;
|
|
2575
|
+
}
|
|
2576
|
+
const created = {
|
|
2577
|
+
phase: "fresh",
|
|
2578
|
+
dirtyReasons: new Set(),
|
|
2579
|
+
refreshedAt: 0,
|
|
2580
|
+
isComplete: false,
|
|
2581
|
+
partialCooldownUntil: null,
|
|
2582
|
+
lastRequestedAt: null,
|
|
2583
|
+
lastStartedAt: null,
|
|
2584
|
+
lastCompletedAt: null,
|
|
2585
|
+
lastFailedAt: null,
|
|
2586
|
+
nextAllowedAt: null,
|
|
2587
|
+
runningTaskId: null
|
|
2588
|
+
};
|
|
2589
|
+
this.workspaceDiscoveryStatuses.set(workspaceId, created);
|
|
2590
|
+
return created;
|
|
2591
|
+
}
|
|
2592
|
+
markWorkspaceDiscoveryRequested(workspaceId, reason) {
|
|
2593
|
+
const status = this.getOrCreateWorkspaceDiscoveryStatus(workspaceId);
|
|
2594
|
+
status.lastRequestedAt = Date.now();
|
|
2595
|
+
if (status.phase === "running") {
|
|
2596
|
+
status.dirtyReasons.add(reason);
|
|
2597
|
+
}
|
|
2598
|
+
return status;
|
|
2599
|
+
}
|
|
2600
|
+
isWorkspaceDiscoveryPartialCoolingDown(status, now) {
|
|
2601
|
+
return Boolean(status
|
|
2602
|
+
&& status.isComplete === false
|
|
2603
|
+
&& status.partialCooldownUntil !== null
|
|
2604
|
+
&& now < status.partialCooldownUntil);
|
|
2605
|
+
}
|
|
2606
|
+
isWorkspaceDiscoveryCompleteAndFresh(status, maxAgeMs, now) {
|
|
2607
|
+
if (!status || !status.isComplete || maxAgeMs <= 0) {
|
|
2608
|
+
return false;
|
|
2609
|
+
}
|
|
2610
|
+
return now - status.refreshedAt <= maxAgeMs;
|
|
2611
|
+
}
|
|
2612
|
+
isWorkspaceDiscoverableForUser(workspaceId, userId) {
|
|
2613
|
+
const workspace = this.workspaceRepository.findById(workspaceId);
|
|
2614
|
+
if (!workspace || workspace.removedAt || workspace.ownerUserId !== userId) {
|
|
2615
|
+
return false;
|
|
2616
|
+
}
|
|
2617
|
+
return true;
|
|
2618
|
+
}
|
|
2619
|
+
getDiscoverableWorkspaceForUserOrThrow(workspaceId, userId) {
|
|
2620
|
+
const workspace = this.getWorkspaceForUserOrThrow(workspaceId, userId);
|
|
2621
|
+
if (workspace.removedAt) {
|
|
2622
|
+
throw new AppError({
|
|
2623
|
+
statusCode: 404,
|
|
2624
|
+
errorCode: "WORKSPACE_NOT_FOUND",
|
|
2625
|
+
detail: "工作区不存在"
|
|
2626
|
+
});
|
|
2627
|
+
}
|
|
2628
|
+
return workspace;
|
|
2629
|
+
}
|
|
2453
2630
|
getBindingForUserOrThrow(sessionId, userId) {
|
|
2454
2631
|
const binding = this.sessionBindingRepository.findBySessionIdForUser(sessionId, userId);
|
|
2455
2632
|
if (!binding) {
|
|
@@ -3189,24 +3366,121 @@ export class SessionHistoryService {
|
|
|
3189
3366
|
}
|
|
3190
3367
|
}
|
|
3191
3368
|
}
|
|
3192
|
-
buildKnownSessionSummaries(sessions, workspacePath) {
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
.
|
|
3196
|
-
|
|
3369
|
+
buildKnownSessionSummaries(sessions, sourceIndexes, workspacePath, repairScope = null) {
|
|
3370
|
+
const merged = new Map();
|
|
3371
|
+
for (const session of sessions) {
|
|
3372
|
+
if (this.isPendingSessionAlias(session) || shouldSkipClaudePendingBinding(session)) {
|
|
3373
|
+
continue;
|
|
3374
|
+
}
|
|
3375
|
+
const sourceKey = buildSessionSourceKey(session.provider, session.providerSessionId, session.rawStoreRef);
|
|
3376
|
+
if (shouldExcludeKnownSessionFromRepairScope(repairScope, session.provider, sourceKey, session.rawStoreRef)) {
|
|
3377
|
+
continue;
|
|
3378
|
+
}
|
|
3197
3379
|
const stats = safeStat(session.rawStoreRef);
|
|
3198
|
-
|
|
3380
|
+
const summary = {
|
|
3199
3381
|
provider: session.provider,
|
|
3200
3382
|
providerSessionId: session.providerSessionId,
|
|
3201
3383
|
title: session.title,
|
|
3202
3384
|
workspacePath,
|
|
3203
3385
|
rawStoreRef: session.rawStoreRef,
|
|
3386
|
+
isArchived: session.isArchived,
|
|
3204
3387
|
lastMessageAt: session.lastMessageAt,
|
|
3205
3388
|
messageCount: session.messageCount,
|
|
3206
3389
|
sourceMtimeMs: stats?.mtimeMs,
|
|
3207
3390
|
sourceSizeBytes: stats?.size
|
|
3208
3391
|
};
|
|
3209
|
-
|
|
3392
|
+
merged.set(buildKnownSessionSummaryKey(summary.provider, summary.providerSessionId, summary.rawStoreRef), summary);
|
|
3393
|
+
}
|
|
3394
|
+
for (const record of sourceIndexes) {
|
|
3395
|
+
if (record.deletedAt) {
|
|
3396
|
+
continue;
|
|
3397
|
+
}
|
|
3398
|
+
if (!record.providerSessionId || !record.rawStoreRef) {
|
|
3399
|
+
continue;
|
|
3400
|
+
}
|
|
3401
|
+
if (shouldExcludeKnownSessionFromRepairScope(repairScope, record.provider, record.sourceKey, record.rawStoreRef)) {
|
|
3402
|
+
continue;
|
|
3403
|
+
}
|
|
3404
|
+
const key = buildKnownSessionSummaryKey(record.provider, record.providerSessionId, record.rawStoreRef);
|
|
3405
|
+
if (merged.has(key)) {
|
|
3406
|
+
continue;
|
|
3407
|
+
}
|
|
3408
|
+
merged.set(key, {
|
|
3409
|
+
provider: record.provider,
|
|
3410
|
+
providerSessionId: record.providerSessionId,
|
|
3411
|
+
title: record.title?.trim() || record.providerSessionId,
|
|
3412
|
+
workspacePath: record.workspacePath?.trim() || workspacePath,
|
|
3413
|
+
rawStoreRef: record.rawStoreRef,
|
|
3414
|
+
isArchived: record.isArchivedHint ?? undefined,
|
|
3415
|
+
lastMessageAt: record.lastMessageAt,
|
|
3416
|
+
messageCount: Math.max(0, record.messageCount ?? 0),
|
|
3417
|
+
sourceMtimeMs: record.fingerprintMtimeMs ?? undefined,
|
|
3418
|
+
sourceSizeBytes: record.fingerprintSizeBytes ?? undefined
|
|
3419
|
+
});
|
|
3420
|
+
}
|
|
3421
|
+
return [...merged.values()];
|
|
3422
|
+
}
|
|
3423
|
+
persistSessionSourceIndexRecords(workspaceId, workspacePath, sessions, existingSourceIndexes, timestamp) {
|
|
3424
|
+
const existingByKey = new Map(existingSourceIndexes.map((record) => [record.sourceKey, record]));
|
|
3425
|
+
for (const session of sessions) {
|
|
3426
|
+
const sourceKind = inferSessionSourceKind(session.rawStoreRef);
|
|
3427
|
+
const sourceKey = buildSessionSourceKey(session.provider, session.providerSessionId, session.rawStoreRef);
|
|
3428
|
+
const stats = safeStat(session.rawStoreRef);
|
|
3429
|
+
const existing = existingByKey.get(sourceKey);
|
|
3430
|
+
this.sessionSourceIndexRepository.upsert({
|
|
3431
|
+
sourceKey,
|
|
3432
|
+
provider: session.provider,
|
|
3433
|
+
sourceKind,
|
|
3434
|
+
workspaceId,
|
|
3435
|
+
providerSessionId: session.providerSessionId,
|
|
3436
|
+
rawStoreRef: session.rawStoreRef,
|
|
3437
|
+
workspacePath,
|
|
3438
|
+
fingerprintMtimeMs: stats?.mtimeMs ?? existing?.fingerprintMtimeMs ?? null,
|
|
3439
|
+
fingerprintSizeBytes: stats?.size ?? existing?.fingerprintSizeBytes ?? null,
|
|
3440
|
+
fingerprintInode: existing?.fingerprintInode ?? null,
|
|
3441
|
+
fingerprintVersion: existing?.fingerprintVersion ?? null,
|
|
3442
|
+
title: session.title,
|
|
3443
|
+
messageCount: session.messageCount,
|
|
3444
|
+
lastMessageAt: session.lastMessageAt,
|
|
3445
|
+
isArchivedHint: session.isArchived ?? existing?.isArchivedHint ?? null,
|
|
3446
|
+
lastParsedAt: timestamp,
|
|
3447
|
+
lastVerifiedAt: timestamp,
|
|
3448
|
+
sampleDueAt: existing?.sampleDueAt ?? null,
|
|
3449
|
+
deletedAt: null,
|
|
3450
|
+
createdAt: existing?.createdAt ?? timestamp,
|
|
3451
|
+
updatedAt: timestamp
|
|
3452
|
+
});
|
|
3453
|
+
}
|
|
3454
|
+
}
|
|
3455
|
+
persistDiscoveryDiagnostics(workspaceId, triggerSource, discovery, timestamp) {
|
|
3456
|
+
try {
|
|
3457
|
+
for (const entry of discovery.providerDiagnostics ?? []) {
|
|
3458
|
+
const record = {
|
|
3459
|
+
id: createId(),
|
|
3460
|
+
workspaceId,
|
|
3461
|
+
triggerSource,
|
|
3462
|
+
provider: entry.provider,
|
|
3463
|
+
isComplete: entry.isComplete,
|
|
3464
|
+
status: entry.status,
|
|
3465
|
+
durationMs: Math.max(0, Math.round(entry.durationMs)),
|
|
3466
|
+
sessionCount: Math.max(0, entry.sessionCount),
|
|
3467
|
+
scannedFiles: Math.max(0, entry.scannedFiles ?? 0),
|
|
3468
|
+
skippedByFingerprint: Math.max(0, entry.skippedByMtimeSize ?? 0),
|
|
3469
|
+
parsedFiles: Math.max(0, entry.parsedFiles ?? 0),
|
|
3470
|
+
bytesRead: Math.max(0, entry.bytesRead ?? 0),
|
|
3471
|
+
createdAt: timestamp
|
|
3472
|
+
};
|
|
3473
|
+
this.sessionDiscoveryDiagnosticsRepository.insert(record);
|
|
3474
|
+
}
|
|
3475
|
+
}
|
|
3476
|
+
catch (error) {
|
|
3477
|
+
console.warn("[session-discovery-diagnostics-persist-failed]", {
|
|
3478
|
+
workspaceId,
|
|
3479
|
+
triggerSource,
|
|
3480
|
+
providerCount: discovery.providerDiagnostics?.length ?? 0,
|
|
3481
|
+
error
|
|
3482
|
+
});
|
|
3483
|
+
}
|
|
3210
3484
|
}
|
|
3211
3485
|
async refreshSessionState(sessionId, userId) {
|
|
3212
3486
|
const binding = this.getBindingOrThrow(sessionId);
|
|
@@ -3783,6 +4057,67 @@ function pickLaterIso(left, right) {
|
|
|
3783
4057
|
function buildProviderSessionKey(provider, providerSessionId) {
|
|
3784
4058
|
return `${provider}::${providerSessionId}`;
|
|
3785
4059
|
}
|
|
4060
|
+
function normalizeOptionalText(value) {
|
|
4061
|
+
const normalized = value?.trim();
|
|
4062
|
+
return normalized ? normalized : null;
|
|
4063
|
+
}
|
|
4064
|
+
function normalizeDistinctTexts(values) {
|
|
4065
|
+
if (!Array.isArray(values)) {
|
|
4066
|
+
return [];
|
|
4067
|
+
}
|
|
4068
|
+
const unique = new Set();
|
|
4069
|
+
for (const value of values) {
|
|
4070
|
+
const normalized = value?.trim();
|
|
4071
|
+
if (normalized) {
|
|
4072
|
+
unique.add(normalized);
|
|
4073
|
+
}
|
|
4074
|
+
}
|
|
4075
|
+
return [...unique];
|
|
4076
|
+
}
|
|
4077
|
+
function matchesSessionSourceIndexRepairScope(record, provider, sourceKeys, rawStoreRefs) {
|
|
4078
|
+
if (provider && record.provider !== provider) {
|
|
4079
|
+
return false;
|
|
4080
|
+
}
|
|
4081
|
+
if (sourceKeys.length === 0 && rawStoreRefs.length === 0) {
|
|
4082
|
+
return true;
|
|
4083
|
+
}
|
|
4084
|
+
return sourceKeys.includes(record.sourceKey)
|
|
4085
|
+
|| (record.rawStoreRef ? rawStoreRefs.includes(record.rawStoreRef) : false);
|
|
4086
|
+
}
|
|
4087
|
+
function shouldExcludeKnownSessionFromRepairScope(scope, provider, sourceKey, rawStoreRef) {
|
|
4088
|
+
if (!scope) {
|
|
4089
|
+
return false;
|
|
4090
|
+
}
|
|
4091
|
+
if (scope.provider && scope.provider !== provider) {
|
|
4092
|
+
return false;
|
|
4093
|
+
}
|
|
4094
|
+
if (scope.sourceKeys.size === 0 && scope.rawStoreRefs.size === 0) {
|
|
4095
|
+
return true;
|
|
4096
|
+
}
|
|
4097
|
+
return scope.sourceKeys.has(sourceKey) || scope.rawStoreRefs.has(rawStoreRef);
|
|
4098
|
+
}
|
|
4099
|
+
function buildKnownSessionSummaryKey(provider, providerSessionId, rawStoreRef) {
|
|
4100
|
+
return `${provider}::${providerSessionId}::${rawStoreRef}`;
|
|
4101
|
+
}
|
|
4102
|
+
function buildSessionSourceKey(provider, providerSessionId, rawStoreRef) {
|
|
4103
|
+
const normalizedRawStoreRef = rawStoreRef.trim();
|
|
4104
|
+
if (normalizedRawStoreRef.length > 0) {
|
|
4105
|
+
return `${provider}:raw:${normalizedRawStoreRef}`;
|
|
4106
|
+
}
|
|
4107
|
+
return `${provider}:session:${providerSessionId}`;
|
|
4108
|
+
}
|
|
4109
|
+
function inferSessionSourceKind(rawStoreRef) {
|
|
4110
|
+
if (rawStoreRef.endsWith(".jsonl")) {
|
|
4111
|
+
return "jsonl";
|
|
4112
|
+
}
|
|
4113
|
+
if (rawStoreRef.startsWith("opencode://") || rawStoreRef.startsWith("server://")) {
|
|
4114
|
+
return "server_session";
|
|
4115
|
+
}
|
|
4116
|
+
if (rawStoreRef.endsWith(".sqlite") || rawStoreRef.includes(".sqlite:")) {
|
|
4117
|
+
return "sqlite_row";
|
|
4118
|
+
}
|
|
4119
|
+
return "index_entry";
|
|
4120
|
+
}
|
|
3786
4121
|
function normalizeSessionBindingSnapshot(sessionId, snapshot) {
|
|
3787
4122
|
if (snapshot.provider !== "claude-code" ||
|
|
3788
4123
|
!(isPendingBindingValue(snapshot.providerSessionId) ||
|