@tonyclaw/agent-inspector 4.0.1 → 4.0.3
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/.output/backend/nitro.json +1 -1
- package/.output/cli.js +193 -110
- package/.output/server/_ssr/index.mjs +1 -1
- package/.output/server/_ssr/{router-CTHqmroT.mjs → router-ChILzhmz.mjs} +92 -4
- package/.output/server/index.mjs +1 -1
- package/.output/ui/assets/{CompareDrawer-L3n4J-Or.js → CompareDrawer-Co3cUF_I.js} +1 -1
- package/.output/ui/assets/{InspectorPet-D5o_3OZS.js → InspectorPet-jFcrL37X.js} +1 -1
- package/.output/ui/assets/{ProxyViewerContainer-Ocagx75S.js → ProxyViewerContainer-BPzt_VpM.js} +4 -4
- package/.output/ui/assets/{ReplayDialog-Bk7x1h-y.js → ReplayDialog-C6O_zuwI.js} +1 -1
- package/.output/ui/assets/{RequestAnatomy-U4lzL7Sc.js → RequestAnatomy-Ca6NvB7L.js} +1 -1
- package/.output/ui/assets/{ResponseView-LOWfvBLK.js → ResponseView-BzqKcveJ.js} +1 -1
- package/.output/ui/assets/{StreamingChunkSequence-DPfsrrXQ.js → StreamingChunkSequence-9pCZIsS_.js} +1 -1
- package/.output/ui/assets/{_sessionId-0MlWS-CO.js → _sessionId-BMP3KVGR.js} +1 -1
- package/.output/ui/assets/{_sessionId-OdX2Jvt1.js → _sessionId-y4eRoT1H.js} +1 -1
- package/.output/ui/assets/{index-Ea-c8hPg.js → index-CH5w-haG.js} +1 -1
- package/.output/ui/assets/{index-zVVS53Hd.js → index-CmocEhyU.js} +1 -1
- package/.output/ui/assets/{index-Du4qNOOt.js → index-DT8sMJ_n.js} +2 -2
- package/.output/ui/assets/{index-gvFj_9K6.js → index-bfsbIRZa.js} +1 -1
- package/.output/ui/assets/{json-viewer-C1WAMzg3.js → json-viewer-BfFOSDG5.js} +1 -1
- package/.output/ui/assets/{jszip.min-B8AKu2zm.js → jszip.min-BkbVkOsp.js} +1 -1
- package/.output/ui/index.html +1 -1
- package/package.json +5 -10
- package/src/assets/IDE/claudecode-color.svg +0 -1
- package/src/assets/IDE/codex-color.svg +0 -1
- package/src/assets/IDE/opencode.svg +0 -1
- package/src/assets/IDE/xiaomimimo.svg +0 -1
- package/src/assets/favicon.svg +0 -21
- package/src/assets/logos/alibaba.svg +0 -1
- package/src/assets/logos/anthropic.svg +0 -1
- package/src/assets/logos/claude-code.svg +0 -4
- package/src/assets/logos/deepseek.svg +0 -1
- package/src/assets/logos/minimax.jpeg +0 -0
- package/src/assets/logos/openai.svg +0 -1
- package/src/assets/logos/opencode.svg +0 -4
- package/src/assets/logos/qwen.webp +0 -0
- package/src/assets/logos/zhipuai.svg +0 -219
- package/src/backend/router.tsx +0 -36
- package/src/backend/routes/$.ts +0 -26
- package/src/backend/routes/__root.ts +0 -4
- package/src/backend/routes/api/-instances.ts +0 -7
- package/src/backend/routes/api/alerts.summary.ts +0 -28
- package/src/backend/routes/api/alerts.ts +0 -70
- package/src/backend/routes/api/config.paths.ts +0 -14
- package/src/backend/routes/api/config.ts +0 -73
- package/src/backend/routes/api/ecosystem.packages.$packageId.help.ts +0 -11
- package/src/backend/routes/api/ecosystem.packages.$packageId.install.ts +0 -11
- package/src/backend/routes/api/ecosystem.packages.$packageId.runner-presets.ts +0 -11
- package/src/backend/routes/api/ecosystem.packages.$packageId.upgrade.ts +0 -11
- package/src/backend/routes/api/ecosystem.packages.ts +0 -21
- package/src/backend/routes/api/ecosystem.recipes.$recipeId.run.ts +0 -11
- package/src/backend/routes/api/ecosystem.tasks.$taskId.ts +0 -16
- package/src/backend/routes/api/ecosystem.tasks.ts +0 -12
- package/src/backend/routes/api/groups.$groupId.evidence.ts +0 -55
- package/src/backend/routes/api/groups.$groupId.sessions.ts +0 -50
- package/src/backend/routes/api/groups.$groupId.ts +0 -93
- package/src/backend/routes/api/groups.ts +0 -79
- package/src/backend/routes/api/health.ts +0 -22
- package/src/backend/routes/api/instances.$name.connection.ts +0 -12
- package/src/backend/routes/api/instances.$name.restart.ts +0 -23
- package/src/backend/routes/api/instances.$name.start.ts +0 -18
- package/src/backend/routes/api/instances.$name.stop.ts +0 -23
- package/src/backend/routes/api/instances.$name.ts +0 -12
- package/src/backend/routes/api/instances.ts +0 -16
- package/src/backend/routes/api/knowledge.candidates.$candidateId.promote.ts +0 -32
- package/src/backend/routes/api/knowledge.candidates.$candidateId.ts +0 -50
- package/src/backend/routes/api/knowledge.candidates.ts +0 -10
- package/src/backend/routes/api/knowledge.project-context.ts +0 -29
- package/src/backend/routes/api/knowledge.search.ts +0 -62
- package/src/backend/routes/api/knowledge.sessions.$sessionId.candidates.ts +0 -26
- package/src/backend/routes/api/logs.$id.body.ts +0 -58
- package/src/backend/routes/api/logs.$id.chunks.ts +0 -37
- package/src/backend/routes/api/logs.$id.replay.ts +0 -297
- package/src/backend/routes/api/logs.$id.ts +0 -23
- package/src/backend/routes/api/logs.import.ts +0 -39
- package/src/backend/routes/api/logs.stream.ts +0 -174
- package/src/backend/routes/api/logs.ts +0 -214
- package/src/backend/routes/api/mcp.ts +0 -25
- package/src/backend/routes/api/models.ts +0 -10
- package/src/backend/routes/api/pi-agent.ts +0 -29
- package/src/backend/routes/api/providers.$providerId.model-metadata.ts +0 -173
- package/src/backend/routes/api/providers.$providerId.test.log.ts +0 -342
- package/src/backend/routes/api/providers.$providerId.ts +0 -111
- package/src/backend/routes/api/providers.export.ts +0 -44
- package/src/backend/routes/api/providers.import.ts +0 -81
- package/src/backend/routes/api/providers.scan.ts +0 -28
- package/src/backend/routes/api/providers.ts +0 -102
- package/src/backend/routes/api/runs.$runId.evidence.ts +0 -55
- package/src/backend/routes/api/runs.$runId.ts +0 -50
- package/src/backend/routes/api/runs.ts +0 -62
- package/src/backend/routes/api/runtime.ts +0 -46
- package/src/backend/routes/api/sessions.ts +0 -51
- package/src/backend/routes/api/storage.ts +0 -56
- package/src/backend/routes/livez.ts +0 -13
- package/src/backend/routes/metrics.ts +0 -14
- package/src/backend/routes/proxy/$.ts +0 -15
- package/src/backend/routes/readyz.ts +0 -18
- package/src/backend/start.ts +0 -10
- package/src/cli/alias.ts +0 -431
- package/src/cli/detect-tools.ts +0 -123
- package/src/cli/doctor.ts +0 -836
- package/src/cli/instance.ts +0 -1071
- package/src/cli/instanceApi.ts +0 -213
- package/src/cli/instanceArgs.ts +0 -301
- package/src/cli/instanceControl.ts +0 -191
- package/src/cli/instanceModel.ts +0 -276
- package/src/cli/instanceRegistry.ts +0 -731
- package/src/cli/networkHints.ts +0 -170
- package/src/cli/onboard.ts +0 -1668
- package/src/cli/onboardTarget.ts +0 -228
- package/src/cli/rustBackendPackage.ts +0 -458
- package/src/cli/startupOutput.ts +0 -16
- package/src/cli/templates/codex-skill-onboard.ts +0 -320
- package/src/cli/templates/command-onboard.ts +0 -25
- package/src/cli/templates/skill-onboard.ts +0 -625
- package/src/cli.ts +0 -1433
- package/src/components/OnboardingBanner.tsx +0 -115
- package/src/components/ProxyViewer.tsx +0 -2259
- package/src/components/ProxyViewerContainer.tsx +0 -1076
- package/src/components/alerts/AlertsDialog.tsx +0 -615
- package/src/components/clients/ClientLogo.tsx +0 -175
- package/src/components/ecosystem/AgentLabDialog.tsx +0 -947
- package/src/components/errors/SafeErrorBoundary.tsx +0 -201
- package/src/components/groups/GroupsDialog.tsx +0 -1304
- package/src/components/inspector-pet/InspectorPet.tsx +0 -398
- package/src/components/inspector-pet/InspectorPetCrab3D.tsx +0 -455
- package/src/components/inspector-pet/inspectorPetLogic.ts +0 -272
- package/src/components/pi-agent/PiAgentPanel.tsx +0 -446
- package/src/components/pi-agent/piAgentChatLogic.ts +0 -273
- package/src/components/providers/ImportWizardDialog.tsx +0 -281
- package/src/components/providers/ProviderCard.tsx +0 -347
- package/src/components/providers/ProviderForm.tsx +0 -1183
- package/src/components/providers/ProviderLogo.tsx +0 -122
- package/src/components/providers/ProviderTestResultsView.tsx +0 -734
- package/src/components/providers/ProvidersPanel.tsx +0 -714
- package/src/components/providers/SettingsDialog.tsx +0 -1042
- package/src/components/providers/providerFormCapabilities.ts +0 -36
- package/src/components/proxy-viewer/AgentTraceSummary.tsx +0 -902
- package/src/components/proxy-viewer/AnswerMarkdown.tsx +0 -51
- package/src/components/proxy-viewer/ApplicationBar.tsx +0 -123
- package/src/components/proxy-viewer/CompareDrawer.tsx +0 -984
- package/src/components/proxy-viewer/ConversationGroup.tsx +0 -208
- package/src/components/proxy-viewer/ConversationGroupList.tsx +0 -652
- package/src/components/proxy-viewer/ConversationHeader.tsx +0 -429
- package/src/components/proxy-viewer/LiveConnectionStatus.tsx +0 -186
- package/src/components/proxy-viewer/LogEntry.tsx +0 -1419
- package/src/components/proxy-viewer/LogEntryHeader.tsx +0 -596
- package/src/components/proxy-viewer/ProviderLogoStack.tsx +0 -57
- package/src/components/proxy-viewer/RawExportWarning.tsx +0 -77
- package/src/components/proxy-viewer/ReplayDialog.tsx +0 -636
- package/src/components/proxy-viewer/RequestToolsPanel.tsx +0 -299
- package/src/components/proxy-viewer/ResponseView.tsx +0 -202
- package/src/components/proxy-viewer/SessionLoadProgressBar.tsx +0 -61
- package/src/components/proxy-viewer/StreamingChunkSequence.tsx +0 -265
- package/src/components/proxy-viewer/ThreadConnector.tsx +0 -165
- package/src/components/proxy-viewer/ToolTraceEvents.tsx +0 -64
- package/src/components/proxy-viewer/TurnGroup.tsx +0 -383
- package/src/components/proxy-viewer/TurnGroupList.tsx +0 -156
- package/src/components/proxy-viewer/accessibility.ts +0 -8
- package/src/components/proxy-viewer/anatomy/RequestAnatomy.tsx +0 -887
- package/src/components/proxy-viewer/anatomy/SegmentBar.tsx +0 -222
- package/src/components/proxy-viewer/anatomy/contextIntelligence.ts +0 -737
- package/src/components/proxy-viewer/anatomy/sessionContextSummary.ts +0 -268
- package/src/components/proxy-viewer/anatomy/tokenEstimate.ts +0 -53
- package/src/components/proxy-viewer/anatomy/types.ts +0 -41
- package/src/components/proxy-viewer/anatomy/useAnatomyJump.ts +0 -114
- package/src/components/proxy-viewer/bodyHydration.ts +0 -123
- package/src/components/proxy-viewer/cacheTrend.ts +0 -50
- package/src/components/proxy-viewer/diff/DiffView.tsx +0 -321
- package/src/components/proxy-viewer/diff/computeDiff.ts +0 -178
- package/src/components/proxy-viewer/diff/index.ts +0 -3
- package/src/components/proxy-viewer/formats/anthropic/ContentBlocks.tsx +0 -194
- package/src/components/proxy-viewer/formats/anthropic/ResponseView.tsx +0 -81
- package/src/components/proxy-viewer/formats/anthropic/thinkingExtract.ts +0 -21
- package/src/components/proxy-viewer/formats/index.tsx +0 -47
- package/src/components/proxy-viewer/formats/openai/ResponseView.tsx +0 -442
- package/src/components/proxy-viewer/index.ts +0 -9
- package/src/components/proxy-viewer/lazy.ts +0 -41
- package/src/components/proxy-viewer/liveConnectionState.ts +0 -158
- package/src/components/proxy-viewer/log-formats/anthropic.ts +0 -191
- package/src/components/proxy-viewer/log-formats/index.ts +0 -23
- package/src/components/proxy-viewer/log-formats/openai.ts +0 -256
- package/src/components/proxy-viewer/log-formats/types.ts +0 -40
- package/src/components/proxy-viewer/log-formats/unknown.ts +0 -18
- package/src/components/proxy-viewer/logEntryVisibility.ts +0 -73
- package/src/components/proxy-viewer/logFocus.ts +0 -54
- package/src/components/proxy-viewer/proxyViewerContainerLogic.ts +0 -124
- package/src/components/proxy-viewer/proxyViewerLogic.ts +0 -488
- package/src/components/proxy-viewer/replayComparison.ts +0 -131
- package/src/components/proxy-viewer/requestDiff.ts +0 -277
- package/src/components/proxy-viewer/requestTools.ts +0 -220
- package/src/components/proxy-viewer/useCopyFeedback.ts +0 -38
- package/src/components/proxy-viewer/useKeyboardNavigation.ts +0 -232
- package/src/components/proxy-viewer/viewerState.ts +0 -176
- package/src/components/ui/badge.tsx +0 -47
- package/src/components/ui/button.tsx +0 -47
- package/src/components/ui/collapsible.tsx +0 -21
- package/src/components/ui/confirm-dialog.tsx +0 -51
- package/src/components/ui/crab-logo.tsx +0 -45
- package/src/components/ui/crab-variants.tsx +0 -467
- package/src/components/ui/dialog.tsx +0 -130
- package/src/components/ui/icon-trigger.ts +0 -2
- package/src/components/ui/json-viewer-bulk.ts +0 -132
- package/src/components/ui/json-viewer.tsx +0 -508
- package/src/components/ui/scroll-area.tsx +0 -54
- package/src/components/ui/select.tsx +0 -178
- package/src/components/ui/separator.tsx +0 -28
- package/src/components/ui/tabs.tsx +0 -88
- package/src/components/ui/tooltip.tsx +0 -51
- package/src/components/ui/transient-toast.tsx +0 -105
- package/src/contracts/anthropic.ts +0 -230
- package/src/contracts/index.ts +0 -59
- package/src/contracts/json.ts +0 -37
- package/src/contracts/log.ts +0 -139
- package/src/contracts/openai.ts +0 -267
- package/src/index.css +0 -11
- package/src/knowledge/candidateStore.ts +0 -94
- package/src/knowledge/distiller.ts +0 -98
- package/src/knowledge/openclawClient.ts +0 -161
- package/src/knowledge/openclawGatewayClient.ts +0 -249
- package/src/knowledge/openclawMarkdown.ts +0 -146
- package/src/knowledge/redactor.ts +0 -80
- package/src/knowledge/types.ts +0 -83
- package/src/lib/alertContract.ts +0 -76
- package/src/lib/apiClient.ts +0 -166
- package/src/lib/apiFormat.ts +0 -29
- package/src/lib/backendImplementation.ts +0 -16
- package/src/lib/basePath.ts +0 -107
- package/src/lib/browserRuntimeContract.ts +0 -124
- package/src/lib/browserRuntimeResolver.ts +0 -333
- package/src/lib/chunkLoadRecovery.ts +0 -83
- package/src/lib/claudeCodeStrip.ts +0 -98
- package/src/lib/clipboard.ts +0 -67
- package/src/lib/codingAgentEndpoints.ts +0 -54
- package/src/lib/ecosystemContract.ts +0 -130
- package/src/lib/export-logs.ts +0 -287
- package/src/lib/groupContract.ts +0 -166
- package/src/lib/instanceContract.ts +0 -239
- package/src/lib/jsonFile.ts +0 -46
- package/src/lib/logImportContract.ts +0 -12
- package/src/lib/managedInstance.ts +0 -112
- package/src/lib/mask.ts +0 -4
- package/src/lib/objectUtils.ts +0 -22
- package/src/lib/piAgentContract.ts +0 -102
- package/src/lib/providerContract.ts +0 -125
- package/src/lib/providerImportContract.ts +0 -27
- package/src/lib/providerModelMetadata.ts +0 -458
- package/src/lib/providerTestContract.ts +0 -170
- package/src/lib/providerTestPrompt.ts +0 -100
- package/src/lib/publicBasePathContext.ts +0 -137
- package/src/lib/resourceLimits.ts +0 -345
- package/src/lib/runContract.ts +0 -164
- package/src/lib/runtimeConfig.ts +0 -43
- package/src/lib/safeDiagnostic.ts +0 -38
- package/src/lib/safeFetch.ts +0 -508
- package/src/lib/serverPort.ts +0 -47
- package/src/lib/sessionInfoContract.ts +0 -78
- package/src/lib/sessionUrl.ts +0 -46
- package/src/lib/ssrfGuard.ts +0 -133
- package/src/lib/stopReason.ts +0 -130
- package/src/lib/themeMode.ts +0 -41
- package/src/lib/timeDisplay.ts +0 -22
- package/src/lib/toolTrace.ts +0 -290
- package/src/lib/uiScale.ts +0 -117
- package/src/lib/unknown.ts +0 -27
- package/src/lib/upstreamUrl.ts +0 -150
- package/src/lib/useAlerts.ts +0 -82
- package/src/lib/useGroupEvidence.ts +0 -37
- package/src/lib/useGroups.ts +0 -32
- package/src/lib/useOnboarding.ts +0 -93
- package/src/lib/useProviders.ts +0 -30
- package/src/lib/useStripConfig.ts +0 -154
- package/src/lib/useThemeMode.ts +0 -40
- package/src/lib/useUiScale.ts +0 -52
- package/src/lib/utils.ts +0 -78
- package/src/mcp/currentContext.ts +0 -65
- package/src/mcp/instanceHandlers.ts +0 -151
- package/src/mcp/loopback.ts +0 -88
- package/src/mcp/mode.ts +0 -75
- package/src/mcp/previewExtractor.ts +0 -233
- package/src/mcp/server.ts +0 -2274
- package/src/mcp/toolHandlers.ts +0 -1533
- package/src/proxy/alerts.ts +0 -664
- package/src/proxy/chunkStorage.ts +0 -123
- package/src/proxy/config.ts +0 -218
- package/src/proxy/constants.ts +0 -66
- package/src/proxy/dataDir.ts +0 -147
- package/src/proxy/ecosystemExecutionConfirmation.ts +0 -114
- package/src/proxy/ecosystemExecutionRoute.ts +0 -116
- package/src/proxy/ecosystemRegistry.ts +0 -296
- package/src/proxy/ecosystemTasks.ts +0 -415
- package/src/proxy/evidenceAnalysis.ts +0 -526
- package/src/proxy/evidenceExporter.ts +0 -235
- package/src/proxy/formats/anthropic/anthropicProvider.ts +0 -75
- package/src/proxy/formats/anthropic/handler.ts +0 -75
- package/src/proxy/formats/anthropic/index.ts +0 -13
- package/src/proxy/formats/anthropic/register.ts +0 -4
- package/src/proxy/formats/anthropic/schemas.ts +0 -6
- package/src/proxy/formats/anthropic/stream.ts +0 -205
- package/src/proxy/formats/handler.ts +0 -46
- package/src/proxy/formats/index.ts +0 -13
- package/src/proxy/formats/jsonSchema.ts +0 -2
- package/src/proxy/formats/openai/alibabaProvider.ts +0 -34
- package/src/proxy/formats/openai/codexMetadata.ts +0 -61
- package/src/proxy/formats/openai/handler.ts +0 -133
- package/src/proxy/formats/openai/index.ts +0 -33
- package/src/proxy/formats/openai/provider.ts +0 -50
- package/src/proxy/formats/openai/register.ts +0 -4
- package/src/proxy/formats/openai/schemas.ts +0 -25
- package/src/proxy/formats/openai/stream.ts +0 -600
- package/src/proxy/formats/openai/zhipuProvider.ts +0 -31
- package/src/proxy/formats/providerAdapter.ts +0 -50
- package/src/proxy/formats/providerRegistry.ts +0 -51
- package/src/proxy/formats/providers/index.ts +0 -3
- package/src/proxy/formats/registry.ts +0 -65
- package/src/proxy/groupEvidenceExporter.ts +0 -371
- package/src/proxy/groupStore.ts +0 -336
- package/src/proxy/handler.ts +0 -729
- package/src/proxy/identityProxy.ts +0 -1842
- package/src/proxy/jsonlRecovery.ts +0 -554
- package/src/proxy/logBodyChunks.ts +0 -91
- package/src/proxy/logFinalizer.ts +0 -777
- package/src/proxy/logFinalizer.worker.ts +0 -24
- package/src/proxy/logImportUpload.ts +0 -128
- package/src/proxy/logImporter.ts +0 -813
- package/src/proxy/logIndex.ts +0 -663
- package/src/proxy/logSearch.ts +0 -122
- package/src/proxy/logger.ts +0 -537
- package/src/proxy/openaiOrphanToolStrip.ts +0 -142
- package/src/proxy/platformCommands.ts +0 -258
- package/src/proxy/privateDataPath.ts +0 -419
- package/src/proxy/providerImporters.ts +0 -578
- package/src/proxy/providerScanStore.ts +0 -87
- package/src/proxy/providerSecretStore.ts +0 -216
- package/src/proxy/providers.ts +0 -998
- package/src/proxy/rawStreamCapture.ts +0 -342
- package/src/proxy/runFailures.ts +0 -94
- package/src/proxy/runStore.ts +0 -214
- package/src/proxy/runtimeAdmission.ts +0 -55
- package/src/proxy/runtimeHealth.ts +0 -221
- package/src/proxy/runtimeMetrics.ts +0 -149
- package/src/proxy/runtimeShutdown.ts +0 -157
- package/src/proxy/schemas.ts +0 -112
- package/src/proxy/sessionArchive.ts +0 -479
- package/src/proxy/sessionInfo.ts +0 -266
- package/src/proxy/sessionProcess.ts +0 -194
- package/src/proxy/sessionRuntime.ts +0 -121
- package/src/proxy/sessionSupervisor.ts +0 -305
- package/src/proxy/sessionWorkerEntry.ts +0 -26
- package/src/proxy/shutdownCoordinator.ts +0 -90
- package/src/proxy/socketTracker.ts +0 -639
- package/src/proxy/sqliteLogIndex.ts +0 -733
- package/src/proxy/storageLifecycle.ts +0 -432
- package/src/proxy/store.ts +0 -1773
- package/src/proxy/streamTiming.ts +0 -31
- package/src/proxy/toolSchemaWarnings.ts +0 -529
- package/src/proxy/uiAssetServer.ts +0 -106
- package/src/proxy/upstream.ts +0 -127
- package/src/services/alerts.ts +0 -12
- package/src/services/groups.ts +0 -119
- package/src/services/piAgent.ts +0 -421
- package/src/services/piAgentRetrieval.ts +0 -1180
- package/src/services/result.ts +0 -17
- package/src/services/runs.ts +0 -76
- package/src/ui/bootstrap.ts +0 -167
- package/src/ui/index.html +0 -38
- package/src/ui/logsStreamClient.ts +0 -20
- package/src/ui/main.tsx +0 -13
- package/src/ui/public/runtime-config.js +0 -2
- package/src/ui/router.tsx +0 -13
- package/src/ui/routes/__root.tsx +0 -69
- package/src/ui/routes/index.tsx +0 -35
- package/src/ui/routes/session/$sessionId.tsx +0 -50
- package/src/ui/runtimeDiscovery.ts +0 -50
|
@@ -1,479 +0,0 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import { readdir, rm } from "node:fs/promises";
|
|
4
|
-
import { dirname, join } from "node:path";
|
|
5
|
-
import { CapturedLogSchema, type CapturedLog } from "./schemas";
|
|
6
|
-
import { logger, resolveLogDir } from "./logger";
|
|
7
|
-
import { ensurePrivateDirectorySync, securePrivateFileSync } from "./privateDataPath";
|
|
8
|
-
|
|
9
|
-
type SqliteConstructorResult = {
|
|
10
|
-
constructor: ((path: string) => unknown) | null;
|
|
11
|
-
reason: string | null;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const SESSION_ARCHIVE_DIR = "sessions";
|
|
15
|
-
const SESSION_ARCHIVE_FILE = "session.sqlite";
|
|
16
|
-
const SQLITE_PACKAGE_NAME = "better-sqlite3";
|
|
17
|
-
const BUN_SQLITE_MODULE_NAME = "bun:sqlite";
|
|
18
|
-
|
|
19
|
-
const CREATE_SCHEMA_SQL = `
|
|
20
|
-
CREATE TABLE IF NOT EXISTS session_logs (
|
|
21
|
-
id INTEGER PRIMARY KEY,
|
|
22
|
-
session_id TEXT NOT NULL,
|
|
23
|
-
log_json TEXT NOT NULL,
|
|
24
|
-
updated_at TEXT NOT NULL
|
|
25
|
-
);
|
|
26
|
-
CREATE INDEX IF NOT EXISTS idx_session_logs_session_id_id ON session_logs(session_id, id);
|
|
27
|
-
`;
|
|
28
|
-
|
|
29
|
-
const UPSERT_SQL = `
|
|
30
|
-
INSERT INTO session_logs (
|
|
31
|
-
id,
|
|
32
|
-
session_id,
|
|
33
|
-
log_json,
|
|
34
|
-
updated_at
|
|
35
|
-
) VALUES (?, ?, ?, ?)
|
|
36
|
-
ON CONFLICT(id) DO UPDATE SET
|
|
37
|
-
session_id = excluded.session_id,
|
|
38
|
-
log_json = excluded.log_json,
|
|
39
|
-
updated_at = excluded.updated_at
|
|
40
|
-
`;
|
|
41
|
-
|
|
42
|
-
let didLogUnavailable = false;
|
|
43
|
-
let cachedArchiveMax: { root: string; maxId: number } | null = null;
|
|
44
|
-
|
|
45
|
-
export function getSessionArchiveRoot(): string {
|
|
46
|
-
return join(resolveLogDir(), SESSION_ARCHIVE_DIR);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function hashSessionId(sessionId: string): string {
|
|
50
|
-
return createHash("sha256").update(sessionId).digest("hex").slice(0, 16);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function sanitizeSessionPrefix(sessionId: string): string {
|
|
54
|
-
const trimmed = sessionId.trim();
|
|
55
|
-
if (trimmed.length === 0) return "session";
|
|
56
|
-
const normalized = trimmed.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
57
|
-
if (normalized.length === 0) return "session";
|
|
58
|
-
return normalized.slice(0, 48);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function sessionArchiveKey(sessionId: string): string {
|
|
62
|
-
return `${sanitizeSessionPrefix(sessionId)}--${hashSessionId(sessionId)}`;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function getSessionArchivePath(sessionId: string): string {
|
|
66
|
-
return join(getSessionArchiveRoot(), sessionArchiveKey(sessionId), SESSION_ARCHIVE_FILE);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function objectFromUnknown(value: unknown): object | null {
|
|
70
|
-
if (value === null) return null;
|
|
71
|
-
if (typeof value === "object" || typeof value === "function") return value;
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function readProperty(value: unknown, name: string): unknown {
|
|
76
|
-
let current = objectFromUnknown(value);
|
|
77
|
-
while (current !== null) {
|
|
78
|
-
const desc = Object.getOwnPropertyDescriptor(current, name);
|
|
79
|
-
if (desc !== undefined) {
|
|
80
|
-
const propertyValue: unknown = Reflect.get(current, name);
|
|
81
|
-
return propertyValue;
|
|
82
|
-
}
|
|
83
|
-
const nextPrototype: unknown = Object.getPrototypeOf(current);
|
|
84
|
-
current = objectFromUnknown(nextPrototype);
|
|
85
|
-
}
|
|
86
|
-
return undefined;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function readFunction(value: unknown, name: string): Function | null {
|
|
90
|
-
const property = readProperty(value, name);
|
|
91
|
-
return typeof property === "function" ? property : null;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function callMethod(target: unknown, methodName: string, args: readonly unknown[]): unknown {
|
|
95
|
-
const method = readFunction(target, methodName);
|
|
96
|
-
if (method === null) return undefined;
|
|
97
|
-
try {
|
|
98
|
-
return Reflect.apply(method, target, [...args]);
|
|
99
|
-
} catch (err) {
|
|
100
|
-
logger.warn("[sessionArchive] SQLite method failed:", methodName, String(err));
|
|
101
|
-
return undefined;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function prepareStatement(db: unknown, sql: string): unknown {
|
|
106
|
-
return callMethod(db, "prepare", [sql]);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function runPrepared(db: unknown, sql: string, params: readonly unknown[] = []): boolean {
|
|
110
|
-
const statement = prepareStatement(db, sql);
|
|
111
|
-
if (statement === undefined) return false;
|
|
112
|
-
const result = callMethod(statement, "run", params);
|
|
113
|
-
callMethod(statement, "finalize", []);
|
|
114
|
-
return result !== undefined;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function allPrepared(db: unknown, sql: string, params: readonly unknown[] = []): unknown[] {
|
|
118
|
-
const statement = prepareStatement(db, sql);
|
|
119
|
-
if (statement === undefined) return [];
|
|
120
|
-
const result = callMethod(statement, "all", params);
|
|
121
|
-
callMethod(statement, "finalize", []);
|
|
122
|
-
return Array.isArray(result) ? result : [];
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function execSql(db: unknown, sql: string): boolean {
|
|
126
|
-
const result = callMethod(db, "exec", [sql]);
|
|
127
|
-
return result !== undefined;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function closeDatabase(db: unknown): void {
|
|
131
|
-
callMethod(db, "close", []);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function sqliteConstructorFromModule(
|
|
135
|
-
moduleValue: unknown,
|
|
136
|
-
exportName: "default" | "Database",
|
|
137
|
-
): ((path: string) => unknown) | null {
|
|
138
|
-
const exportedValue = readProperty(moduleValue, exportName);
|
|
139
|
-
if (typeof exportedValue === "function") {
|
|
140
|
-
return (path: string): unknown => Reflect.construct(exportedValue, [path]);
|
|
141
|
-
}
|
|
142
|
-
return null;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
async function loadSqliteModuleConstructor(
|
|
146
|
-
moduleName: string,
|
|
147
|
-
exportName: "default" | "Database",
|
|
148
|
-
): Promise<SqliteConstructorResult> {
|
|
149
|
-
try {
|
|
150
|
-
const importedModule: unknown = await import(/* @vite-ignore */ moduleName);
|
|
151
|
-
const exportedConstructor = sqliteConstructorFromModule(importedModule, exportName);
|
|
152
|
-
if (exportedConstructor !== null) return { constructor: exportedConstructor, reason: null };
|
|
153
|
-
if (exportName === "default" && typeof importedModule === "function") {
|
|
154
|
-
return {
|
|
155
|
-
constructor: (path: string): unknown => Reflect.construct(importedModule, [path]),
|
|
156
|
-
reason: null,
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
return { constructor: null, reason: `${moduleName} did not expose ${exportName}` };
|
|
160
|
-
} catch (err) {
|
|
161
|
-
return { constructor: null, reason: String(err) };
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
async function loadSqliteConstructor(): Promise<SqliteConstructorResult> {
|
|
166
|
-
const bunRuntimeDesc = Object.getOwnPropertyDescriptor(process.versions, "bun");
|
|
167
|
-
if (bunRuntimeDesc !== undefined) {
|
|
168
|
-
const bunSqlite = await loadSqliteModuleConstructor(BUN_SQLITE_MODULE_NAME, "Database");
|
|
169
|
-
if (bunSqlite.constructor !== null) return bunSqlite;
|
|
170
|
-
|
|
171
|
-
const betterSqlite = await loadSqliteModuleConstructor(SQLITE_PACKAGE_NAME, "default");
|
|
172
|
-
if (betterSqlite.constructor !== null) return betterSqlite;
|
|
173
|
-
|
|
174
|
-
return {
|
|
175
|
-
constructor: null,
|
|
176
|
-
reason: [bunSqlite.reason, betterSqlite.reason]
|
|
177
|
-
.filter((item): item is string => item !== null)
|
|
178
|
-
.join("; "),
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const betterSqlite = await loadSqliteModuleConstructor(SQLITE_PACKAGE_NAME, "default");
|
|
183
|
-
if (betterSqlite.constructor !== null) return betterSqlite;
|
|
184
|
-
|
|
185
|
-
const bunSqlite = await loadSqliteModuleConstructor(BUN_SQLITE_MODULE_NAME, "Database");
|
|
186
|
-
if (bunSqlite.constructor !== null) return bunSqlite;
|
|
187
|
-
|
|
188
|
-
return {
|
|
189
|
-
constructor: null,
|
|
190
|
-
reason: [betterSqlite.reason, bunSqlite.reason]
|
|
191
|
-
.filter((item): item is string => item !== null)
|
|
192
|
-
.join("; "),
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
function logUnavailableOnce(reason: string): void {
|
|
197
|
-
if (didLogUnavailable) return;
|
|
198
|
-
didLogUnavailable = true;
|
|
199
|
-
logger.warn("[sessionArchive] Optional session archive unavailable:", reason);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
async function openSessionArchiveDb(filePath: string, create: boolean): Promise<unknown | null> {
|
|
203
|
-
if (!create && !existsSync(filePath)) return null;
|
|
204
|
-
|
|
205
|
-
const sqliteConstructor = await loadSqliteConstructor();
|
|
206
|
-
if (sqliteConstructor.constructor === null) {
|
|
207
|
-
logUnavailableOnce(sqliteConstructor.reason ?? "SQLite runtime is not available");
|
|
208
|
-
return null;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
try {
|
|
212
|
-
if (!create && !existsSync(filePath)) return null;
|
|
213
|
-
if (!ensurePrivateDirectorySync(dirname(filePath))) {
|
|
214
|
-
logger.warn("[sessionArchive] Failed to secure archive directory:", dirname(filePath));
|
|
215
|
-
return null;
|
|
216
|
-
}
|
|
217
|
-
const db = sqliteConstructor.constructor(filePath);
|
|
218
|
-
execSql(db, "PRAGMA journal_mode = WAL");
|
|
219
|
-
execSql(db, "PRAGMA synchronous = NORMAL");
|
|
220
|
-
if (!securePrivateFileSync(filePath, true)) {
|
|
221
|
-
closeDatabase(db);
|
|
222
|
-
logger.warn("[sessionArchive] Failed to secure archive database:", filePath);
|
|
223
|
-
return null;
|
|
224
|
-
}
|
|
225
|
-
for (const sidecarPath of [`${filePath}-wal`, `${filePath}-shm`]) {
|
|
226
|
-
if (existsSync(sidecarPath)) void securePrivateFileSync(sidecarPath);
|
|
227
|
-
}
|
|
228
|
-
if (!execSql(db, CREATE_SCHEMA_SQL)) {
|
|
229
|
-
closeDatabase(db);
|
|
230
|
-
logger.warn("[sessionArchive] Failed to initialize schema:", filePath);
|
|
231
|
-
return null;
|
|
232
|
-
}
|
|
233
|
-
return db;
|
|
234
|
-
} catch (err) {
|
|
235
|
-
logger.warn("[sessionArchive] Failed to open session archive:", filePath, String(err));
|
|
236
|
-
return null;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
export async function archiveSessionLogs(logs: readonly CapturedLog[]): Promise<number> {
|
|
241
|
-
const bySession = new Map<string, CapturedLog[]>();
|
|
242
|
-
for (const log of logs) {
|
|
243
|
-
const sessionId = log.sessionId;
|
|
244
|
-
if (sessionId === null || sessionId.trim().length === 0) continue;
|
|
245
|
-
const existing = bySession.get(sessionId);
|
|
246
|
-
if (existing === undefined) bySession.set(sessionId, [log]);
|
|
247
|
-
else existing.push(log);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
let archivedCount = 0;
|
|
251
|
-
for (const [sessionId, sessionLogs] of bySession) {
|
|
252
|
-
const db = await openSessionArchiveDb(getSessionArchivePath(sessionId), true);
|
|
253
|
-
if (db === null || !execSql(db, "BEGIN IMMEDIATE")) {
|
|
254
|
-
if (db !== null) closeDatabase(db);
|
|
255
|
-
continue;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
let committed = false;
|
|
259
|
-
try {
|
|
260
|
-
const updatedAt = new Date().toISOString();
|
|
261
|
-
const archived = sessionLogs.every((log) =>
|
|
262
|
-
runPrepared(db, UPSERT_SQL, [log.id, sessionId, JSON.stringify(log), updatedAt]),
|
|
263
|
-
);
|
|
264
|
-
if (archived && execSql(db, "COMMIT")) {
|
|
265
|
-
committed = true;
|
|
266
|
-
archivedCount += sessionLogs.length;
|
|
267
|
-
if (cachedArchiveMax?.root === getSessionArchiveRoot()) {
|
|
268
|
-
for (const log of sessionLogs) {
|
|
269
|
-
cachedArchiveMax.maxId = Math.max(cachedArchiveMax.maxId, log.id);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
} finally {
|
|
274
|
-
if (!committed) void execSql(db, "ROLLBACK");
|
|
275
|
-
closeDatabase(db);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
return archivedCount;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
function readString(row: unknown, name: string): string | null {
|
|
282
|
-
const value = readProperty(row, name);
|
|
283
|
-
return typeof value === "string" ? value : null;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
function readNumber(row: unknown, name: string): number | null {
|
|
287
|
-
const value = readProperty(row, name);
|
|
288
|
-
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
function logFromJson(value: string | null): CapturedLog | null {
|
|
292
|
-
if (value === null) return null;
|
|
293
|
-
try {
|
|
294
|
-
const parsed: unknown = JSON.parse(value);
|
|
295
|
-
const result = CapturedLogSchema.safeParse(parsed);
|
|
296
|
-
return result.success ? result.data : null;
|
|
297
|
-
} catch {
|
|
298
|
-
return null;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
function logsFromRows(rows: readonly unknown[]): CapturedLog[] {
|
|
303
|
-
const logs: CapturedLog[] = [];
|
|
304
|
-
for (const row of rows) {
|
|
305
|
-
const log = logFromJson(readString(row, "log_json"));
|
|
306
|
-
if (log !== null) logs.push(log);
|
|
307
|
-
}
|
|
308
|
-
return logs;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
export async function listArchivedSessionLogs(sessionId: string): Promise<CapturedLog[]> {
|
|
312
|
-
const db = await openSessionArchiveDb(getSessionArchivePath(sessionId), false);
|
|
313
|
-
if (db === null) return [];
|
|
314
|
-
|
|
315
|
-
try {
|
|
316
|
-
const rows = allPrepared(
|
|
317
|
-
db,
|
|
318
|
-
"SELECT log_json FROM session_logs WHERE session_id = ? ORDER BY id ASC",
|
|
319
|
-
[sessionId],
|
|
320
|
-
);
|
|
321
|
-
return logsFromRows(rows);
|
|
322
|
-
} finally {
|
|
323
|
-
closeDatabase(db);
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
export async function listArchivedSessionIds(): Promise<string[]> {
|
|
328
|
-
const archivePaths = await listArchiveDatabasePaths();
|
|
329
|
-
const sessionIds = new Set<string>();
|
|
330
|
-
for (const archivePath of archivePaths) {
|
|
331
|
-
const db = await openSessionArchiveDb(archivePath, false);
|
|
332
|
-
if (db === null) continue;
|
|
333
|
-
|
|
334
|
-
try {
|
|
335
|
-
const rows = allPrepared(
|
|
336
|
-
db,
|
|
337
|
-
"SELECT DISTINCT session_id FROM session_logs ORDER BY session_id ASC",
|
|
338
|
-
);
|
|
339
|
-
for (const row of rows) {
|
|
340
|
-
const sessionId = readString(row, "session_id");
|
|
341
|
-
if (sessionId !== null && sessionId.length > 0) sessionIds.add(sessionId);
|
|
342
|
-
}
|
|
343
|
-
} finally {
|
|
344
|
-
closeDatabase(db);
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
return [...sessionIds].sort();
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
async function listArchiveDatabasePaths(): Promise<string[]> {
|
|
351
|
-
const root = getSessionArchiveRoot();
|
|
352
|
-
if (!existsSync(root)) return [];
|
|
353
|
-
|
|
354
|
-
try {
|
|
355
|
-
const entries = await readdir(root, { withFileTypes: true });
|
|
356
|
-
const paths: string[] = [];
|
|
357
|
-
for (const entry of entries) {
|
|
358
|
-
if (!entry.isDirectory()) continue;
|
|
359
|
-
const candidate = join(root, entry.name, SESSION_ARCHIVE_FILE);
|
|
360
|
-
if (existsSync(candidate)) paths.push(candidate);
|
|
361
|
-
}
|
|
362
|
-
return paths;
|
|
363
|
-
} catch (err) {
|
|
364
|
-
logger.warn("[sessionArchive] Failed to list session archives:", String(err));
|
|
365
|
-
return [];
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
* Return the highest ID retained by an authoritative session archive. The global SQLite index is a
|
|
371
|
-
* rebuildable projection and must never influence ID allocation, while archive IDs must remain
|
|
372
|
-
* reserved even after their corresponding global JSONL records have aged out.
|
|
373
|
-
*/
|
|
374
|
-
export async function getSessionArchiveMaxLogId(): Promise<number> {
|
|
375
|
-
const root = getSessionArchiveRoot();
|
|
376
|
-
if (cachedArchiveMax?.root === root) return cachedArchiveMax.maxId;
|
|
377
|
-
|
|
378
|
-
let maxId = 0;
|
|
379
|
-
const archivePaths = await listArchiveDatabasePaths();
|
|
380
|
-
for (const archivePath of archivePaths) {
|
|
381
|
-
const db = await openSessionArchiveDb(archivePath, false);
|
|
382
|
-
if (db === null) continue;
|
|
383
|
-
|
|
384
|
-
try {
|
|
385
|
-
const rows = allPrepared(db, "SELECT MAX(id) AS max_id FROM session_logs");
|
|
386
|
-
const archiveMax = readNumber(rows[0], "max_id");
|
|
387
|
-
if (archiveMax !== null && Number.isSafeInteger(archiveMax) && archiveMax >= 0) {
|
|
388
|
-
maxId = Math.max(maxId, archiveMax);
|
|
389
|
-
}
|
|
390
|
-
} finally {
|
|
391
|
-
closeDatabase(db);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
cachedArchiveMax = { root, maxId };
|
|
396
|
-
return maxId;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
export async function findArchivedLogById(id: number): Promise<CapturedLog | null> {
|
|
400
|
-
const archivePaths = await listArchiveDatabasePaths();
|
|
401
|
-
for (const archivePath of archivePaths) {
|
|
402
|
-
const db = await openSessionArchiveDb(archivePath, false);
|
|
403
|
-
if (db === null) continue;
|
|
404
|
-
|
|
405
|
-
try {
|
|
406
|
-
const rows = allPrepared(db, "SELECT log_json FROM session_logs WHERE id = ? LIMIT 1", [id]);
|
|
407
|
-
const first = logsFromRows(rows)[0];
|
|
408
|
-
if (first !== undefined) return first;
|
|
409
|
-
} finally {
|
|
410
|
-
closeDatabase(db);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
return null;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
function placeholders(count: number): string {
|
|
418
|
-
return Array.from({ length: count }, () => "?").join(", ");
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
function idsFromRows(rows: readonly unknown[]): Set<number> {
|
|
422
|
-
const ids = new Set<number>();
|
|
423
|
-
for (const row of rows) {
|
|
424
|
-
const id = readNumber(row, "id");
|
|
425
|
-
if (id !== null && Number.isInteger(id)) ids.add(id);
|
|
426
|
-
}
|
|
427
|
-
return ids;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
export async function deleteArchivedLogsByIds(ids: ReadonlySet<number>): Promise<Set<number>> {
|
|
431
|
-
if (ids.size === 0) return new Set();
|
|
432
|
-
|
|
433
|
-
const removedIds = new Set<number>();
|
|
434
|
-
const idValues = [...ids];
|
|
435
|
-
const sqlPlaceholders = placeholders(idValues.length);
|
|
436
|
-
const archivePaths = await listArchiveDatabasePaths();
|
|
437
|
-
|
|
438
|
-
for (const archivePath of archivePaths) {
|
|
439
|
-
const db = await openSessionArchiveDb(archivePath, false);
|
|
440
|
-
if (db === null) continue;
|
|
441
|
-
|
|
442
|
-
try {
|
|
443
|
-
const matchingRows = allPrepared(
|
|
444
|
-
db,
|
|
445
|
-
`SELECT id FROM session_logs WHERE id IN (${sqlPlaceholders})`,
|
|
446
|
-
idValues,
|
|
447
|
-
);
|
|
448
|
-
const matchingIds = idsFromRows(matchingRows);
|
|
449
|
-
if (matchingIds.size === 0) continue;
|
|
450
|
-
|
|
451
|
-
if (runPrepared(db, `DELETE FROM session_logs WHERE id IN (${sqlPlaceholders})`, idValues)) {
|
|
452
|
-
for (const id of matchingIds) {
|
|
453
|
-
removedIds.add(id);
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
} finally {
|
|
457
|
-
closeDatabase(db);
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
if (removedIds.size > 0) cachedArchiveMax = null;
|
|
462
|
-
|
|
463
|
-
return removedIds;
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
export async function clearSessionArchives(): Promise<number> {
|
|
467
|
-
const root = getSessionArchiveRoot();
|
|
468
|
-
if (!existsSync(root)) return 0;
|
|
469
|
-
|
|
470
|
-
const archivePaths = await listArchiveDatabasePaths();
|
|
471
|
-
try {
|
|
472
|
-
await rm(root, { recursive: true, force: true });
|
|
473
|
-
cachedArchiveMax = null;
|
|
474
|
-
return archivePaths.length;
|
|
475
|
-
} catch (err) {
|
|
476
|
-
logger.warn("[sessionArchive] Failed to clear session archives:", String(err));
|
|
477
|
-
return 0;
|
|
478
|
-
}
|
|
479
|
-
}
|