diff --git a/src/main/ai-vault/deletion/session-delete-target.ts b/src/main/ai-vault/deletion/session-delete-target.ts index a935f813314..3efb816883f 100644 --- a/src/main/ai-vault/deletion/session-delete-target.ts +++ b/src/main/ai-vault/deletion/session-delete-target.ts @@ -14,9 +14,11 @@ import { type ExecutionHostId } from '../../../shared/execution-host' import { isPathInsideOrEqual } from '../../../shared/cross-platform-path' -import { AI_VAULT_AGENT_SOURCES } from '../discovery/session-scanner-agent-sources' +import { + AI_VAULT_AGENT_SOURCES, + sessionRowRootDirs +} from '../discovery/session-scanner-agent-sources' import { isDiscoverableSessionFile } from '../discovery/session-file-discovery' -import { sessionRowRootDirs } from '../discovery/session-scanner-agent-sources' import { subagentTranscriptsDirFor } from '../scanners/claude/session-scanner-subagent-transcripts' import type { AiVaultScanOptions } from '../session-scanner-types' diff --git a/src/main/ai-vault/discovery/session-path-absence.ts b/src/main/ai-vault/discovery/session-path-absence.ts new file mode 100644 index 00000000000..ef5aae3969f --- /dev/null +++ b/src/main/ai-vault/discovery/session-path-absence.ts @@ -0,0 +1,13 @@ +import { WslTranscriptFsError } from '../../native-chat/wsl-transcript-fs-error' + +/** A missing file or folder is absence, not a refusal; WSL gate errors are always refusals. */ +export function isMissingTranscriptPathError(error: unknown): boolean { + if (error instanceof WslTranscriptFsError) { + return false + } + const code = + error && typeof error === 'object' && 'code' in error && typeof error.code === 'string' + ? error.code + : null + return code === 'ENOENT' || code === 'ENOTDIR' +} diff --git a/src/main/ai-vault/discovery/session-scanner-discovery.ts b/src/main/ai-vault/discovery/session-scanner-discovery.ts index b0a3939bfa5..4af6f505fe9 100644 --- a/src/main/ai-vault/discovery/session-scanner-discovery.ts +++ b/src/main/ai-vault/discovery/session-scanner-discovery.ts @@ -5,8 +5,10 @@ import { PrioritySemaphore } from '../../../shared/priority-semaphore' import { isWslUncPath } from '../../../shared/wsl-paths' import { SessionNewestFiles } from './session-newest-files' import type { SessionSidecarObservation } from '../parse-cache/session-sidecar-stat' -import type { AiVaultAgent } from '../../../shared/ai-vault/contracts/ai-vault-types' -import type { AiVaultScanIssue } from '../../../shared/ai-vault/contracts/ai-vault-types' +import type { + AiVaultAgent, + AiVaultScanIssue +} from '../../../shared/ai-vault/contracts/ai-vault-types' import { wslGatedReaddir, wslGatedStat } from '../../native-chat/wsl-transcript-fs-access' import { WslTranscriptFsError } from '../../native-chat/wsl-transcript-fs-error' import { recordSessionScanIssue, scanIssueTextFromError } from '../parsing/session-scan-issues' @@ -23,6 +25,7 @@ import { noteAiVaultScanWorkChanged, openAiVaultScanSource } from '../scan-lifecycle/ai-vault-scan-progress' +import { isMissingTranscriptPathError } from './session-path-absence' const NATIVE_DISCOVERY_CONCURRENCY = 4 const NATIVE_DISCOVERY_BATCH_SIZE = 16 @@ -251,18 +254,6 @@ async function observeSessionSidecar( } } -/** A missing file or folder is absence, not a refusal; WSL gate errors are always refusals. */ -export function isMissingTranscriptPathError(error: unknown): boolean { - if (error instanceof WslTranscriptFsError) { - return false - } - const code = - error && typeof error === 'object' && 'code' in error && typeof error.code === 'string' - ? error.code - : null - return code === 'ENOENT' || code === 'ENOTDIR' -} - /** Collecting form for callers that want every match; bounded scans stream. */ export async function walkSessionFiles( dirPath: string, diff --git a/src/main/ai-vault/parsing/session-scanner-text-normalization.test.ts b/src/main/ai-vault/parsing/session-scanner-text-normalization.test.ts index 79be53c4e0c..3995690fd8d 100644 --- a/src/main/ai-vault/parsing/session-scanner-text-normalization.test.ts +++ b/src/main/ai-vault/parsing/session-scanner-text-normalization.test.ts @@ -2,9 +2,12 @@ import { homedir } from 'node:os' import { join } from 'node:path' import { describe, expect, it } from 'vitest' import { extractFullFirstUserPromptText } from '../prompts/session-scanner-first-user-prompt' -import { extractPreviewContentText } from './session-scanner-text-normalization' +import { + extractPreviewContentText, + normalizePreviewText, + normalizeTitleText +} from './session-scanner-text-normalization' import { primeAgentSessionsDirFromEnv } from '../discovery/agent-session-directories' -import { normalizePreviewText, normalizeTitleText } from './session-scanner-text-normalization' describe('AI Vault session scanner text values', () => { it('normalizes compact title text without surfacing hidden context blocks', () => { diff --git a/src/main/ai-vault/scanners/cline/session-scanner-cline-parser.ts b/src/main/ai-vault/scanners/cline/session-scanner-cline-parser.ts index 93f4749a8be..3e612f46dc8 100644 --- a/src/main/ai-vault/scanners/cline/session-scanner-cline-parser.ts +++ b/src/main/ai-vault/scanners/cline/session-scanner-cline-parser.ts @@ -14,9 +14,8 @@ import { import { addSessionContent } from '../../parsing/session-scanner-messages' import type { FileWithMtime, SessionAccumulator } from '../../session-scanner-types' import type { TranscriptMessageSink } from '../../transcripts/session-transcript-consumers' -import { arrayValue } from '../../parsing/session-record-fields' +import { arrayValue, asRecord } from '../../parsing/session-record-fields' import { extractString } from '../../../../shared/trimmed-string' -import { asRecord } from '../../parsing/session-record-fields' import { extractContentText, normalizeTitleText diff --git a/src/main/ai-vault/scanners/codex/session-scanner-codex-parser.ts b/src/main/ai-vault/scanners/codex/session-scanner-codex-parser.ts index 50e5fbbf1f2..23a03759b4a 100644 --- a/src/main/ai-vault/scanners/codex/session-scanner-codex-parser.ts +++ b/src/main/ai-vault/scanners/codex/session-scanner-codex-parser.ts @@ -37,8 +37,7 @@ import { normalizeCodexUsage, subtractCodexUsage } from '../../parsing/session-scanner-token-values' -import { asRecord } from '../../parsing/session-record-fields' -import { extractGitBranch, extractModel } from '../../parsing/session-record-fields' +import { asRecord, extractGitBranch, extractModel } from '../../parsing/session-record-fields' import { extractString } from '../../../../shared/trimmed-string' import { parseJsonObject } from '../../parsing/session-json-object' import { readCodexTimelineOnlyRecord } from './session-scanner-codex-record-fast-path' diff --git a/src/main/ai-vault/scanners/devin/session-scanner-devin-parser.ts b/src/main/ai-vault/scanners/devin/session-scanner-devin-parser.ts index cd654878f03..190ed724b1e 100644 --- a/src/main/ai-vault/scanners/devin/session-scanner-devin-parser.ts +++ b/src/main/ai-vault/scanners/devin/session-scanner-devin-parser.ts @@ -15,9 +15,8 @@ import { decodeSessionMessage, type DecodedSessionMessage } from '../../transcripts/session-decoded-message' -import { arrayValue } from '../../parsing/session-record-fields' +import { arrayValue, asRecord } from '../../parsing/session-record-fields' import { extractString } from '../../../../shared/trimmed-string' -import { asRecord } from '../../parsing/session-record-fields' import { extractContentText } from '../../parsing/session-scanner-text-normalization' import { numberValue } from '../../parsing/session-scanner-token-values' diff --git a/src/main/ai-vault/scanners/gemini/session-scanner-gemini-parsers.ts b/src/main/ai-vault/scanners/gemini/session-scanner-gemini-parsers.ts index 708cbdf51fb..4a4d3c88b7f 100644 --- a/src/main/ai-vault/scanners/gemini/session-scanner-gemini-parsers.ts +++ b/src/main/ai-vault/scanners/gemini/session-scanner-gemini-parsers.ts @@ -18,10 +18,9 @@ import { updateTimeline } from '../../parsing/session-scanner-accumulator' import { addSessionContent } from '../../parsing/session-scanner-messages' -import { arrayValue } from '../../parsing/session-record-fields' +import { arrayValue, asRecord } from '../../parsing/session-record-fields' import { extractString } from '../../../../shared/trimmed-string' import { parseJsonObject } from '../../parsing/session-json-object' -import { asRecord } from '../../parsing/session-record-fields' import { extractContentText } from '../../parsing/session-scanner-text-normalization' import { tokenTotal } from '../../parsing/session-scanner-token-values' diff --git a/src/main/ai-vault/scanners/hermes/session-scanner-hermes-parser.ts b/src/main/ai-vault/scanners/hermes/session-scanner-hermes-parser.ts index 0ec075b90fa..dbde0e4957e 100644 --- a/src/main/ai-vault/scanners/hermes/session-scanner-hermes-parser.ts +++ b/src/main/ai-vault/scanners/hermes/session-scanner-hermes-parser.ts @@ -11,9 +11,8 @@ import { updateTimeline } from '../../parsing/session-scanner-accumulator' import { addSessionContent } from '../../parsing/session-scanner-messages' -import { arrayValue } from '../../parsing/session-record-fields' +import { arrayValue, asRecord } from '../../parsing/session-record-fields' import { extractString } from '../../../../shared/trimmed-string' -import { asRecord } from '../../parsing/session-record-fields' import { extractContentText } from '../../parsing/session-scanner-text-normalization' import { numberValue } from '../../parsing/session-scanner-token-values' diff --git a/src/main/ai-vault/scanners/jcode/session-scanner-jcode-parser.ts b/src/main/ai-vault/scanners/jcode/session-scanner-jcode-parser.ts index 24cfa283152..a1868042814 100644 --- a/src/main/ai-vault/scanners/jcode/session-scanner-jcode-parser.ts +++ b/src/main/ai-vault/scanners/jcode/session-scanner-jcode-parser.ts @@ -11,9 +11,8 @@ import { updateTimeline } from '../../parsing/session-scanner-accumulator' import { addSessionContent } from '../../parsing/session-scanner-messages' -import { arrayValue } from '../../parsing/session-record-fields' +import { arrayValue, asRecord } from '../../parsing/session-record-fields' import { extractString } from '../../../../shared/trimmed-string' -import { asRecord } from '../../parsing/session-record-fields' import { extractContentText, normalizeTitleText diff --git a/src/main/ai-vault/scanners/kiro/session-scanner-kiro-parser.ts b/src/main/ai-vault/scanners/kiro/session-scanner-kiro-parser.ts index 2360359346f..e5e13484052 100644 --- a/src/main/ai-vault/scanners/kiro/session-scanner-kiro-parser.ts +++ b/src/main/ai-vault/scanners/kiro/session-scanner-kiro-parser.ts @@ -15,10 +15,9 @@ import { consumeCompleteJsonlLines } from '../../parsing/session-scanner-jsonl-r import type { FileWithMtime, SessionAccumulator } from '../../session-scanner-types' import type { TranscriptMessageSink } from '../../transcripts/session-transcript-consumers' import type { SkippedTranscriptRecord } from '../../transcripts/session-transcript-record-budget' -import { arrayValue } from '../../parsing/session-record-fields' +import { arrayValue, asRecord } from '../../parsing/session-record-fields' import { extractString } from '../../../../shared/trimmed-string' import { parseJsonObject } from '../../parsing/session-json-object' -import { asRecord } from '../../parsing/session-record-fields' import { normalizeTitleText } from '../../parsing/session-scanner-text-normalization' type ParserSessionOptions = { diff --git a/src/main/ai-vault/scanners/muse/session-scanner-muse-parser.ts b/src/main/ai-vault/scanners/muse/session-scanner-muse-parser.ts index fdc83bd73bb..f5c09005016 100644 --- a/src/main/ai-vault/scanners/muse/session-scanner-muse-parser.ts +++ b/src/main/ai-vault/scanners/muse/session-scanner-muse-parser.ts @@ -12,11 +12,10 @@ import { } from '../../parsing/session-scanner-accumulator' import { addSessionContent } from '../../parsing/session-scanner-messages' import { museSessionIdFromFilePath } from './session-scanner-muse-paths' -import { arrayValue } from '../../parsing/session-record-fields' +import { arrayValue, asRecord } from '../../parsing/session-record-fields' import { extractString } from '../../../../shared/trimmed-string' import { parseJsonObject } from '../../parsing/session-json-object' import { timestampMs } from '../../parsing/session-record-time' -import { asRecord } from '../../parsing/session-record-fields' import { normalizeTitleText } from '../../parsing/session-scanner-text-normalization' import { numberValue } from '../../parsing/session-scanner-token-values' diff --git a/src/main/ai-vault/scanners/session-scanner-graph-parsers.ts b/src/main/ai-vault/scanners/session-scanner-graph-parsers.ts index bf2aab79d79..3a781b834ca 100644 --- a/src/main/ai-vault/scanners/session-scanner-graph-parsers.ts +++ b/src/main/ai-vault/scanners/session-scanner-graph-parsers.ts @@ -32,12 +32,10 @@ import { updateTimeline } from '../parsing/session-scanner-accumulator' import { addSessionContent } from '../parsing/session-scanner-messages' -import { arrayValue } from '../parsing/session-record-fields' +import { arrayValue, firstString, asRecord } from '../parsing/session-record-fields' import { extractString } from '../../../shared/trimmed-string' -import { firstString } from '../parsing/session-record-fields' import { parseJsonObject } from '../parsing/session-json-object' import { readJsonObjectIfExists } from '../discovery/session-json-file' -import { asRecord } from '../parsing/session-record-fields' import { extractContentText, extractMessageText diff --git a/src/main/ai-vault/scope/session-scanner-scope-discovery.ts b/src/main/ai-vault/scope/session-scanner-scope-discovery.ts index 3404529f903..b07dbab1aac 100644 --- a/src/main/ai-vault/scope/session-scanner-scope-discovery.ts +++ b/src/main/ai-vault/scope/session-scanner-scope-discovery.ts @@ -18,7 +18,7 @@ import type { FileWithMtime } from '../session-scanner-types' import { extractString } from '../../../shared/trimmed-string' import { parseJsonObject } from '../parsing/session-json-object' import { scanIssueTextFromError } from '../parsing/session-scan-issues' -import { isMissingTranscriptPathError } from '../discovery/session-scanner-discovery' +import { isMissingTranscriptPathError } from '../discovery/session-path-absence' import { noteAiVaultScanFileFound } from '../scan-lifecycle/ai-vault-scan-progress' // Limit representative probing when a bucket contains transcripts without cwd records.