@greppleai/grip-agent-core 0.1.5 → 0.1.6

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.
Files changed (61) hide show
  1. package/dist/agent-loop.d.ts.map +1 -1
  2. package/dist/agent-loop.js.map +1 -1
  3. package/dist/agent.d.ts +7 -0
  4. package/dist/agent.d.ts.map +1 -1
  5. package/dist/agent.js +2 -27
  6. package/dist/agent.js.map +1 -1
  7. package/dist/harness/agent-harness.d.ts.map +1 -1
  8. package/dist/harness/agent-harness.js +7 -20
  9. package/dist/harness/agent-harness.js.map +1 -1
  10. package/dist/harness/compaction/branch-summarization.d.ts.map +1 -1
  11. package/dist/harness/compaction/branch-summarization.js.map +1 -1
  12. package/dist/harness/compaction/compaction.d.ts.map +1 -1
  13. package/dist/harness/compaction/compaction.js.map +1 -1
  14. package/dist/harness/compaction/utils.d.ts.map +1 -1
  15. package/dist/harness/compaction/utils.js.map +1 -1
  16. package/dist/harness/env/nodejs.d.ts.map +1 -1
  17. package/dist/harness/env/nodejs.js +0 -3
  18. package/dist/harness/env/nodejs.js.map +1 -1
  19. package/dist/harness/messages.d.ts.map +1 -1
  20. package/dist/harness/messages.js.map +1 -1
  21. package/dist/harness/prompt-templates.d.ts.map +1 -1
  22. package/dist/harness/prompt-templates.js.map +1 -1
  23. package/dist/harness/session/jsonl-errors.d.ts.map +1 -1
  24. package/dist/harness/session/jsonl-errors.js +0 -10
  25. package/dist/harness/session/jsonl-errors.js.map +1 -1
  26. package/dist/harness/session/jsonl-repo.d.ts.map +1 -1
  27. package/dist/harness/session/jsonl-repo.js +1 -4
  28. package/dist/harness/session/jsonl-repo.js.map +1 -1
  29. package/dist/harness/session/jsonl-storage.d.ts.map +1 -1
  30. package/dist/harness/session/jsonl-storage.js +1 -11
  31. package/dist/harness/session/jsonl-storage.js.map +1 -1
  32. package/dist/harness/session/memory-repo.d.ts.map +1 -1
  33. package/dist/harness/session/memory-repo.js +3 -1
  34. package/dist/harness/session/memory-repo.js.map +1 -1
  35. package/dist/harness/session/memory-storage.d.ts.map +1 -1
  36. package/dist/harness/session/memory-storage.js +0 -5
  37. package/dist/harness/session/memory-storage.js.map +1 -1
  38. package/dist/harness/session/repo-utils.d.ts.map +1 -1
  39. package/dist/harness/session/repo-utils.js.map +1 -1
  40. package/dist/harness/session/session.d.ts.map +1 -1
  41. package/dist/harness/session/session.js +0 -1
  42. package/dist/harness/session/session.js.map +1 -1
  43. package/dist/harness/session/uuid.d.ts.map +1 -1
  44. package/dist/harness/session/uuid.js.map +1 -1
  45. package/dist/harness/skills.d.ts.map +1 -1
  46. package/dist/harness/skills.js.map +1 -1
  47. package/dist/harness/system-prompt.d.ts.map +1 -1
  48. package/dist/harness/system-prompt.js.map +1 -1
  49. package/dist/harness/types.d.ts.map +1 -1
  50. package/dist/harness/types.js +0 -13
  51. package/dist/harness/types.js.map +1 -1
  52. package/dist/harness/utils/shell-output.d.ts.map +1 -1
  53. package/dist/harness/utils/shell-output.js.map +1 -1
  54. package/dist/harness/utils/truncate.d.ts.map +1 -1
  55. package/dist/harness/utils/truncate.js.map +1 -1
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/node.d.ts.map +1 -1
  58. package/dist/proxy.d.ts.map +1 -1
  59. package/dist/proxy.js.map +1 -1
  60. package/dist/types.d.ts.map +1 -1
  61. package/package.json +10 -10
@@ -1 +1 @@
1
- {"version":3,"file":"jsonl-repo.js","sourceRoot":"","sources":["../../../src/harness/session/jsonl-repo.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tFileSystem,\n\tJsonlSessionCreateOptions,\n\tJsonlSessionListOptions,\n\tJsonlSessionMetadata,\n\tJsonlSessionRepoApi,\n\tSession,\n\tSessionForkOptions,\n\tSessionTreeEntry,\n} from \"../types.ts\";\nimport { SessionError, toError } from \"../types.ts\";\nimport { JsonlDecodeError, JsonlSessionError } from \"./jsonl-errors.ts\";\nimport {\n\ttype JsonlSessionCreationPhase,\n\ttype JsonlSessionLoadPhase,\n\tJsonlSessionStorage,\n\tloadJsonlSessionMetadata,\n} from \"./jsonl-storage.ts\";\nimport {\n\tcreateSessionId,\n\tcreateTimestamp,\n\tgetEntriesToFork,\n\tgetFileSystemResultOrThrow,\n\ttoSession,\n} from \"./repo-utils.ts\";\n\ntype JsonlSessionRepoFileSystem = Pick<\n\tFileSystem,\n\t| \"cwd\"\n\t| \"absolutePath\"\n\t| \"joinPath\"\n\t| \"readBinaryFile\"\n\t| \"readTextLines\"\n\t| \"writeFile\"\n\t| \"appendFile\"\n\t| \"renameFile\"\n\t| \"fileInfo\"\n\t| \"listDir\"\n\t| \"exists\"\n\t| \"createDir\"\n\t| \"remove\"\n>;\n\n/** Options for constructing a JSONL-backed session repository. */\nexport interface JsonlSessionRepoOptions {\n\tfs: JsonlSessionRepoFileSystem;\n\tsessionsRoot: string;\n}\n\ninterface JsonlSessionCreateDestination {\n\tid: string;\n\tcwd: string;\n}\n\nfunction canonicalClaimCwd(cwd: string): string {\n\tif (!/^[A-Za-z]:[/\\\\]/.test(cwd)) return cwd;\n\treturn `${cwd[0]!.toLowerCase()}:${cwd.slice(2).replaceAll(\"\\\\\", \"/\")}`;\n}\n\nconst SESSION_ID_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;\n\nfunction validateSessionId(id: string): void {\n\tif (!SESSION_ID_PATTERN.test(id)) {\n\t\tthrow new SessionError(\n\t\t\t\"invalid_session\",\n\t\t\t\"Session id must be non-empty, contain only alphanumeric characters, '-', '_', and '.', and start and end with an alphanumeric character\",\n\t\t);\n\t}\n}\n\nfunction encodeCwd(cwd: string): string {\n\treturn `--${cwd.replace(/^[/\\\\]/, \"\").replace(/[/\\\\:]/g, \"-\")}--`;\n}\n\nexport class JsonlSessionRepo implements JsonlSessionRepoApi {\n\tprivate readonly fs: JsonlSessionRepoFileSystem;\n\tprivate readonly sessionsRootInput: string;\n\tprivate readonly activeCreateDestinations = new Set<string>();\n\tprivate sessionsRoot: string | undefined;\n\n\tconstructor(options: JsonlSessionRepoOptions) {\n\t\tthis.fs = options.fs;\n\t\tthis.sessionsRootInput = options.sessionsRoot;\n\t}\n\n\tprivate async getSessionsRoot(): Promise<string> {\n\t\tif (!this.sessionsRoot) {\n\t\t\tthis.sessionsRoot = getFileSystemResultOrThrow(\n\t\t\t\tawait this.fs.absolutePath(this.sessionsRootInput),\n\t\t\t\t`Failed to resolve sessions root ${this.sessionsRootInput}`,\n\t\t\t);\n\t\t}\n\t\treturn this.sessionsRoot;\n\t}\n\n\tprivate async getSessionDir(cwd: string): Promise<string> {\n\t\treturn getFileSystemResultOrThrow(\n\t\t\tawait this.fs.joinPath([await this.getSessionsRoot(), encodeCwd(cwd)]),\n\t\t\t`Failed to resolve session directory for ${cwd}`,\n\t\t);\n\t}\n\n\tprivate async createSessionFilePath(cwd: string, sessionId: string, timestamp: string): Promise<string> {\n\t\treturn getFileSystemResultOrThrow(\n\t\t\tawait this.fs.joinPath([\n\t\t\t\tawait this.getSessionDir(cwd),\n\t\t\t\t`${timestamp.replace(/[:.]/g, \"-\")}_${sessionId}.jsonl`,\n\t\t\t]),\n\t\t\t`Failed to resolve session file path for ${sessionId}`,\n\t\t);\n\t}\n\n\tasync create(options: JsonlSessionCreateOptions): Promise<Session<JsonlSessionMetadata>> {\n\t\tconst destination = await this.resolveCreateDestination(options);\n\t\treturn this.claimCreateDestination(destination, \"create\", async () => {\n\t\t\tconst createdAt = createTimestamp();\n\t\t\tconst sessionDir = await this.getSessionDir(destination.cwd);\n\t\t\tgetFileSystemResultOrThrow(\n\t\t\t\tawait this.fs.createDir(sessionDir, { recursive: true }),\n\t\t\t\t`Failed to create session directory ${sessionDir}`,\n\t\t\t);\n\t\t\tawait this.rejectExistingSessionId(destination);\n\t\t\tconst filePath = await this.createSessionFilePath(destination.cwd, destination.id, createdAt);\n\t\t\tconst storage = await JsonlSessionStorage.create(this.fs, filePath, {\n\t\t\t\tcwd: destination.cwd,\n\t\t\t\tsessionId: destination.id,\n\t\t\t\tparentSessionPath: options.parentSessionPath,\n\t\t\t});\n\t\t\treturn toSession(storage);\n\t\t});\n\t}\n\n\tasync open(metadata: JsonlSessionMetadata): Promise<Session<JsonlSessionMetadata>> {\n\t\treturn this.openWithPhase(metadata, \"open\");\n\t}\n\n\tprivate async openWithPhase(\n\t\tmetadata: JsonlSessionMetadata,\n\t\tphase: JsonlSessionLoadPhase,\n\t): Promise<Session<JsonlSessionMetadata>> {\n\t\tif (\n\t\t\t!getFileSystemResultOrThrow(await this.fs.exists(metadata.path), `Failed to check session ${metadata.path}`)\n\t\t) {\n\t\t\tthrow new SessionError(\"not_found\", `Session not found: ${metadata.path}`);\n\t\t}\n\t\tconst storage = await JsonlSessionStorage.open(this.fs, metadata.path, phase);\n\t\tconst loadedMetadata = await storage.getMetadata();\n\t\tif (loadedMetadata.id !== metadata.id) {\n\t\t\tconst cause = new JsonlDecodeError(\n\t\t\t\t\"state\",\n\t\t\t\t`metadata id ${metadata.id} does not match file header ${loadedMetadata.id}`,\n\t\t\t);\n\t\t\tthrow new JsonlSessionError({\n\t\t\t\tcode: \"invalid_session\",\n\t\t\t\treference: metadata.path,\n\t\t\t\tphase,\n\t\t\t\tline: 1,\n\t\t\t\tbyteOffset: 0,\n\t\t\t\tdecodeKind: cause.decodeKind,\n\t\t\t\tmessage: `Session metadata id ${metadata.id} does not match file header ${loadedMetadata.id}`,\n\t\t\t\tcause,\n\t\t\t});\n\t\t}\n\t\treturn toSession(storage);\n\t}\n\n\tasync list(options: JsonlSessionListOptions = {}): Promise<JsonlSessionMetadata[]> {\n\t\tconst cwd = options.cwd\n\t\t\t? getFileSystemResultOrThrow(\n\t\t\t\t\tawait this.fs.absolutePath(options.cwd),\n\t\t\t\t\t`Failed to resolve session cwd ${options.cwd}`,\n\t\t\t\t)\n\t\t\t: undefined;\n\t\tconst dirs = cwd ? [await this.getSessionDir(cwd)] : await this.listSessionDirs();\n\t\tconst sessions: JsonlSessionMetadata[] = [];\n\t\tfor (const dir of dirs) sessions.push(...(await this.listSessionsInDir(dir, cwd)));\n\t\tsessions.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());\n\t\treturn sessions;\n\t}\n\n\tprivate async listSessionsInDir(dir: string, cwd: string | undefined): Promise<JsonlSessionMetadata[]> {\n\t\tif (!getFileSystemResultOrThrow(await this.fs.exists(dir), `Failed to check session directory ${dir}`)) {\n\t\t\treturn [];\n\t\t}\n\t\tconst files = getFileSystemResultOrThrow(await this.fs.listDir(dir), `Failed to list sessions in ${dir}`).filter(\n\t\t\t(file) => file.kind !== \"directory\" && file.name.endsWith(\".jsonl\"),\n\t\t);\n\t\tconst sessions: JsonlSessionMetadata[] = [];\n\t\tfor (const file of files) {\n\t\t\tconst metadata = await this.loadListableSessionMetadata(file.path);\n\t\t\tif (metadata && (!cwd || canonicalClaimCwd(metadata.cwd) === canonicalClaimCwd(cwd))) sessions.push(metadata);\n\t\t}\n\t\treturn sessions;\n\t}\n\n\tprivate async loadListableSessionMetadata(path: string): Promise<JsonlSessionMetadata | undefined> {\n\t\ttry {\n\t\t\treturn await loadJsonlSessionMetadata(this.fs, path);\n\t\t} catch (error) {\n\t\t\tconst cause = toError(error);\n\t\t\tif (!(cause instanceof SessionError) || cause.code !== \"invalid_session\") throw cause;\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tasync delete(metadata: JsonlSessionMetadata): Promise<void> {\n\t\tgetFileSystemResultOrThrow(\n\t\t\tawait this.fs.remove(metadata.path, { force: true }),\n\t\t\t`Failed to delete session ${metadata.path}`,\n\t\t);\n\t}\n\n\tasync fork(\n\t\tsourceMetadata: JsonlSessionMetadata,\n\t\toptions: JsonlSessionCreateOptions & SessionForkOptions,\n\t): Promise<Session<JsonlSessionMetadata>> {\n\t\tconst source = await this.openWithPhase(sourceMetadata, \"fork\");\n\t\tlet forkedEntries: SessionTreeEntry[];\n\t\ttry {\n\t\t\tforkedEntries = await getEntriesToFork(source.getStorage(), options);\n\t\t} catch (error) {\n\t\t\tconst cause = toError(error);\n\t\t\tthrow new JsonlSessionError({\n\t\t\t\tcode: cause instanceof SessionError ? cause.code : \"invalid_fork_target\",\n\t\t\t\treference: sourceMetadata.path,\n\t\t\t\tphase: \"fork\",\n\t\t\t\tmessage: cause.message,\n\t\t\t\tcause,\n\t\t\t});\n\t\t}\n\t\tconst destination = await this.resolveCreateDestination(options);\n\t\treturn this.claimCreateDestination(destination, \"fork\", async () => {\n\t\t\tconst createdAt = createTimestamp();\n\t\t\tconst sessionDir = await this.getSessionDir(destination.cwd);\n\t\t\tgetFileSystemResultOrThrow(\n\t\t\t\tawait this.fs.createDir(sessionDir, { recursive: true }),\n\t\t\t\t`Failed to create session directory ${sessionDir}`,\n\t\t\t);\n\t\t\tawait this.rejectExistingSessionId(destination, \"fork\");\n\t\t\tconst storage = await JsonlSessionStorage.create(\n\t\t\t\tthis.fs,\n\t\t\t\tawait this.createSessionFilePath(destination.cwd, destination.id, createdAt),\n\t\t\t\t{\n\t\t\t\t\tcwd: destination.cwd,\n\t\t\t\t\tsessionId: destination.id,\n\t\t\t\t\tparentSessionPath: options.parentSessionPath ?? sourceMetadata.path,\n\t\t\t\t\tentries: forkedEntries,\n\t\t\t\t\tphase: \"fork\",\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn toSession(storage);\n\t\t});\n\t}\n\n\tprivate async resolveCreateDestination(options: JsonlSessionCreateOptions): Promise<JsonlSessionCreateDestination> {\n\t\tconst id = options.id ?? createSessionId();\n\t\tvalidateSessionId(id);\n\t\tconst cwd = getFileSystemResultOrThrow(\n\t\t\tawait this.fs.absolutePath(options.cwd),\n\t\t\t`Failed to resolve session cwd ${options.cwd}`,\n\t\t);\n\t\treturn { id, cwd };\n\t}\n\n\tprivate async claimCreateDestination<T>(\n\t\tdestination: JsonlSessionCreateDestination,\n\t\tphase: JsonlSessionCreationPhase,\n\t\toperation: () => Promise<T>,\n\t): Promise<T> {\n\t\tconst key = `${canonicalClaimCwd(destination.cwd)}\\0${destination.id}`;\n\t\tif (this.activeCreateDestinations.has(key)) {\n\t\t\tthrow new JsonlSessionError({\n\t\t\t\tcode: \"already_exists\",\n\t\t\t\treference: `${destination.cwd}#${destination.id}`,\n\t\t\t\tphase,\n\t\t\t\tmessage: `Session already exists: ${destination.id}`,\n\t\t\t\toutcome: \"not_written\",\n\t\t\t});\n\t\t}\n\t\tthis.activeCreateDestinations.add(key);\n\t\ttry {\n\t\t\treturn await operation();\n\t\t} finally {\n\t\t\tthis.activeCreateDestinations.delete(key);\n\t\t}\n\t}\n\n\tprivate async rejectExistingSessionId(\n\t\tdestination: JsonlSessionCreateDestination,\n\t\tphase: JsonlSessionCreationPhase = \"create\",\n\t): Promise<void> {\n\t\tconst existing = (await this.list({ cwd: destination.cwd })).find(\n\t\t\t(session) =>\n\t\t\t\tsession.id === destination.id && canonicalClaimCwd(session.cwd) === canonicalClaimCwd(destination.cwd),\n\t\t);\n\t\tif (existing) {\n\t\t\tthrow new JsonlSessionError({\n\t\t\t\tcode: \"already_exists\",\n\t\t\t\treference: existing.path,\n\t\t\t\tphase,\n\t\t\t\tmessage: `Session already exists: ${destination.id}`,\n\t\t\t\toutcome: \"not_written\",\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate async listSessionDirs(): Promise<string[]> {\n\t\tconst sessionsRoot = await this.getSessionsRoot();\n\t\tif (\n\t\t\t!getFileSystemResultOrThrow(\n\t\t\t\tawait this.fs.exists(sessionsRoot),\n\t\t\t\t`Failed to check sessions root ${sessionsRoot}`,\n\t\t\t)\n\t\t) {\n\t\t\treturn [];\n\t\t}\n\t\tconst entries = getFileSystemResultOrThrow(\n\t\t\tawait this.fs.listDir(sessionsRoot),\n\t\t\t`Failed to list sessions root ${sessionsRoot}`,\n\t\t);\n\t\treturn entries.filter((entry) => entry.kind === \"directory\").map((entry) => entry.path);\n\t}\n}\n"]}
1
+ {"version":3,"file":"jsonl-repo.js","sourceRoot":"","sources":["../../../src/harness/session/jsonl-repo.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tFileSystem,\n\tJsonlSessionCreateOptions,\n\tJsonlSessionListOptions,\n\tJsonlSessionMetadata,\n\tJsonlSessionRepoApi,\n\tSession,\n\tSessionForkOptions,\n\tSessionTreeEntry,\n} from \"../types.ts\";\nimport { SessionError, toError } from \"../types.ts\";\nimport { JsonlDecodeError, JsonlSessionError } from \"./jsonl-errors.ts\";\nimport {\n\ttype JsonlSessionCreationPhase,\n\ttype JsonlSessionLoadPhase,\n\tJsonlSessionStorage,\n\tloadJsonlSessionMetadata,\n} from \"./jsonl-storage.ts\";\nimport {\n\tcreateSessionId,\n\tcreateTimestamp,\n\tgetEntriesToFork,\n\tgetFileSystemResultOrThrow,\n\ttoSession,\n} from \"./repo-utils.ts\";\n\ntype JsonlSessionRepoFileSystem = Pick<\n\tFileSystem,\n\t| \"cwd\"\n\t| \"absolutePath\"\n\t| \"joinPath\"\n\t| \"readBinaryFile\"\n\t| \"readTextLines\"\n\t| \"writeFile\"\n\t| \"appendFile\"\n\t| \"renameFile\"\n\t| \"fileInfo\"\n\t| \"listDir\"\n\t| \"exists\"\n\t| \"createDir\"\n\t| \"remove\"\n>;\n\n/** Options for constructing a JSONL-backed session repository. */\nexport interface JsonlSessionRepoOptions {\n\tfs: JsonlSessionRepoFileSystem;\n\tsessionsRoot: string;\n}\n\ninterface JsonlSessionCreateDestination {\n\tid: string;\n\tcwd: string;\n}\n\nfunction canonicalClaimCwd(cwd: string): string {\n\tif (!/^[A-Za-z]:[/\\\\]/.test(cwd)) return cwd;\n\treturn `${cwd[0]!.toLowerCase()}:${cwd.slice(2).replaceAll(\"\\\\\", \"/\")}`;\n}\n\nconst SESSION_ID_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;\n\nfunction validateSessionId(id: string): void {\n\tif (!SESSION_ID_PATTERN.test(id)) {\n\t\tthrow new SessionError(\n\t\t\t\"invalid_session\",\n\t\t\t\"Session id must be non-empty, contain only alphanumeric characters, '-', '_', and '.', and start and end with an alphanumeric character\",\n\t\t);\n\t}\n}\n\nfunction encodeCwd(cwd: string): string {\n\treturn `--${cwd.replace(/^[/\\\\]/, \"\").replace(/[/\\\\:]/g, \"-\")}--`;\n}\n\nexport class JsonlSessionRepo implements JsonlSessionRepoApi {\n\tprivate readonly fs: JsonlSessionRepoFileSystem;\n\tprivate readonly sessionsRootInput: string;\n\tprivate readonly activeCreateDestinations = new Set<string>();\n\tprivate sessionsRoot: string | undefined;\n\n\tconstructor(options: JsonlSessionRepoOptions) {\n\t\tthis.fs = options.fs;\n\t\tthis.sessionsRootInput = options.sessionsRoot;\n\t}\n\n\tprivate async getSessionsRoot(): Promise<string> {\n\t\tif (!this.sessionsRoot) {\n\t\t\tthis.sessionsRoot = getFileSystemResultOrThrow(\n\t\t\t\tawait this.fs.absolutePath(this.sessionsRootInput),\n\t\t\t\t`Failed to resolve sessions root ${this.sessionsRootInput}`,\n\t\t\t);\n\t\t}\n\t\treturn this.sessionsRoot;\n\t}\n\n\tprivate async getSessionDir(cwd: string): Promise<string> {\n\t\treturn getFileSystemResultOrThrow(\n\t\t\tawait this.fs.joinPath([await this.getSessionsRoot(), encodeCwd(cwd)]),\n\t\t\t`Failed to resolve session directory for ${cwd}`,\n\t\t);\n\t}\n\n\tprivate async createSessionFilePath(cwd: string, sessionId: string, timestamp: string): Promise<string> {\n\t\treturn getFileSystemResultOrThrow(\n\t\t\tawait this.fs.joinPath([\n\t\t\t\tawait this.getSessionDir(cwd),\n\t\t\t\t`${timestamp.replace(/[:.]/g, \"-\")}_${sessionId}.jsonl`,\n\t\t\t]),\n\t\t\t`Failed to resolve session file path for ${sessionId}`,\n\t\t);\n\t}\n\n\tasync create(options: JsonlSessionCreateOptions): Promise<Session<JsonlSessionMetadata>> {\n\t\tconst destination = await this.resolveCreateDestination(options);\n\t\treturn this.claimCreateDestination(destination, \"create\", async () => {\n\t\t\tconst createdAt = createTimestamp();\n\t\t\tconst sessionDir = await this.getSessionDir(destination.cwd);\n\t\t\tgetFileSystemResultOrThrow(\n\t\t\t\tawait this.fs.createDir(sessionDir, { recursive: true }),\n\t\t\t\t`Failed to create session directory ${sessionDir}`,\n\t\t\t);\n\t\t\tawait this.rejectExistingSessionId(destination);\n\t\t\tconst filePath = await this.createSessionFilePath(destination.cwd, destination.id, createdAt);\n\t\t\tconst storage = await JsonlSessionStorage.create(this.fs, filePath, {\n\t\t\t\tcwd: destination.cwd,\n\t\t\t\tsessionId: destination.id,\n\t\t\t\tparentSessionPath: options.parentSessionPath,\n\t\t\t});\n\t\t\treturn toSession(storage);\n\t\t});\n\t}\n\n\tasync open(metadata: JsonlSessionMetadata): Promise<Session<JsonlSessionMetadata>> {\n\t\treturn this.openWithPhase(metadata, \"open\");\n\t}\n\n\tprivate async openWithPhase(\n\t\tmetadata: JsonlSessionMetadata,\n\t\tphase: JsonlSessionLoadPhase,\n\t): Promise<Session<JsonlSessionMetadata>> {\n\t\tif (\n\t\t\t!getFileSystemResultOrThrow(await this.fs.exists(metadata.path), `Failed to check session ${metadata.path}`)\n\t\t) {\n\t\t\tthrow new SessionError(\"not_found\", `Session not found: ${metadata.path}`);\n\t\t}\n\t\tconst storage = await JsonlSessionStorage.open(this.fs, metadata.path, phase);\n\t\tconst loadedMetadata = await storage.getMetadata();\n\t\tif (loadedMetadata.id !== metadata.id) {\n\t\t\tconst cause = new JsonlDecodeError(\n\t\t\t\t\"state\",\n\t\t\t\t`metadata id ${metadata.id} does not match file header ${loadedMetadata.id}`,\n\t\t\t);\n\t\t\tthrow new JsonlSessionError({\n\t\t\t\tcode: \"invalid_session\",\n\t\t\t\treference: metadata.path,\n\t\t\t\tphase,\n\t\t\t\tline: 1,\n\t\t\t\tbyteOffset: 0,\n\t\t\t\tdecodeKind: cause.decodeKind,\n\t\t\t\tmessage: `Session metadata id ${metadata.id} does not match file header ${loadedMetadata.id}`,\n\t\t\t\tcause,\n\t\t\t});\n\t\t}\n\t\treturn toSession(storage);\n\t}\n\n\tasync list(options: JsonlSessionListOptions = {}): Promise<JsonlSessionMetadata[]> {\n\t\tconst cwd = options.cwd\n\t\t\t? getFileSystemResultOrThrow(\n\t\t\t\t\tawait this.fs.absolutePath(options.cwd),\n\t\t\t\t\t`Failed to resolve session cwd ${options.cwd}`,\n\t\t\t\t)\n\t\t\t: undefined;\n\t\tconst dirs = cwd ? [await this.getSessionDir(cwd)] : await this.listSessionDirs();\n\t\tconst sessions: JsonlSessionMetadata[] = [];\n\t\tfor (const dir of dirs) sessions.push(...(await this.listSessionsInDir(dir, cwd)));\n\t\tsessions.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());\n\t\treturn sessions;\n\t}\n\n\tprivate async listSessionsInDir(dir: string, cwd: string | undefined): Promise<JsonlSessionMetadata[]> {\n\t\tif (!getFileSystemResultOrThrow(await this.fs.exists(dir), `Failed to check session directory ${dir}`)) {\n\t\t\treturn [];\n\t\t}\n\t\tconst files = getFileSystemResultOrThrow(await this.fs.listDir(dir), `Failed to list sessions in ${dir}`).filter(\n\t\t\t(file) => file.kind !== \"directory\" && file.name.endsWith(\".jsonl\"),\n\t\t);\n\t\tconst sessions: JsonlSessionMetadata[] = [];\n\t\tfor (const file of files) {\n\t\t\tconst metadata = await this.loadListableSessionMetadata(file.path);\n\t\t\tif (metadata && (!cwd || canonicalClaimCwd(metadata.cwd) === canonicalClaimCwd(cwd))) sessions.push(metadata);\n\t\t}\n\t\treturn sessions;\n\t}\n\n\tprivate async loadListableSessionMetadata(path: string): Promise<JsonlSessionMetadata | undefined> {\n\t\ttry {\n\t\t\treturn await loadJsonlSessionMetadata(this.fs, path);\n\t\t} catch (error) {\n\t\t\tconst cause = toError(error);\n\t\t\tif (!(cause instanceof SessionError) || cause.code !== \"invalid_session\") throw cause;\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tasync delete(metadata: JsonlSessionMetadata): Promise<void> {\n\t\tgetFileSystemResultOrThrow(\n\t\t\tawait this.fs.remove(metadata.path, { force: true }),\n\t\t\t`Failed to delete session ${metadata.path}`,\n\t\t);\n\t}\n\n\tasync fork(\n\t\tsourceMetadata: JsonlSessionMetadata,\n\t\toptions: JsonlSessionCreateOptions & SessionForkOptions,\n\t): Promise<Session<JsonlSessionMetadata>> {\n\t\tconst source = await this.openWithPhase(sourceMetadata, \"fork\");\n\t\tlet forkedEntries: SessionTreeEntry[];\n\t\ttry {\n\t\t\tforkedEntries = await getEntriesToFork(source.getStorage(), options);\n\t\t} catch (error) {\n\t\t\tconst cause = toError(error);\n\t\t\tthrow new JsonlSessionError({\n\t\t\t\tcode: cause instanceof SessionError ? cause.code : \"invalid_fork_target\",\n\t\t\t\treference: sourceMetadata.path,\n\t\t\t\tphase: \"fork\",\n\t\t\t\tmessage: cause.message,\n\t\t\t\tcause,\n\t\t\t});\n\t\t}\n\t\tconst destination = await this.resolveCreateDestination(options);\n\t\treturn this.claimCreateDestination(destination, \"fork\", async () => {\n\t\t\tconst createdAt = createTimestamp();\n\t\t\tconst sessionDir = await this.getSessionDir(destination.cwd);\n\t\t\tgetFileSystemResultOrThrow(\n\t\t\t\tawait this.fs.createDir(sessionDir, { recursive: true }),\n\t\t\t\t`Failed to create session directory ${sessionDir}`,\n\t\t\t);\n\t\t\tawait this.rejectExistingSessionId(destination, \"fork\");\n\t\t\tconst storage = await JsonlSessionStorage.create(\n\t\t\t\tthis.fs,\n\t\t\t\tawait this.createSessionFilePath(destination.cwd, destination.id, createdAt),\n\t\t\t\t{\n\t\t\t\t\tcwd: destination.cwd,\n\t\t\t\t\tsessionId: destination.id,\n\t\t\t\t\tparentSessionPath: options.parentSessionPath ?? sourceMetadata.path,\n\t\t\t\t\tentries: forkedEntries,\n\t\t\t\t\tphase: \"fork\",\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn toSession(storage);\n\t\t});\n\t}\n\n\tprivate async resolveCreateDestination(options: JsonlSessionCreateOptions): Promise<JsonlSessionCreateDestination> {\n\t\tconst id = options.id ?? createSessionId();\n\t\tvalidateSessionId(id);\n\t\tconst cwd = getFileSystemResultOrThrow(\n\t\t\tawait this.fs.absolutePath(options.cwd),\n\t\t\t`Failed to resolve session cwd ${options.cwd}`,\n\t\t);\n\t\treturn { id, cwd };\n\t}\n\n\tprivate async claimCreateDestination<T>(\n\t\tdestination: JsonlSessionCreateDestination,\n\t\tphase: JsonlSessionCreationPhase,\n\t\toperation: () => Promise<T>,\n\t): Promise<T> {\n\t\tconst key = `${canonicalClaimCwd(destination.cwd)}\\0${destination.id}`;\n\t\tif (this.activeCreateDestinations.has(key)) {\n\t\t\tthrow new JsonlSessionError({\n\t\t\t\tcode: \"already_exists\",\n\t\t\t\treference: `${destination.cwd}#${destination.id}`,\n\t\t\t\tphase,\n\t\t\t\tmessage: `Session already exists: ${destination.id}`,\n\t\t\t\toutcome: \"not_written\",\n\t\t\t});\n\t\t}\n\t\tthis.activeCreateDestinations.add(key);\n\t\ttry {\n\t\t\treturn await operation();\n\t\t} finally {\n\t\t\tthis.activeCreateDestinations.delete(key);\n\t\t}\n\t}\n\n\tprivate async rejectExistingSessionId(\n\t\tdestination: JsonlSessionCreateDestination,\n\t\tphase: JsonlSessionCreationPhase = \"create\",\n\t): Promise<void> {\n\t\tconst existing = (await this.list({ cwd: destination.cwd })).find(\n\t\t\t(session) =>\n\t\t\t\tsession.id === destination.id && canonicalClaimCwd(session.cwd) === canonicalClaimCwd(destination.cwd),\n\t\t);\n\t\tif (existing) {\n\t\t\tthrow new JsonlSessionError({\n\t\t\t\tcode: \"already_exists\",\n\t\t\t\treference: existing.path,\n\t\t\t\tphase,\n\t\t\t\tmessage: `Session already exists: ${destination.id}`,\n\t\t\t\toutcome: \"not_written\",\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate async listSessionDirs(): Promise<string[]> {\n\t\tconst sessionsRoot = await this.getSessionsRoot();\n\t\tif (\n\t\t\t!getFileSystemResultOrThrow(\n\t\t\t\tawait this.fs.exists(sessionsRoot),\n\t\t\t\t`Failed to check sessions root ${sessionsRoot}`,\n\t\t\t)\n\t\t) {\n\t\t\treturn [];\n\t\t}\n\t\tconst entries = getFileSystemResultOrThrow(\n\t\t\tawait this.fs.listDir(sessionsRoot),\n\t\t\t`Failed to list sessions root ${sessionsRoot}`,\n\t\t);\n\t\treturn entries.filter((entry) => entry.kind === \"directory\").map((entry) => entry.path);\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"jsonl-storage.d.ts","sourceRoot":"","sources":["../../../src/harness/session/jsonl-storage.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tFileError,\n\ttype FileSystem,\n\ttype JsonlSessionMetadata,\n\ttype LeafEntry,\n\tSessionError,\n\ttype SessionStorage,\n\ttype SessionTreeEntry,\n\ttype SessionTreeEntryOfType,\n\ttoError,\n} from \"../types.ts\";\nimport {\n\tJsonlDecodeError as JsonlDecodeFailure,\n\ttype JsonlErrorPhase,\n\tJsonlSessionError,\n\ttype JsonlWriteOutcome,\n} from \"./jsonl-errors.ts\";\nimport { getFileSystemResultOrThrow } from \"./repo-utils.ts\";\nimport { uuidv7 } from \"./uuid.ts\";\n\ntype JsonlSessionStorageFileSystem = Pick<\n\tFileSystem,\n\t\"readBinaryFile\" | \"readTextLines\" | \"writeFile\" | \"appendFile\" | \"renameFile\" | \"fileInfo\" | \"exists\" | \"remove\"\n>;\ntype JsonlSessionMetadataFileSystem = Pick<FileSystem, \"readBinaryFile\" | \"readTextLines\">;\n\nexport type JsonlSessionCreationPhase = \"create\" | \"fork\";\nexport type JsonlSessionLoadPhase = \"open\" | \"fork\";\n\ninterface SessionHeader {\n\ttype: \"session\";\n\tversion: 3;\n\tid: string;\n\ttimestamp: string;\n\tcwd: string;\n\tparentSession?: string;\n}\n\n/** Options for creating a JSONL session storage file. */\nexport interface JsonlSessionStorageCreateOptions {\n\tcwd: string;\n\tsessionId: string;\n\tparentSessionPath?: string;\n\tentries?: SessionTreeEntry[];\n\tphase?: JsonlSessionCreationPhase;\n}\n\nfunction updateLabelCache(labelsById: Map<string, string>, entry: SessionTreeEntry): void {\n\tif (entry.type !== \"label\") return;\n\tconst label = entry.label?.trim();\n\tif (label) {\n\t\tlabelsById.set(entry.targetId, label);\n\t} else {\n\t\tlabelsById.delete(entry.targetId);\n\t}\n}\n\nfunction buildLabelsById(entries: SessionTreeEntry[]): Map<string, string> {\n\tconst labelsById = new Map<string, string>();\n\tfor (const entry of entries) {\n\t\tupdateLabelCache(labelsById, entry);\n\t}\n\treturn labelsById;\n}\n\ninterface SessionEntryIdLookup {\n\thas(id: string): boolean;\n}\n\nfunction generateEntryId(byId: SessionEntryIdLookup): string {\n\tfor (let i = 0; i < 100; i++) {\n\t\t// The uuidv7 prefix is timestamp-derived and nearly constant between calls,\n\t\t// so short ids must come from the random tail.\n\t\tconst id = uuidv7().slice(-8);\n\t\tif (!byId.has(id)) return id;\n\t}\n\treturn uuidv7();\n}\n\nconst SAFE_ID_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Raw JSONL line boundaries shared by session storage implementations. */\nexport interface JsonlPhysicalRecord {\n\tbytes: Uint8Array;\n\tline: number;\n\tstart: number;\n\tterminated: boolean;\n}\n\nfunction splitPhysicalRecords(bytes: Uint8Array): JsonlPhysicalRecord[] {\n\tconst records: JsonlPhysicalRecord[] = [];\n\tlet start = 0;\n\tlet line = 1;\n\tfor (let index = 0; index < bytes.length; index++) {\n\t\tif (bytes[index] !== 0x0a) continue;\n\t\trecords.push({ bytes: bytes.subarray(start, index), line, start, terminated: true });\n\t\tstart = index + 1;\n\t\tline++;\n\t}\n\tif (start < bytes.length) records.push({ bytes: bytes.subarray(start), line, start, terminated: false });\n\treturn records;\n}\n\nfunction decodeRecord(record: JsonlPhysicalRecord): string {\n\tlet bytes = record.bytes;\n\tif (bytes.at(-1) === 0x0d) bytes = bytes.subarray(0, bytes.length - 1);\n\ttry {\n\t\treturn new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes);\n\t} catch (error) {\n\t\tthrow new JsonlDecodeFailure(\"utf8\", \"contains invalid UTF-8\", toError(error));\n\t}\n}\n\nfunction parseJsonObject(record: JsonlPhysicalRecord): Record<string, unknown> {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(decodeRecord(record));\n\t} catch (error) {\n\t\tif (error instanceof JsonlDecodeFailure) throw error;\n\t\tthrow new JsonlDecodeFailure(\"syntax\", \"is not valid JSON\", toError(error));\n\t}\n\tif (!isRecord(parsed)) throw new JsonlDecodeFailure(\"schema\", \"is not a JSON object\");\n\treturn parsed;\n}\n\nfunction invalidSession(\n\tfilePath: string,\n\tmessage: string,\n\tcause?: Error,\n\tphase: JsonlErrorPhase = \"open\",\n): JsonlSessionError {\n\tconst decodeCause = cause instanceof JsonlDecodeFailure ? cause : new JsonlDecodeFailure(\"schema\", message, cause);\n\treturn new JsonlSessionError({\n\t\tcode: \"invalid_session\",\n\t\treference: filePath,\n\t\tphase,\n\t\tline: 1,\n\t\tbyteOffset: 0,\n\t\tdecodeKind: decodeCause.decodeKind,\n\t\tmessage: `Invalid JSONL session file ${filePath}: ${message}`,\n\t\tcause: decodeCause,\n\t});\n}\n\nfunction invalidEntry(\n\tfilePath: string,\n\tlineNumber: number,\n\tmessage: string,\n\tcause?: Error,\n\tbyteOffset?: number,\n\tphase: JsonlErrorPhase = \"open\",\n): JsonlSessionError {\n\tconst decodeCause = cause instanceof JsonlDecodeFailure ? cause : new JsonlDecodeFailure(\"state\", message, cause);\n\treturn new JsonlSessionError({\n\t\tcode: \"invalid_entry\",\n\t\treference: filePath,\n\t\tphase,\n\t\tline: lineNumber,\n\t\tbyteOffset,\n\t\tdecodeKind: decodeCause.decodeKind,\n\t\tmessage: `Invalid JSONL session file ${filePath}: line ${lineNumber} ${message}`,\n\t\tcause: decodeCause,\n\t});\n}\n\nfunction withJsonlPhase(error: JsonlSessionError, phase: JsonlErrorPhase): JsonlSessionError {\n\treturn new JsonlSessionError({\n\t\tcode: error.code,\n\t\treference: error.reference,\n\t\tphase,\n\t\tline: error.line,\n\t\tbyteOffset: error.byteOffset,\n\t\tdecodeKind: error.decodeKind,\n\t\toutcome: error.outcome,\n\t\tmessage: error.message,\n\t\tcause: error.cause instanceof Error ? error.cause : undefined,\n\t});\n}\n\nfunction jsonlStorageError(\n\treference: string,\n\tphase: JsonlErrorPhase,\n\tmessage: string,\n\tcause: Error,\n\toutcome?: JsonlWriteOutcome,\n): JsonlSessionError {\n\tif (cause instanceof JsonlSessionError) return withJsonlPhase(cause, phase);\n\treturn new JsonlSessionError({\n\t\tcode: cause instanceof SessionError ? cause.code : \"storage\",\n\t\treference,\n\t\tphase,\n\t\tmessage: message.includes(cause.message) ? message : `${message}: ${cause.message}`,\n\t\toutcome,\n\t\tcause,\n\t});\n}\n\nfunction parseHeaderRecord(record: JsonlPhysicalRecord, filePath: string): SessionHeader {\n\tlet parsed: Record<string, unknown>;\n\ttry {\n\t\tparsed = parseJsonObject(record);\n\t} catch (error) {\n\t\tthrow invalidSession(filePath, \"first line is not a valid session header\", toError(error));\n\t}\n\tif (parsed.type !== \"session\") throw invalidSession(filePath, \"first line is not a valid session header\");\n\tif (parsed.version !== 3) throw invalidSession(filePath, \"unsupported session version\");\n\tif (typeof parsed.id !== \"string\" || !SAFE_ID_PATTERN.test(parsed.id)) {\n\t\tthrow invalidSession(filePath, \"session header has invalid id\");\n\t}\n\tif (typeof parsed.timestamp !== \"string\" || Number.isNaN(Date.parse(parsed.timestamp))) {\n\t\tthrow invalidSession(filePath, \"session header has invalid timestamp\");\n\t}\n\tif (typeof parsed.cwd !== \"string\" || !parsed.cwd) throw invalidSession(filePath, \"session header is missing cwd\");\n\tif (parsed.parentSession !== undefined && typeof parsed.parentSession !== \"string\") {\n\t\tthrow invalidSession(filePath, \"session header parentSession must be a string\");\n\t}\n\treturn {\n\t\ttype: \"session\",\n\t\tversion: 3,\n\t\tid: parsed.id,\n\t\ttimestamp: parsed.timestamp,\n\t\tcwd: parsed.cwd,\n\t\tparentSession: parsed.parentSession,\n\t};\n}\n\nconst ENTRY_TYPES = new Set<SessionTreeEntry[\"type\"]>([\n\t\"message\",\n\t\"thinking_level_change\",\n\t\"model_change\",\n\t\"compaction\",\n\t\"branch_summary\",\n\t\"custom\",\n\t\"custom_message\",\n\t\"label\",\n\t\"session_info\",\n\t\"leaf\",\n]);\n\nfunction requireString(value: unknown, field: string): string {\n\tif (typeof value !== \"string\" || value.length === 0) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", `has invalid ${field}`);\n\t}\n\treturn value;\n}\n\nfunction requireId(value: unknown, field: string): string {\n\tconst id = requireString(value, field);\n\tif (!SAFE_ID_PATTERN.test(id)) throw new JsonlDecodeFailure(\"schema\", `has invalid ${field}`);\n\treturn id;\n}\n\nfunction requireTimestamp(value: unknown): string {\n\tconst timestamp = requireString(value, \"timestamp\");\n\tif (Number.isNaN(Date.parse(timestamp))) throw new JsonlDecodeFailure(\"schema\", \"has invalid timestamp\");\n\treturn timestamp;\n}\n\nconst MESSAGE_ROLES = new Set([\n\t\"user\",\n\t\"assistant\",\n\t\"toolResult\",\n\t\"bashExecution\",\n\t\"custom\",\n\t\"branchSummary\",\n\t\"compactionSummary\",\n\t\"hookMessage\",\n]);\n\nfunction validateToolResultMessage(value: Record<string, unknown>): void {\n\trequireString(value.toolCallId, \"toolCallId\");\n\trequireString(value.toolName, \"toolName\");\n\tif (typeof value.isError !== \"boolean\") throw new JsonlDecodeFailure(\"schema\", \"has invalid isError\");\n}\n\nfunction validateCustomMessage(value: Record<string, unknown>): void {\n\trequireString(value.customType, \"customType\");\n\tif (typeof value.display !== \"boolean\") throw new JsonlDecodeFailure(\"schema\", \"has invalid display\");\n}\n\nfunction validateBashExecutionMessage(value: Record<string, unknown>): void {\n\trequireString(value.command, \"command\");\n\tif (typeof value.output !== \"string\") throw new JsonlDecodeFailure(\"schema\", \"has invalid output\");\n\tif (typeof value.cancelled !== \"boolean\" || typeof value.truncated !== \"boolean\") {\n\t\tthrow new JsonlDecodeFailure(\"schema\", \"has invalid bash state\");\n\t}\n}\n\nfunction validateSummaryMessage(value: Record<string, unknown>): void {\n\trequireString(value.summary, \"summary\");\n}\n\nfunction validateMessageRolePayload(role: string, value: Record<string, unknown>): void {\n\tswitch (role) {\n\t\tcase \"toolResult\":\n\t\t\tvalidateToolResultMessage(value);\n\t\t\tbreak;\n\t\tcase \"custom\":\n\t\tcase \"hookMessage\":\n\t\t\tvalidateCustomMessage(value);\n\t\t\tbreak;\n\t\tcase \"bashExecution\":\n\t\t\tvalidateBashExecutionMessage(value);\n\t\t\tbreak;\n\t\tcase \"branchSummary\":\n\t\tcase \"compactionSummary\":\n\t\t\tvalidateSummaryMessage(value);\n\t\t\tbreak;\n\t}\n}\n\nfunction validatePersistedMessage(value: unknown): void {\n\tif (!isRecord(value)) throw new JsonlDecodeFailure(\"schema\", \"has invalid message\");\n\tconst role = requireString(value.role, \"message role\");\n\tif (!MESSAGE_ROLES.has(role)) throw new JsonlDecodeFailure(\"schema\", `has unknown message role ${role}`);\n\tif (typeof value.timestamp !== \"number\" || !Number.isFinite(value.timestamp)) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", \"has invalid message timestamp\");\n\t}\n\tif (value.content != null && typeof value.content !== \"string\" && !Array.isArray(value.content)) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", \"has invalid message content\");\n\t}\n\tvalidateMessageRolePayload(role, value);\n}\n\nfunction validateCompactionEntry(value: Record<string, unknown>): void {\n\trequireString(value.summary, \"summary\");\n\trequireId(value.firstKeptEntryId, \"firstKeptEntryId\");\n\tif (typeof value.tokensBefore !== \"number\" || !Number.isFinite(value.tokensBefore)) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", \"has invalid tokensBefore\");\n\t}\n}\n\nfunction validateCustomMessageEntry(value: Record<string, unknown>): void {\n\trequireString(value.customType, \"customType\");\n\tif (value.content != null && typeof value.content !== \"string\" && !Array.isArray(value.content)) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", \"has invalid content\");\n\t}\n\tif (typeof value.display !== \"boolean\") throw new JsonlDecodeFailure(\"schema\", \"has invalid display\");\n}\n\nfunction validateOptionalString(value: unknown, field: string): void {\n\tif (value !== undefined && typeof value !== \"string\") {\n\t\tthrow new JsonlDecodeFailure(\"schema\", `has invalid ${field}`);\n\t}\n}\n\nfunction validateNullableId(value: unknown, field: string): void {\n\tif (value !== null && (typeof value !== \"string\" || !SAFE_ID_PATTERN.test(value))) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", `has invalid ${field}`);\n\t}\n}\n\nfunction validateEntryPayload(type: string, parsed: Record<string, unknown>): void {\n\tswitch (type) {\n\t\tcase \"message\":\n\t\t\tvalidatePersistedMessage(parsed.message);\n\t\t\tbreak;\n\t\tcase \"thinking_level_change\":\n\t\t\trequireString(parsed.thinkingLevel, \"thinkingLevel\");\n\t\t\tbreak;\n\t\tcase \"model_change\":\n\t\t\trequireString(parsed.provider, \"provider\");\n\t\t\trequireString(parsed.modelId, \"modelId\");\n\t\t\tbreak;\n\t\tcase \"compaction\":\n\t\t\tvalidateCompactionEntry(parsed);\n\t\t\tbreak;\n\t\tcase \"branch_summary\":\n\t\t\trequireId(parsed.fromId, \"fromId\");\n\t\t\trequireString(parsed.summary, \"summary\");\n\t\t\tbreak;\n\t\tcase \"custom\":\n\t\t\trequireString(parsed.customType, \"customType\");\n\t\t\tbreak;\n\t\tcase \"custom_message\":\n\t\t\tvalidateCustomMessageEntry(parsed);\n\t\t\tbreak;\n\t\tcase \"label\":\n\t\t\trequireId(parsed.targetId, \"targetId\");\n\t\t\tvalidateOptionalString(parsed.label, \"label\");\n\t\t\tbreak;\n\t\tcase \"session_info\":\n\t\t\tvalidateOptionalString(parsed.name, \"name\");\n\t\t\tbreak;\n\t\tcase \"leaf\":\n\t\t\tvalidateNullableId(parsed.targetId, \"targetId\");\n\t\t\tbreak;\n\t}\n}\n\nfunction parseEntryRecord(record: JsonlPhysicalRecord): SessionTreeEntry {\n\tconst parsed = parseJsonObject(record);\n\tconst type = requireString(parsed.type, \"entry type\");\n\tif (!ENTRY_TYPES.has(type as SessionTreeEntry[\"type\"])) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", `has unknown entry type ${type}`);\n\t}\n\trequireId(parsed.id, \"entry id\");\n\tif (parsed.parentId !== null && (typeof parsed.parentId !== \"string\" || !SAFE_ID_PATTERN.test(parsed.parentId))) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", \"has invalid parentId\");\n\t}\n\trequireTimestamp(parsed.timestamp);\n\tvalidateEntryPayload(type, parsed);\n\treturn parsed as unknown as SessionTreeEntry;\n}\n\nfunction leafIdAfterEntry(entry: SessionTreeEntry): string | null {\n\treturn entry.type === \"leaf\" ? entry.targetId : entry.id;\n}\n\nfunction leafIdAfterEntries(entries: SessionTreeEntry[]): string | null {\n\tlet leafId: string | null = null;\n\tfor (const entry of entries) leafId = leafIdAfterEntry(entry);\n\treturn leafId;\n}\n\nfunction isDefinitelyNotWritten(error: unknown): boolean {\n\tconst cause = error instanceof SessionError ? error.cause : error;\n\treturn cause instanceof FileError && cause.code !== \"unknown\" && cause.code !== \"aborted\";\n}\n\nfunction serializeJsonlSession(header: SessionHeader, entries: SessionTreeEntry[]): string {\n\treturn `${[header, ...entries].map((entry) => JSON.stringify(entry)).join(\"\\n\")}\\n`;\n}\n\nasync function publishJsonlContentAtomicallyUnsafe(\n\tfs: JsonlSessionStorageFileSystem,\n\tfilePath: string,\n\tcontent: string | Uint8Array,\n\tallowReplace: boolean,\n): Promise<void> {\n\tconst destinationInfo = await fs.fileInfo(filePath);\n\tif (destinationInfo.ok) {\n\t\tif (!allowReplace) throw new SessionError(\"already_exists\", `Session already exists: ${filePath}`);\n\t\tif (destinationInfo.value.kind !== \"file\") {\n\t\t\tthrow new SessionError(\"storage\", `Refusing to replace non-file session path: ${filePath}`);\n\t\t}\n\t} else if (destinationInfo.error.code !== \"not_found\") {\n\t\tgetFileSystemResultOrThrow(destinationInfo, `Failed to inspect session destination ${filePath}`);\n\t}\n\n\tlet tempPath: string | undefined;\n\tfor (let attempt = 0; attempt < 100; attempt++) {\n\t\tconst candidate = `${filePath}.${uuidv7()}.tmp`;\n\t\tif (\n\t\t\t!getFileSystemResultOrThrow(await fs.exists(candidate), `Failed to inspect session staging path ${candidate}`)\n\t\t) {\n\t\t\ttempPath = candidate;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (!tempPath) throw new SessionError(\"storage\", `Failed to allocate staging path for session ${filePath}`);\n\n\tlet published = false;\n\ttry {\n\t\ttry {\n\t\t\tgetFileSystemResultOrThrow(await fs.writeFile(tempPath, content), `Failed to stage session ${filePath}`);\n\t\t} catch (error) {\n\t\t\tthrow jsonlStorageError(\n\t\t\t\tfilePath,\n\t\t\t\t\"replace\",\n\t\t\t\t`Failed to stage session ${filePath}`,\n\t\t\t\ttoError(error),\n\t\t\t\t\"not_written\",\n\t\t\t);\n\t\t}\n\t\ttry {\n\t\t\tgetFileSystemResultOrThrow(await fs.renameFile(tempPath, filePath), `Failed to publish session ${filePath}`);\n\t\t} catch (error) {\n\t\t\tthrow jsonlStorageError(\n\t\t\t\tfilePath,\n\t\t\t\t\"replace\",\n\t\t\t\t`Failed to publish session ${filePath}`,\n\t\t\t\ttoError(error),\n\t\t\t\t\"unknown\",\n\t\t\t);\n\t\t}\n\t\tpublished = true;\n\t} finally {\n\t\tif (!published) await fs.remove(tempPath, { force: true });\n\t}\n}\n\nasync function publishJsonlContentAtomically(\n\tfs: JsonlSessionStorageFileSystem,\n\tfilePath: string,\n\tcontent: string | Uint8Array,\n\tallowReplace: boolean,\n\tphase: JsonlErrorPhase = \"replace\",\n): Promise<void> {\n\ttry {\n\t\tawait publishJsonlContentAtomicallyUnsafe(fs, filePath, content, allowReplace);\n\t} catch (error) {\n\t\tconst cause = toError(error);\n\t\tif (cause instanceof JsonlSessionError) {\n\t\t\tthrow new JsonlSessionError({\n\t\t\t\tcode: cause.code,\n\t\t\t\treference: cause.reference,\n\t\t\t\tphase,\n\t\t\t\tmessage: cause.message,\n\t\t\t\toutcome: cause.outcome,\n\t\t\t\tcause: cause.cause instanceof Error ? cause.cause : cause,\n\t\t\t});\n\t\t}\n\t\tthrow jsonlStorageError(filePath, phase, cause.message, cause, \"not_written\");\n\t}\n}\n\nfunction headerToSessionMetadata(header: SessionHeader, path: string): JsonlSessionMetadata {\n\treturn {\n\t\tid: header.id,\n\t\tcreatedAt: header.timestamp,\n\t\tcwd: header.cwd,\n\t\tpath,\n\t\tparentSessionPath: header.parentSession,\n\t};\n}\n\nexport async function loadJsonlSessionMetadata(\n\tfs: JsonlSessionMetadataFileSystem,\n\tfilePath: string,\n): Promise<JsonlSessionMetadata> {\n\tlet firstLine: string;\n\ttry {\n\t\tconst lines = getFileSystemResultOrThrow(\n\t\t\tawait fs.readTextLines(filePath, { maxLines: 1 }),\n\t\t\t`Failed to read session header ${filePath}`,\n\t\t);\n\t\tfirstLine = lines[0] ?? \"\";\n\t} catch (error) {\n\t\tthrow jsonlStorageError(filePath, \"list\", `Failed to read session header ${filePath}`, toError(error));\n\t}\n\tif (!firstLine) throw invalidSession(filePath, \"missing session header\", undefined, \"list\");\n\tlet headerBytes: Uint8Array = new TextEncoder().encode(firstLine);\n\tif (firstLine.includes(\"\\uFFFD\")) {\n\t\tlet bytes: Uint8Array;\n\t\ttry {\n\t\t\tbytes = getFileSystemResultOrThrow(\n\t\t\t\tawait fs.readBinaryFile(filePath),\n\t\t\t\t`Failed to verify session header encoding ${filePath}`,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tthrow jsonlStorageError(\n\t\t\t\tfilePath,\n\t\t\t\t\"list\",\n\t\t\t\t`Failed to verify session header encoding ${filePath}`,\n\t\t\t\ttoError(error),\n\t\t\t);\n\t\t}\n\t\tconst newline = bytes.indexOf(0x0a);\n\t\theaderBytes = newline === -1 ? bytes : bytes.subarray(0, newline);\n\t}\n\ttry {\n\t\treturn headerToSessionMetadata(\n\t\t\tparseHeaderRecord({ bytes: headerBytes, line: 1, start: 0, terminated: true }, filePath),\n\t\t\tfilePath,\n\t\t);\n\t} catch (error) {\n\t\tif (error instanceof JsonlSessionError) throw withJsonlPhase(error, \"list\");\n\t\tthrow error;\n\t}\n}\n\nfunction validateEntryState(\n\tentry: SessionTreeEntry,\n\tentriesById: Map<string, SessionTreeEntry>,\n\tfilePath: string,\n\tline: number,\n\tbyteOffset?: number,\n\tphase: JsonlErrorPhase = \"open\",\n): void {\n\tif (entriesById.has(entry.id)) {\n\t\tthrow invalidEntry(filePath, line, `duplicates entry id ${entry.id}`, undefined, byteOffset, phase);\n\t}\n\tif (entry.parentId !== null && !entriesById.has(entry.parentId)) {\n\t\tthrow invalidEntry(filePath, line, `references missing parent ${entry.parentId}`, undefined, byteOffset, phase);\n\t}\n\tconst targetId =\n\t\tentry.type === \"label\"\n\t\t\t? entry.targetId\n\t\t\t: entry.type === \"compaction\"\n\t\t\t\t? entry.firstKeptEntryId\n\t\t\t\t: entry.type === \"branch_summary\"\n\t\t\t\t\t? entry.fromId\n\t\t\t\t\t: entry.type === \"leaf\"\n\t\t\t\t\t\t? entry.targetId\n\t\t\t\t\t\t: undefined;\n\tif (targetId !== undefined && targetId !== null && !entriesById.has(targetId)) {\n\t\tthrow invalidEntry(filePath, line, `references missing target ${targetId}`, undefined, byteOffset, phase);\n\t}\n\tentriesById.set(entry.id, entry);\n}\n\ninterface JsonlAppendPosition {\n\tnextLine: number;\n\tnextOffset: number;\n}\n\ninterface JsonlEntryRecordResolution {\n\tentry?: SessionTreeEntry;\n\trepairTruncatedTail: boolean;\n}\n\ninterface JsonlStorageLoadResult extends JsonlAppendPosition {\n\theader: SessionHeader;\n\tentries: SessionTreeEntry[];\n\tleafId: string | null;\n}\nfunction getNextAppendPosition(bytes: Uint8Array): JsonlAppendPosition {\n\tlet nextLine = 1;\n\tfor (const byte of bytes) {\n\t\tif (byte === 0x0a) nextLine++;\n\t}\n\treturn { nextLine, nextOffset: bytes.length };\n}\n\nfunction resolveJsonlEntryRecord(\n\trecord: JsonlPhysicalRecord,\n\tisLastRecord: boolean,\n\tfilePath: string,\n\tphase: JsonlErrorPhase,\n): JsonlEntryRecordResolution {\n\tlet line: string;\n\ttry {\n\t\tline = decodeRecord(record);\n\t} catch (error) {\n\t\tconst failure = toError(error);\n\t\tconst isRepairableTail = !record.terminated && isLastRecord && failure instanceof JsonlDecodeFailure;\n\t\tif (isRepairableTail) return { repairTruncatedTail: true };\n\t\tthrow invalidEntry(filePath, record.line, failure.message, failure, record.start, phase);\n\t}\n\tif (!line.trim()) return { repairTruncatedTail: false };\n\ttry {\n\t\treturn { entry: parseEntryRecord(record), repairTruncatedTail: false };\n\t} catch (error) {\n\t\tconst failure = toError(error);\n\t\tconst isRepairableTail =\n\t\t\t!record.terminated && isLastRecord && failure instanceof JsonlDecodeFailure && failure.kind === \"syntax\";\n\t\tif (isRepairableTail) return { repairTruncatedTail: true };\n\t\tthrow invalidEntry(filePath, record.line, failure.message, failure, record.start, phase);\n\t}\n}\n\nasync function loadJsonlStorage(\n\tfs: JsonlSessionStorageFileSystem,\n\tfilePath: string,\n\tphase: JsonlSessionLoadPhase = \"open\",\n): Promise<JsonlStorageLoadResult> {\n\tlet bytes: Uint8Array;\n\ttry {\n\t\tbytes = getFileSystemResultOrThrow(await fs.readBinaryFile(filePath), `Failed to read session ${filePath}`);\n\t} catch (error) {\n\t\tthrow jsonlStorageError(filePath, phase, `Failed to read session ${filePath}`, toError(error));\n\t}\n\tconst records = splitPhysicalRecords(bytes);\n\tif (records.length === 0) throw invalidSession(filePath, \"missing session header\", undefined, phase);\n\tlet header: SessionHeader;\n\ttry {\n\t\theader = parseHeaderRecord(records[0]!, filePath);\n\t} catch (error) {\n\t\tif (error instanceof JsonlSessionError) throw withJsonlPhase(error, phase);\n\t\tthrow error;\n\t}\n\tconst entries: SessionTreeEntry[] = [];\n\tconst entriesById = new Map<string, SessionTreeEntry>();\n\tlet leafId: string | null = null;\n\n\tfor (let index = 1; index < records.length; index++) {\n\t\tconst record = records[index]!;\n\t\tconst resolution = resolveJsonlEntryRecord(record, index === records.length - 1, filePath, phase);\n\t\tif (resolution.repairTruncatedTail) {\n\t\t\tconst repairedBytes = bytes.subarray(0, record.start);\n\t\t\tawait publishJsonlContentAtomically(fs, filePath, repairedBytes, true, \"repair\");\n\t\t\treturn { header, entries, leafId, ...getNextAppendPosition(repairedBytes) };\n\t\t}\n\t\tif (!resolution.entry) continue;\n\t\tvalidateEntryState(resolution.entry, entriesById, filePath, record.line, record.start, phase);\n\t\tentries.push(resolution.entry);\n\t\tleafId = leafIdAfterEntry(resolution.entry);\n\t}\n\n\tif (records.at(-1)?.terminated === false) {\n\t\tconst repaired = new Uint8Array(bytes.length + 1);\n\t\trepaired.set(bytes);\n\t\trepaired[bytes.length] = 0x0a;\n\t\tawait publishJsonlContentAtomically(fs, filePath, repaired, true, \"repair\");\n\t}\n\tconst position = getNextAppendPosition(bytes);\n\tif (records.at(-1)?.terminated === false) {\n\t\tposition.nextLine++;\n\t\tposition.nextOffset++;\n\t}\n\treturn { header, entries, leafId, ...position };\n}\n\nexport class JsonlSessionStorage implements SessionStorage<JsonlSessionMetadata> {\n\tprivate readonly fs: JsonlSessionStorageFileSystem;\n\tprivate readonly filePath: string;\n\tprivate readonly metadata: JsonlSessionMetadata;\n\tprivate entries: SessionTreeEntry[];\n\tprivate byId: Map<string, SessionTreeEntry>;\n\tprivate labelsById: Map<string, string>;\n\tprivate currentLeafId: string | null;\n\tprivate appendQueue: Promise<void> = Promise.resolve();\n\tprivate writeFence: JsonlSessionError | undefined;\n\tprivate nextAppendLine: number;\n\tprivate nextAppendOffset: number;\n\n\tprivate constructor(\n\t\tfs: JsonlSessionStorageFileSystem,\n\t\tfilePath: string,\n\t\theader: SessionHeader,\n\t\tentries: SessionTreeEntry[],\n\t\tleafId: string | null,\n\t\tnextAppendLine: number,\n\t\tnextAppendOffset: number,\n\t) {\n\t\tthis.fs = fs;\n\t\tthis.filePath = filePath;\n\t\tthis.metadata = headerToSessionMetadata(header, this.filePath);\n\t\tthis.entries = entries;\n\t\tthis.byId = new Map(entries.map((entry) => [entry.id, entry]));\n\t\tthis.labelsById = buildLabelsById(entries);\n\t\tthis.currentLeafId = leafId;\n\t\tthis.nextAppendLine = nextAppendLine;\n\t\tthis.nextAppendOffset = nextAppendOffset;\n\t}\n\n\tstatic async open(\n\t\tfs: JsonlSessionStorageFileSystem,\n\t\tfilePath: string,\n\t\tphase: JsonlSessionLoadPhase = \"open\",\n\t): Promise<JsonlSessionStorage> {\n\t\tconst loaded = await loadJsonlStorage(fs, filePath, phase);\n\t\treturn new JsonlSessionStorage(\n\t\t\tfs,\n\t\t\tfilePath,\n\t\t\tloaded.header,\n\t\t\tloaded.entries,\n\t\t\tloaded.leafId,\n\t\t\tloaded.nextLine,\n\t\t\tloaded.nextOffset,\n\t\t);\n\t}\n\n\tstatic async create(\n\t\tfs: JsonlSessionStorageFileSystem,\n\t\tfilePath: string,\n\t\toptions: JsonlSessionStorageCreateOptions,\n\t): Promise<JsonlSessionStorage> {\n\t\tconst header: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tversion: 3,\n\t\t\tid: options.sessionId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcwd: options.cwd,\n\t\t\tparentSession: options.parentSessionPath,\n\t\t};\n\t\tconst entries = [...(options.entries ?? [])];\n\t\tconst serialized = serializeJsonlSession(header, entries);\n\t\tawait publishJsonlContentAtomically(fs, filePath, serialized, false, options.phase ?? \"create\");\n\t\tconst position = getNextAppendPosition(new TextEncoder().encode(serialized));\n\t\treturn new JsonlSessionStorage(\n\t\t\tfs,\n\t\t\tfilePath,\n\t\t\theader,\n\t\t\tentries,\n\t\t\tleafIdAfterEntries(entries),\n\t\t\tposition.nextLine,\n\t\t\tposition.nextOffset,\n\t\t);\n\t}\n\n\tasync getMetadata(): Promise<JsonlSessionMetadata> {\n\t\treturn this.metadata;\n\t}\n\n\tasync getLeafId(): Promise<string | null> {\n\t\tif (this.currentLeafId !== null && !this.byId.has(this.currentLeafId)) {\n\t\t\tthrow new SessionError(\"invalid_session\", `Entry ${this.currentLeafId} not found`);\n\t\t}\n\t\treturn this.currentLeafId;\n\t}\n\n\tasync setLeafId(leafId: string | null): Promise<void> {\n\t\tif (leafId !== null && !this.byId.has(leafId)) {\n\t\t\tthrow new SessionError(\"not_found\", `Entry ${leafId} not found`);\n\t\t}\n\t\tconst entry: LeafEntry = {\n\t\t\ttype: \"leaf\",\n\t\t\tid: generateEntryId(this.byId),\n\t\t\tparentId: this.currentLeafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\ttargetId: leafId,\n\t\t};\n\t\tawait this.appendSerializedEntry(entry, `Failed to append session leaf ${entry.id}`, () => {\n\t\t\tthis.entries.push(entry);\n\t\t\tthis.byId.set(entry.id, entry);\n\t\t\tthis.currentLeafId = leafId;\n\t\t});\n\t}\n\n\tasync createEntryId(): Promise<string> {\n\t\treturn generateEntryId(this.byId);\n\t}\n\n\tasync appendEntry(entry: SessionTreeEntry): Promise<void> {\n\t\tawait this.appendSerializedEntry(entry, `Failed to append session entry ${entry.id}`, () => {\n\t\t\tthis.entries.push(entry);\n\t\t\tthis.byId.set(entry.id, entry);\n\t\t\tupdateLabelCache(this.labelsById, entry);\n\t\t\tthis.currentLeafId = leafIdAfterEntry(entry);\n\t\t});\n\t}\n\n\tprivate async appendSerializedEntry(entry: SessionTreeEntry, message: string, commit: () => void): Promise<void> {\n\t\tconst serialized = `${JSON.stringify(entry)}\\n`;\n\t\tconst serializedLength = new TextEncoder().encode(serialized).length;\n\t\tconst operation = this.appendQueue.then(async () => {\n\t\t\tvalidateEntryState(\n\t\t\t\tentry,\n\t\t\t\tnew Map(this.byId),\n\t\t\t\tthis.filePath,\n\t\t\t\tthis.nextAppendLine,\n\t\t\t\tthis.nextAppendOffset,\n\t\t\t\t\"append\",\n\t\t\t);\n\t\t\tif (this.writeFence) {\n\t\t\t\tthrow new JsonlSessionError({\n\t\t\t\t\tcode: \"storage\",\n\t\t\t\t\treference: this.filePath,\n\t\t\t\t\tphase: \"append\",\n\t\t\t\t\tmessage: `Session writes are fenced after an ambiguous append failure: ${this.filePath}`,\n\t\t\t\t\toutcome: \"unknown\",\n\t\t\t\t\tcause: this.writeFence,\n\t\t\t\t});\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tgetFileSystemResultOrThrow(await this.fs.appendFile(this.filePath, serialized), message);\n\t\t\t} catch (error) {\n\t\t\t\tconst cause = toError(error);\n\t\t\t\tif (isDefinitelyNotWritten(error)) {\n\t\t\t\t\tthrow jsonlStorageError(this.filePath, \"append\", message, cause, \"not_written\");\n\t\t\t\t}\n\t\t\t\tthis.writeFence = jsonlStorageError(this.filePath, \"append\", message, cause, \"unknown\");\n\t\t\t\tthrow this.writeFence;\n\t\t\t}\n\t\t\tcommit();\n\t\t\tthis.nextAppendLine++;\n\t\t\tthis.nextAppendOffset += serializedLength;\n\t\t});\n\t\tthis.appendQueue = operation.catch(() => {});\n\t\tawait operation;\n\t}\n\n\tasync getEntry(id: string): Promise<SessionTreeEntry | undefined> {\n\t\treturn this.byId.get(id);\n\t}\n\n\tasync findEntries<TType extends SessionTreeEntry[\"type\"]>(\n\t\ttype: TType,\n\t): Promise<Array<SessionTreeEntryOfType<TType>>> {\n\t\treturn this.entries.filter((entry): entry is SessionTreeEntryOfType<TType> => entry.type === type);\n\t}\n\n\tasync getLabel(id: string): Promise<string | undefined> {\n\t\treturn this.labelsById.get(id);\n\t}\n\n\tasync getPathToRoot(leafId: string | null): Promise<SessionTreeEntry[]> {\n\t\tif (leafId === null) return [];\n\t\tconst path: SessionTreeEntry[] = [];\n\t\tlet current = this.byId.get(leafId);\n\t\tif (!current) throw new SessionError(\"not_found\", `Entry ${leafId} not found`);\n\t\twhile (current) {\n\t\t\tpath.unshift(current);\n\t\t\tif (!current.parentId) break;\n\t\t\tconst parent = this.byId.get(current.parentId);\n\t\t\tif (!parent) throw new SessionError(\"invalid_session\", `Entry ${current.parentId} not found`);\n\t\t\tcurrent = parent;\n\t\t}\n\t\treturn path;\n\t}\n\n\tasync getEntries(): Promise<SessionTreeEntry[]> {\n\t\treturn [...this.entries];\n\t}\n}\n"]}
1
+ {"version":3,"file":"jsonl-storage.d.ts","sourceRoot":"","sources":["../../../src/harness/session/jsonl-storage.ts"],"names":[],"mappings":"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"}
@@ -551,18 +551,8 @@ async function loadJsonlStorage(fs, filePath, phase = "open") {
551
551
  return { header, entries, leafId, ...position };
552
552
  }
553
553
  export class JsonlSessionStorage {
554
- fs;
555
- filePath;
556
- metadata;
557
- entries;
558
- byId;
559
- labelsById;
560
- currentLeafId;
561
- appendQueue = Promise.resolve();
562
- writeFence;
563
- nextAppendLine;
564
- nextAppendOffset;
565
554
  constructor(fs, filePath, header, entries, leafId, nextAppendLine, nextAppendOffset) {
555
+ this.appendQueue = Promise.resolve();
566
556
  this.fs = fs;
567
557
  this.filePath = filePath;
568
558
  this.metadata = headerToSessionMetadata(header, this.filePath);
@@ -1 +1 @@
1
- {"version":3,"file":"jsonl-storage.js","sourceRoot":"","sources":["../../../src/harness/session/jsonl-storage.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tFileError,\n\ttype FileSystem,\n\ttype JsonlSessionMetadata,\n\ttype LeafEntry,\n\tSessionError,\n\ttype SessionStorage,\n\ttype SessionTreeEntry,\n\ttype SessionTreeEntryOfType,\n\ttoError,\n} from \"../types.ts\";\nimport {\n\tJsonlDecodeError as JsonlDecodeFailure,\n\ttype JsonlErrorPhase,\n\tJsonlSessionError,\n\ttype JsonlWriteOutcome,\n} from \"./jsonl-errors.ts\";\nimport { getFileSystemResultOrThrow } from \"./repo-utils.ts\";\nimport { uuidv7 } from \"./uuid.ts\";\n\ntype JsonlSessionStorageFileSystem = Pick<\n\tFileSystem,\n\t\"readBinaryFile\" | \"readTextLines\" | \"writeFile\" | \"appendFile\" | \"renameFile\" | \"fileInfo\" | \"exists\" | \"remove\"\n>;\ntype JsonlSessionMetadataFileSystem = Pick<FileSystem, \"readBinaryFile\" | \"readTextLines\">;\n\nexport type JsonlSessionCreationPhase = \"create\" | \"fork\";\nexport type JsonlSessionLoadPhase = \"open\" | \"fork\";\n\ninterface SessionHeader {\n\ttype: \"session\";\n\tversion: 3;\n\tid: string;\n\ttimestamp: string;\n\tcwd: string;\n\tparentSession?: string;\n}\n\n/** Options for creating a JSONL session storage file. */\nexport interface JsonlSessionStorageCreateOptions {\n\tcwd: string;\n\tsessionId: string;\n\tparentSessionPath?: string;\n\tentries?: SessionTreeEntry[];\n\tphase?: JsonlSessionCreationPhase;\n}\n\nfunction updateLabelCache(labelsById: Map<string, string>, entry: SessionTreeEntry): void {\n\tif (entry.type !== \"label\") return;\n\tconst label = entry.label?.trim();\n\tif (label) {\n\t\tlabelsById.set(entry.targetId, label);\n\t} else {\n\t\tlabelsById.delete(entry.targetId);\n\t}\n}\n\nfunction buildLabelsById(entries: SessionTreeEntry[]): Map<string, string> {\n\tconst labelsById = new Map<string, string>();\n\tfor (const entry of entries) {\n\t\tupdateLabelCache(labelsById, entry);\n\t}\n\treturn labelsById;\n}\n\ninterface SessionEntryIdLookup {\n\thas(id: string): boolean;\n}\n\nfunction generateEntryId(byId: SessionEntryIdLookup): string {\n\tfor (let i = 0; i < 100; i++) {\n\t\t// The uuidv7 prefix is timestamp-derived and nearly constant between calls,\n\t\t// so short ids must come from the random tail.\n\t\tconst id = uuidv7().slice(-8);\n\t\tif (!byId.has(id)) return id;\n\t}\n\treturn uuidv7();\n}\n\nconst SAFE_ID_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Raw JSONL line boundaries shared by session storage implementations. */\nexport interface JsonlPhysicalRecord {\n\tbytes: Uint8Array;\n\tline: number;\n\tstart: number;\n\tterminated: boolean;\n}\n\nfunction splitPhysicalRecords(bytes: Uint8Array): JsonlPhysicalRecord[] {\n\tconst records: JsonlPhysicalRecord[] = [];\n\tlet start = 0;\n\tlet line = 1;\n\tfor (let index = 0; index < bytes.length; index++) {\n\t\tif (bytes[index] !== 0x0a) continue;\n\t\trecords.push({ bytes: bytes.subarray(start, index), line, start, terminated: true });\n\t\tstart = index + 1;\n\t\tline++;\n\t}\n\tif (start < bytes.length) records.push({ bytes: bytes.subarray(start), line, start, terminated: false });\n\treturn records;\n}\n\nfunction decodeRecord(record: JsonlPhysicalRecord): string {\n\tlet bytes = record.bytes;\n\tif (bytes.at(-1) === 0x0d) bytes = bytes.subarray(0, bytes.length - 1);\n\ttry {\n\t\treturn new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes);\n\t} catch (error) {\n\t\tthrow new JsonlDecodeFailure(\"utf8\", \"contains invalid UTF-8\", toError(error));\n\t}\n}\n\nfunction parseJsonObject(record: JsonlPhysicalRecord): Record<string, unknown> {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(decodeRecord(record));\n\t} catch (error) {\n\t\tif (error instanceof JsonlDecodeFailure) throw error;\n\t\tthrow new JsonlDecodeFailure(\"syntax\", \"is not valid JSON\", toError(error));\n\t}\n\tif (!isRecord(parsed)) throw new JsonlDecodeFailure(\"schema\", \"is not a JSON object\");\n\treturn parsed;\n}\n\nfunction invalidSession(\n\tfilePath: string,\n\tmessage: string,\n\tcause?: Error,\n\tphase: JsonlErrorPhase = \"open\",\n): JsonlSessionError {\n\tconst decodeCause = cause instanceof JsonlDecodeFailure ? cause : new JsonlDecodeFailure(\"schema\", message, cause);\n\treturn new JsonlSessionError({\n\t\tcode: \"invalid_session\",\n\t\treference: filePath,\n\t\tphase,\n\t\tline: 1,\n\t\tbyteOffset: 0,\n\t\tdecodeKind: decodeCause.decodeKind,\n\t\tmessage: `Invalid JSONL session file ${filePath}: ${message}`,\n\t\tcause: decodeCause,\n\t});\n}\n\nfunction invalidEntry(\n\tfilePath: string,\n\tlineNumber: number,\n\tmessage: string,\n\tcause?: Error,\n\tbyteOffset?: number,\n\tphase: JsonlErrorPhase = \"open\",\n): JsonlSessionError {\n\tconst decodeCause = cause instanceof JsonlDecodeFailure ? cause : new JsonlDecodeFailure(\"state\", message, cause);\n\treturn new JsonlSessionError({\n\t\tcode: \"invalid_entry\",\n\t\treference: filePath,\n\t\tphase,\n\t\tline: lineNumber,\n\t\tbyteOffset,\n\t\tdecodeKind: decodeCause.decodeKind,\n\t\tmessage: `Invalid JSONL session file ${filePath}: line ${lineNumber} ${message}`,\n\t\tcause: decodeCause,\n\t});\n}\n\nfunction withJsonlPhase(error: JsonlSessionError, phase: JsonlErrorPhase): JsonlSessionError {\n\treturn new JsonlSessionError({\n\t\tcode: error.code,\n\t\treference: error.reference,\n\t\tphase,\n\t\tline: error.line,\n\t\tbyteOffset: error.byteOffset,\n\t\tdecodeKind: error.decodeKind,\n\t\toutcome: error.outcome,\n\t\tmessage: error.message,\n\t\tcause: error.cause instanceof Error ? error.cause : undefined,\n\t});\n}\n\nfunction jsonlStorageError(\n\treference: string,\n\tphase: JsonlErrorPhase,\n\tmessage: string,\n\tcause: Error,\n\toutcome?: JsonlWriteOutcome,\n): JsonlSessionError {\n\tif (cause instanceof JsonlSessionError) return withJsonlPhase(cause, phase);\n\treturn new JsonlSessionError({\n\t\tcode: cause instanceof SessionError ? cause.code : \"storage\",\n\t\treference,\n\t\tphase,\n\t\tmessage: message.includes(cause.message) ? message : `${message}: ${cause.message}`,\n\t\toutcome,\n\t\tcause,\n\t});\n}\n\nfunction parseHeaderRecord(record: JsonlPhysicalRecord, filePath: string): SessionHeader {\n\tlet parsed: Record<string, unknown>;\n\ttry {\n\t\tparsed = parseJsonObject(record);\n\t} catch (error) {\n\t\tthrow invalidSession(filePath, \"first line is not a valid session header\", toError(error));\n\t}\n\tif (parsed.type !== \"session\") throw invalidSession(filePath, \"first line is not a valid session header\");\n\tif (parsed.version !== 3) throw invalidSession(filePath, \"unsupported session version\");\n\tif (typeof parsed.id !== \"string\" || !SAFE_ID_PATTERN.test(parsed.id)) {\n\t\tthrow invalidSession(filePath, \"session header has invalid id\");\n\t}\n\tif (typeof parsed.timestamp !== \"string\" || Number.isNaN(Date.parse(parsed.timestamp))) {\n\t\tthrow invalidSession(filePath, \"session header has invalid timestamp\");\n\t}\n\tif (typeof parsed.cwd !== \"string\" || !parsed.cwd) throw invalidSession(filePath, \"session header is missing cwd\");\n\tif (parsed.parentSession !== undefined && typeof parsed.parentSession !== \"string\") {\n\t\tthrow invalidSession(filePath, \"session header parentSession must be a string\");\n\t}\n\treturn {\n\t\ttype: \"session\",\n\t\tversion: 3,\n\t\tid: parsed.id,\n\t\ttimestamp: parsed.timestamp,\n\t\tcwd: parsed.cwd,\n\t\tparentSession: parsed.parentSession,\n\t};\n}\n\nconst ENTRY_TYPES = new Set<SessionTreeEntry[\"type\"]>([\n\t\"message\",\n\t\"thinking_level_change\",\n\t\"model_change\",\n\t\"compaction\",\n\t\"branch_summary\",\n\t\"custom\",\n\t\"custom_message\",\n\t\"label\",\n\t\"session_info\",\n\t\"leaf\",\n]);\n\nfunction requireString(value: unknown, field: string): string {\n\tif (typeof value !== \"string\" || value.length === 0) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", `has invalid ${field}`);\n\t}\n\treturn value;\n}\n\nfunction requireId(value: unknown, field: string): string {\n\tconst id = requireString(value, field);\n\tif (!SAFE_ID_PATTERN.test(id)) throw new JsonlDecodeFailure(\"schema\", `has invalid ${field}`);\n\treturn id;\n}\n\nfunction requireTimestamp(value: unknown): string {\n\tconst timestamp = requireString(value, \"timestamp\");\n\tif (Number.isNaN(Date.parse(timestamp))) throw new JsonlDecodeFailure(\"schema\", \"has invalid timestamp\");\n\treturn timestamp;\n}\n\nconst MESSAGE_ROLES = new Set([\n\t\"user\",\n\t\"assistant\",\n\t\"toolResult\",\n\t\"bashExecution\",\n\t\"custom\",\n\t\"branchSummary\",\n\t\"compactionSummary\",\n\t\"hookMessage\",\n]);\n\nfunction validateToolResultMessage(value: Record<string, unknown>): void {\n\trequireString(value.toolCallId, \"toolCallId\");\n\trequireString(value.toolName, \"toolName\");\n\tif (typeof value.isError !== \"boolean\") throw new JsonlDecodeFailure(\"schema\", \"has invalid isError\");\n}\n\nfunction validateCustomMessage(value: Record<string, unknown>): void {\n\trequireString(value.customType, \"customType\");\n\tif (typeof value.display !== \"boolean\") throw new JsonlDecodeFailure(\"schema\", \"has invalid display\");\n}\n\nfunction validateBashExecutionMessage(value: Record<string, unknown>): void {\n\trequireString(value.command, \"command\");\n\tif (typeof value.output !== \"string\") throw new JsonlDecodeFailure(\"schema\", \"has invalid output\");\n\tif (typeof value.cancelled !== \"boolean\" || typeof value.truncated !== \"boolean\") {\n\t\tthrow new JsonlDecodeFailure(\"schema\", \"has invalid bash state\");\n\t}\n}\n\nfunction validateSummaryMessage(value: Record<string, unknown>): void {\n\trequireString(value.summary, \"summary\");\n}\n\nfunction validateMessageRolePayload(role: string, value: Record<string, unknown>): void {\n\tswitch (role) {\n\t\tcase \"toolResult\":\n\t\t\tvalidateToolResultMessage(value);\n\t\t\tbreak;\n\t\tcase \"custom\":\n\t\tcase \"hookMessage\":\n\t\t\tvalidateCustomMessage(value);\n\t\t\tbreak;\n\t\tcase \"bashExecution\":\n\t\t\tvalidateBashExecutionMessage(value);\n\t\t\tbreak;\n\t\tcase \"branchSummary\":\n\t\tcase \"compactionSummary\":\n\t\t\tvalidateSummaryMessage(value);\n\t\t\tbreak;\n\t}\n}\n\nfunction validatePersistedMessage(value: unknown): void {\n\tif (!isRecord(value)) throw new JsonlDecodeFailure(\"schema\", \"has invalid message\");\n\tconst role = requireString(value.role, \"message role\");\n\tif (!MESSAGE_ROLES.has(role)) throw new JsonlDecodeFailure(\"schema\", `has unknown message role ${role}`);\n\tif (typeof value.timestamp !== \"number\" || !Number.isFinite(value.timestamp)) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", \"has invalid message timestamp\");\n\t}\n\tif (value.content != null && typeof value.content !== \"string\" && !Array.isArray(value.content)) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", \"has invalid message content\");\n\t}\n\tvalidateMessageRolePayload(role, value);\n}\n\nfunction validateCompactionEntry(value: Record<string, unknown>): void {\n\trequireString(value.summary, \"summary\");\n\trequireId(value.firstKeptEntryId, \"firstKeptEntryId\");\n\tif (typeof value.tokensBefore !== \"number\" || !Number.isFinite(value.tokensBefore)) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", \"has invalid tokensBefore\");\n\t}\n}\n\nfunction validateCustomMessageEntry(value: Record<string, unknown>): void {\n\trequireString(value.customType, \"customType\");\n\tif (value.content != null && typeof value.content !== \"string\" && !Array.isArray(value.content)) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", \"has invalid content\");\n\t}\n\tif (typeof value.display !== \"boolean\") throw new JsonlDecodeFailure(\"schema\", \"has invalid display\");\n}\n\nfunction validateOptionalString(value: unknown, field: string): void {\n\tif (value !== undefined && typeof value !== \"string\") {\n\t\tthrow new JsonlDecodeFailure(\"schema\", `has invalid ${field}`);\n\t}\n}\n\nfunction validateNullableId(value: unknown, field: string): void {\n\tif (value !== null && (typeof value !== \"string\" || !SAFE_ID_PATTERN.test(value))) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", `has invalid ${field}`);\n\t}\n}\n\nfunction validateEntryPayload(type: string, parsed: Record<string, unknown>): void {\n\tswitch (type) {\n\t\tcase \"message\":\n\t\t\tvalidatePersistedMessage(parsed.message);\n\t\t\tbreak;\n\t\tcase \"thinking_level_change\":\n\t\t\trequireString(parsed.thinkingLevel, \"thinkingLevel\");\n\t\t\tbreak;\n\t\tcase \"model_change\":\n\t\t\trequireString(parsed.provider, \"provider\");\n\t\t\trequireString(parsed.modelId, \"modelId\");\n\t\t\tbreak;\n\t\tcase \"compaction\":\n\t\t\tvalidateCompactionEntry(parsed);\n\t\t\tbreak;\n\t\tcase \"branch_summary\":\n\t\t\trequireId(parsed.fromId, \"fromId\");\n\t\t\trequireString(parsed.summary, \"summary\");\n\t\t\tbreak;\n\t\tcase \"custom\":\n\t\t\trequireString(parsed.customType, \"customType\");\n\t\t\tbreak;\n\t\tcase \"custom_message\":\n\t\t\tvalidateCustomMessageEntry(parsed);\n\t\t\tbreak;\n\t\tcase \"label\":\n\t\t\trequireId(parsed.targetId, \"targetId\");\n\t\t\tvalidateOptionalString(parsed.label, \"label\");\n\t\t\tbreak;\n\t\tcase \"session_info\":\n\t\t\tvalidateOptionalString(parsed.name, \"name\");\n\t\t\tbreak;\n\t\tcase \"leaf\":\n\t\t\tvalidateNullableId(parsed.targetId, \"targetId\");\n\t\t\tbreak;\n\t}\n}\n\nfunction parseEntryRecord(record: JsonlPhysicalRecord): SessionTreeEntry {\n\tconst parsed = parseJsonObject(record);\n\tconst type = requireString(parsed.type, \"entry type\");\n\tif (!ENTRY_TYPES.has(type as SessionTreeEntry[\"type\"])) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", `has unknown entry type ${type}`);\n\t}\n\trequireId(parsed.id, \"entry id\");\n\tif (parsed.parentId !== null && (typeof parsed.parentId !== \"string\" || !SAFE_ID_PATTERN.test(parsed.parentId))) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", \"has invalid parentId\");\n\t}\n\trequireTimestamp(parsed.timestamp);\n\tvalidateEntryPayload(type, parsed);\n\treturn parsed as unknown as SessionTreeEntry;\n}\n\nfunction leafIdAfterEntry(entry: SessionTreeEntry): string | null {\n\treturn entry.type === \"leaf\" ? entry.targetId : entry.id;\n}\n\nfunction leafIdAfterEntries(entries: SessionTreeEntry[]): string | null {\n\tlet leafId: string | null = null;\n\tfor (const entry of entries) leafId = leafIdAfterEntry(entry);\n\treturn leafId;\n}\n\nfunction isDefinitelyNotWritten(error: unknown): boolean {\n\tconst cause = error instanceof SessionError ? error.cause : error;\n\treturn cause instanceof FileError && cause.code !== \"unknown\" && cause.code !== \"aborted\";\n}\n\nfunction serializeJsonlSession(header: SessionHeader, entries: SessionTreeEntry[]): string {\n\treturn `${[header, ...entries].map((entry) => JSON.stringify(entry)).join(\"\\n\")}\\n`;\n}\n\nasync function publishJsonlContentAtomicallyUnsafe(\n\tfs: JsonlSessionStorageFileSystem,\n\tfilePath: string,\n\tcontent: string | Uint8Array,\n\tallowReplace: boolean,\n): Promise<void> {\n\tconst destinationInfo = await fs.fileInfo(filePath);\n\tif (destinationInfo.ok) {\n\t\tif (!allowReplace) throw new SessionError(\"already_exists\", `Session already exists: ${filePath}`);\n\t\tif (destinationInfo.value.kind !== \"file\") {\n\t\t\tthrow new SessionError(\"storage\", `Refusing to replace non-file session path: ${filePath}`);\n\t\t}\n\t} else if (destinationInfo.error.code !== \"not_found\") {\n\t\tgetFileSystemResultOrThrow(destinationInfo, `Failed to inspect session destination ${filePath}`);\n\t}\n\n\tlet tempPath: string | undefined;\n\tfor (let attempt = 0; attempt < 100; attempt++) {\n\t\tconst candidate = `${filePath}.${uuidv7()}.tmp`;\n\t\tif (\n\t\t\t!getFileSystemResultOrThrow(await fs.exists(candidate), `Failed to inspect session staging path ${candidate}`)\n\t\t) {\n\t\t\ttempPath = candidate;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (!tempPath) throw new SessionError(\"storage\", `Failed to allocate staging path for session ${filePath}`);\n\n\tlet published = false;\n\ttry {\n\t\ttry {\n\t\t\tgetFileSystemResultOrThrow(await fs.writeFile(tempPath, content), `Failed to stage session ${filePath}`);\n\t\t} catch (error) {\n\t\t\tthrow jsonlStorageError(\n\t\t\t\tfilePath,\n\t\t\t\t\"replace\",\n\t\t\t\t`Failed to stage session ${filePath}`,\n\t\t\t\ttoError(error),\n\t\t\t\t\"not_written\",\n\t\t\t);\n\t\t}\n\t\ttry {\n\t\t\tgetFileSystemResultOrThrow(await fs.renameFile(tempPath, filePath), `Failed to publish session ${filePath}`);\n\t\t} catch (error) {\n\t\t\tthrow jsonlStorageError(\n\t\t\t\tfilePath,\n\t\t\t\t\"replace\",\n\t\t\t\t`Failed to publish session ${filePath}`,\n\t\t\t\ttoError(error),\n\t\t\t\t\"unknown\",\n\t\t\t);\n\t\t}\n\t\tpublished = true;\n\t} finally {\n\t\tif (!published) await fs.remove(tempPath, { force: true });\n\t}\n}\n\nasync function publishJsonlContentAtomically(\n\tfs: JsonlSessionStorageFileSystem,\n\tfilePath: string,\n\tcontent: string | Uint8Array,\n\tallowReplace: boolean,\n\tphase: JsonlErrorPhase = \"replace\",\n): Promise<void> {\n\ttry {\n\t\tawait publishJsonlContentAtomicallyUnsafe(fs, filePath, content, allowReplace);\n\t} catch (error) {\n\t\tconst cause = toError(error);\n\t\tif (cause instanceof JsonlSessionError) {\n\t\t\tthrow new JsonlSessionError({\n\t\t\t\tcode: cause.code,\n\t\t\t\treference: cause.reference,\n\t\t\t\tphase,\n\t\t\t\tmessage: cause.message,\n\t\t\t\toutcome: cause.outcome,\n\t\t\t\tcause: cause.cause instanceof Error ? cause.cause : cause,\n\t\t\t});\n\t\t}\n\t\tthrow jsonlStorageError(filePath, phase, cause.message, cause, \"not_written\");\n\t}\n}\n\nfunction headerToSessionMetadata(header: SessionHeader, path: string): JsonlSessionMetadata {\n\treturn {\n\t\tid: header.id,\n\t\tcreatedAt: header.timestamp,\n\t\tcwd: header.cwd,\n\t\tpath,\n\t\tparentSessionPath: header.parentSession,\n\t};\n}\n\nexport async function loadJsonlSessionMetadata(\n\tfs: JsonlSessionMetadataFileSystem,\n\tfilePath: string,\n): Promise<JsonlSessionMetadata> {\n\tlet firstLine: string;\n\ttry {\n\t\tconst lines = getFileSystemResultOrThrow(\n\t\t\tawait fs.readTextLines(filePath, { maxLines: 1 }),\n\t\t\t`Failed to read session header ${filePath}`,\n\t\t);\n\t\tfirstLine = lines[0] ?? \"\";\n\t} catch (error) {\n\t\tthrow jsonlStorageError(filePath, \"list\", `Failed to read session header ${filePath}`, toError(error));\n\t}\n\tif (!firstLine) throw invalidSession(filePath, \"missing session header\", undefined, \"list\");\n\tlet headerBytes: Uint8Array = new TextEncoder().encode(firstLine);\n\tif (firstLine.includes(\"\\uFFFD\")) {\n\t\tlet bytes: Uint8Array;\n\t\ttry {\n\t\t\tbytes = getFileSystemResultOrThrow(\n\t\t\t\tawait fs.readBinaryFile(filePath),\n\t\t\t\t`Failed to verify session header encoding ${filePath}`,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tthrow jsonlStorageError(\n\t\t\t\tfilePath,\n\t\t\t\t\"list\",\n\t\t\t\t`Failed to verify session header encoding ${filePath}`,\n\t\t\t\ttoError(error),\n\t\t\t);\n\t\t}\n\t\tconst newline = bytes.indexOf(0x0a);\n\t\theaderBytes = newline === -1 ? bytes : bytes.subarray(0, newline);\n\t}\n\ttry {\n\t\treturn headerToSessionMetadata(\n\t\t\tparseHeaderRecord({ bytes: headerBytes, line: 1, start: 0, terminated: true }, filePath),\n\t\t\tfilePath,\n\t\t);\n\t} catch (error) {\n\t\tif (error instanceof JsonlSessionError) throw withJsonlPhase(error, \"list\");\n\t\tthrow error;\n\t}\n}\n\nfunction validateEntryState(\n\tentry: SessionTreeEntry,\n\tentriesById: Map<string, SessionTreeEntry>,\n\tfilePath: string,\n\tline: number,\n\tbyteOffset?: number,\n\tphase: JsonlErrorPhase = \"open\",\n): void {\n\tif (entriesById.has(entry.id)) {\n\t\tthrow invalidEntry(filePath, line, `duplicates entry id ${entry.id}`, undefined, byteOffset, phase);\n\t}\n\tif (entry.parentId !== null && !entriesById.has(entry.parentId)) {\n\t\tthrow invalidEntry(filePath, line, `references missing parent ${entry.parentId}`, undefined, byteOffset, phase);\n\t}\n\tconst targetId =\n\t\tentry.type === \"label\"\n\t\t\t? entry.targetId\n\t\t\t: entry.type === \"compaction\"\n\t\t\t\t? entry.firstKeptEntryId\n\t\t\t\t: entry.type === \"branch_summary\"\n\t\t\t\t\t? entry.fromId\n\t\t\t\t\t: entry.type === \"leaf\"\n\t\t\t\t\t\t? entry.targetId\n\t\t\t\t\t\t: undefined;\n\tif (targetId !== undefined && targetId !== null && !entriesById.has(targetId)) {\n\t\tthrow invalidEntry(filePath, line, `references missing target ${targetId}`, undefined, byteOffset, phase);\n\t}\n\tentriesById.set(entry.id, entry);\n}\n\ninterface JsonlAppendPosition {\n\tnextLine: number;\n\tnextOffset: number;\n}\n\ninterface JsonlEntryRecordResolution {\n\tentry?: SessionTreeEntry;\n\trepairTruncatedTail: boolean;\n}\n\ninterface JsonlStorageLoadResult extends JsonlAppendPosition {\n\theader: SessionHeader;\n\tentries: SessionTreeEntry[];\n\tleafId: string | null;\n}\nfunction getNextAppendPosition(bytes: Uint8Array): JsonlAppendPosition {\n\tlet nextLine = 1;\n\tfor (const byte of bytes) {\n\t\tif (byte === 0x0a) nextLine++;\n\t}\n\treturn { nextLine, nextOffset: bytes.length };\n}\n\nfunction resolveJsonlEntryRecord(\n\trecord: JsonlPhysicalRecord,\n\tisLastRecord: boolean,\n\tfilePath: string,\n\tphase: JsonlErrorPhase,\n): JsonlEntryRecordResolution {\n\tlet line: string;\n\ttry {\n\t\tline = decodeRecord(record);\n\t} catch (error) {\n\t\tconst failure = toError(error);\n\t\tconst isRepairableTail = !record.terminated && isLastRecord && failure instanceof JsonlDecodeFailure;\n\t\tif (isRepairableTail) return { repairTruncatedTail: true };\n\t\tthrow invalidEntry(filePath, record.line, failure.message, failure, record.start, phase);\n\t}\n\tif (!line.trim()) return { repairTruncatedTail: false };\n\ttry {\n\t\treturn { entry: parseEntryRecord(record), repairTruncatedTail: false };\n\t} catch (error) {\n\t\tconst failure = toError(error);\n\t\tconst isRepairableTail =\n\t\t\t!record.terminated && isLastRecord && failure instanceof JsonlDecodeFailure && failure.kind === \"syntax\";\n\t\tif (isRepairableTail) return { repairTruncatedTail: true };\n\t\tthrow invalidEntry(filePath, record.line, failure.message, failure, record.start, phase);\n\t}\n}\n\nasync function loadJsonlStorage(\n\tfs: JsonlSessionStorageFileSystem,\n\tfilePath: string,\n\tphase: JsonlSessionLoadPhase = \"open\",\n): Promise<JsonlStorageLoadResult> {\n\tlet bytes: Uint8Array;\n\ttry {\n\t\tbytes = getFileSystemResultOrThrow(await fs.readBinaryFile(filePath), `Failed to read session ${filePath}`);\n\t} catch (error) {\n\t\tthrow jsonlStorageError(filePath, phase, `Failed to read session ${filePath}`, toError(error));\n\t}\n\tconst records = splitPhysicalRecords(bytes);\n\tif (records.length === 0) throw invalidSession(filePath, \"missing session header\", undefined, phase);\n\tlet header: SessionHeader;\n\ttry {\n\t\theader = parseHeaderRecord(records[0]!, filePath);\n\t} catch (error) {\n\t\tif (error instanceof JsonlSessionError) throw withJsonlPhase(error, phase);\n\t\tthrow error;\n\t}\n\tconst entries: SessionTreeEntry[] = [];\n\tconst entriesById = new Map<string, SessionTreeEntry>();\n\tlet leafId: string | null = null;\n\n\tfor (let index = 1; index < records.length; index++) {\n\t\tconst record = records[index]!;\n\t\tconst resolution = resolveJsonlEntryRecord(record, index === records.length - 1, filePath, phase);\n\t\tif (resolution.repairTruncatedTail) {\n\t\t\tconst repairedBytes = bytes.subarray(0, record.start);\n\t\t\tawait publishJsonlContentAtomically(fs, filePath, repairedBytes, true, \"repair\");\n\t\t\treturn { header, entries, leafId, ...getNextAppendPosition(repairedBytes) };\n\t\t}\n\t\tif (!resolution.entry) continue;\n\t\tvalidateEntryState(resolution.entry, entriesById, filePath, record.line, record.start, phase);\n\t\tentries.push(resolution.entry);\n\t\tleafId = leafIdAfterEntry(resolution.entry);\n\t}\n\n\tif (records.at(-1)?.terminated === false) {\n\t\tconst repaired = new Uint8Array(bytes.length + 1);\n\t\trepaired.set(bytes);\n\t\trepaired[bytes.length] = 0x0a;\n\t\tawait publishJsonlContentAtomically(fs, filePath, repaired, true, \"repair\");\n\t}\n\tconst position = getNextAppendPosition(bytes);\n\tif (records.at(-1)?.terminated === false) {\n\t\tposition.nextLine++;\n\t\tposition.nextOffset++;\n\t}\n\treturn { header, entries, leafId, ...position };\n}\n\nexport class JsonlSessionStorage implements SessionStorage<JsonlSessionMetadata> {\n\tprivate readonly fs: JsonlSessionStorageFileSystem;\n\tprivate readonly filePath: string;\n\tprivate readonly metadata: JsonlSessionMetadata;\n\tprivate entries: SessionTreeEntry[];\n\tprivate byId: Map<string, SessionTreeEntry>;\n\tprivate labelsById: Map<string, string>;\n\tprivate currentLeafId: string | null;\n\tprivate appendQueue: Promise<void> = Promise.resolve();\n\tprivate writeFence: JsonlSessionError | undefined;\n\tprivate nextAppendLine: number;\n\tprivate nextAppendOffset: number;\n\n\tprivate constructor(\n\t\tfs: JsonlSessionStorageFileSystem,\n\t\tfilePath: string,\n\t\theader: SessionHeader,\n\t\tentries: SessionTreeEntry[],\n\t\tleafId: string | null,\n\t\tnextAppendLine: number,\n\t\tnextAppendOffset: number,\n\t) {\n\t\tthis.fs = fs;\n\t\tthis.filePath = filePath;\n\t\tthis.metadata = headerToSessionMetadata(header, this.filePath);\n\t\tthis.entries = entries;\n\t\tthis.byId = new Map(entries.map((entry) => [entry.id, entry]));\n\t\tthis.labelsById = buildLabelsById(entries);\n\t\tthis.currentLeafId = leafId;\n\t\tthis.nextAppendLine = nextAppendLine;\n\t\tthis.nextAppendOffset = nextAppendOffset;\n\t}\n\n\tstatic async open(\n\t\tfs: JsonlSessionStorageFileSystem,\n\t\tfilePath: string,\n\t\tphase: JsonlSessionLoadPhase = \"open\",\n\t): Promise<JsonlSessionStorage> {\n\t\tconst loaded = await loadJsonlStorage(fs, filePath, phase);\n\t\treturn new JsonlSessionStorage(\n\t\t\tfs,\n\t\t\tfilePath,\n\t\t\tloaded.header,\n\t\t\tloaded.entries,\n\t\t\tloaded.leafId,\n\t\t\tloaded.nextLine,\n\t\t\tloaded.nextOffset,\n\t\t);\n\t}\n\n\tstatic async create(\n\t\tfs: JsonlSessionStorageFileSystem,\n\t\tfilePath: string,\n\t\toptions: JsonlSessionStorageCreateOptions,\n\t): Promise<JsonlSessionStorage> {\n\t\tconst header: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tversion: 3,\n\t\t\tid: options.sessionId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcwd: options.cwd,\n\t\t\tparentSession: options.parentSessionPath,\n\t\t};\n\t\tconst entries = [...(options.entries ?? [])];\n\t\tconst serialized = serializeJsonlSession(header, entries);\n\t\tawait publishJsonlContentAtomically(fs, filePath, serialized, false, options.phase ?? \"create\");\n\t\tconst position = getNextAppendPosition(new TextEncoder().encode(serialized));\n\t\treturn new JsonlSessionStorage(\n\t\t\tfs,\n\t\t\tfilePath,\n\t\t\theader,\n\t\t\tentries,\n\t\t\tleafIdAfterEntries(entries),\n\t\t\tposition.nextLine,\n\t\t\tposition.nextOffset,\n\t\t);\n\t}\n\n\tasync getMetadata(): Promise<JsonlSessionMetadata> {\n\t\treturn this.metadata;\n\t}\n\n\tasync getLeafId(): Promise<string | null> {\n\t\tif (this.currentLeafId !== null && !this.byId.has(this.currentLeafId)) {\n\t\t\tthrow new SessionError(\"invalid_session\", `Entry ${this.currentLeafId} not found`);\n\t\t}\n\t\treturn this.currentLeafId;\n\t}\n\n\tasync setLeafId(leafId: string | null): Promise<void> {\n\t\tif (leafId !== null && !this.byId.has(leafId)) {\n\t\t\tthrow new SessionError(\"not_found\", `Entry ${leafId} not found`);\n\t\t}\n\t\tconst entry: LeafEntry = {\n\t\t\ttype: \"leaf\",\n\t\t\tid: generateEntryId(this.byId),\n\t\t\tparentId: this.currentLeafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\ttargetId: leafId,\n\t\t};\n\t\tawait this.appendSerializedEntry(entry, `Failed to append session leaf ${entry.id}`, () => {\n\t\t\tthis.entries.push(entry);\n\t\t\tthis.byId.set(entry.id, entry);\n\t\t\tthis.currentLeafId = leafId;\n\t\t});\n\t}\n\n\tasync createEntryId(): Promise<string> {\n\t\treturn generateEntryId(this.byId);\n\t}\n\n\tasync appendEntry(entry: SessionTreeEntry): Promise<void> {\n\t\tawait this.appendSerializedEntry(entry, `Failed to append session entry ${entry.id}`, () => {\n\t\t\tthis.entries.push(entry);\n\t\t\tthis.byId.set(entry.id, entry);\n\t\t\tupdateLabelCache(this.labelsById, entry);\n\t\t\tthis.currentLeafId = leafIdAfterEntry(entry);\n\t\t});\n\t}\n\n\tprivate async appendSerializedEntry(entry: SessionTreeEntry, message: string, commit: () => void): Promise<void> {\n\t\tconst serialized = `${JSON.stringify(entry)}\\n`;\n\t\tconst serializedLength = new TextEncoder().encode(serialized).length;\n\t\tconst operation = this.appendQueue.then(async () => {\n\t\t\tvalidateEntryState(\n\t\t\t\tentry,\n\t\t\t\tnew Map(this.byId),\n\t\t\t\tthis.filePath,\n\t\t\t\tthis.nextAppendLine,\n\t\t\t\tthis.nextAppendOffset,\n\t\t\t\t\"append\",\n\t\t\t);\n\t\t\tif (this.writeFence) {\n\t\t\t\tthrow new JsonlSessionError({\n\t\t\t\t\tcode: \"storage\",\n\t\t\t\t\treference: this.filePath,\n\t\t\t\t\tphase: \"append\",\n\t\t\t\t\tmessage: `Session writes are fenced after an ambiguous append failure: ${this.filePath}`,\n\t\t\t\t\toutcome: \"unknown\",\n\t\t\t\t\tcause: this.writeFence,\n\t\t\t\t});\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tgetFileSystemResultOrThrow(await this.fs.appendFile(this.filePath, serialized), message);\n\t\t\t} catch (error) {\n\t\t\t\tconst cause = toError(error);\n\t\t\t\tif (isDefinitelyNotWritten(error)) {\n\t\t\t\t\tthrow jsonlStorageError(this.filePath, \"append\", message, cause, \"not_written\");\n\t\t\t\t}\n\t\t\t\tthis.writeFence = jsonlStorageError(this.filePath, \"append\", message, cause, \"unknown\");\n\t\t\t\tthrow this.writeFence;\n\t\t\t}\n\t\t\tcommit();\n\t\t\tthis.nextAppendLine++;\n\t\t\tthis.nextAppendOffset += serializedLength;\n\t\t});\n\t\tthis.appendQueue = operation.catch(() => {});\n\t\tawait operation;\n\t}\n\n\tasync getEntry(id: string): Promise<SessionTreeEntry | undefined> {\n\t\treturn this.byId.get(id);\n\t}\n\n\tasync findEntries<TType extends SessionTreeEntry[\"type\"]>(\n\t\ttype: TType,\n\t): Promise<Array<SessionTreeEntryOfType<TType>>> {\n\t\treturn this.entries.filter((entry): entry is SessionTreeEntryOfType<TType> => entry.type === type);\n\t}\n\n\tasync getLabel(id: string): Promise<string | undefined> {\n\t\treturn this.labelsById.get(id);\n\t}\n\n\tasync getPathToRoot(leafId: string | null): Promise<SessionTreeEntry[]> {\n\t\tif (leafId === null) return [];\n\t\tconst path: SessionTreeEntry[] = [];\n\t\tlet current = this.byId.get(leafId);\n\t\tif (!current) throw new SessionError(\"not_found\", `Entry ${leafId} not found`);\n\t\twhile (current) {\n\t\t\tpath.unshift(current);\n\t\t\tif (!current.parentId) break;\n\t\t\tconst parent = this.byId.get(current.parentId);\n\t\t\tif (!parent) throw new SessionError(\"invalid_session\", `Entry ${current.parentId} not found`);\n\t\t\tcurrent = parent;\n\t\t}\n\t\treturn path;\n\t}\n\n\tasync getEntries(): Promise<SessionTreeEntry[]> {\n\t\treturn [...this.entries];\n\t}\n}\n"]}
1
+ {"version":3,"file":"jsonl-storage.js","sourceRoot":"","sources":["../../../src/harness/session/jsonl-storage.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tFileError,\n\ttype FileSystem,\n\ttype JsonlSessionMetadata,\n\ttype LeafEntry,\n\tSessionError,\n\ttype SessionStorage,\n\ttype SessionTreeEntry,\n\ttype SessionTreeEntryOfType,\n\ttoError,\n} from \"../types.ts\";\nimport {\n\tJsonlDecodeError as JsonlDecodeFailure,\n\ttype JsonlErrorPhase,\n\tJsonlSessionError,\n\ttype JsonlWriteOutcome,\n} from \"./jsonl-errors.ts\";\nimport { getFileSystemResultOrThrow } from \"./repo-utils.ts\";\nimport { uuidv7 } from \"./uuid.ts\";\n\ntype JsonlSessionStorageFileSystem = Pick<\n\tFileSystem,\n\t\"readBinaryFile\" | \"readTextLines\" | \"writeFile\" | \"appendFile\" | \"renameFile\" | \"fileInfo\" | \"exists\" | \"remove\"\n>;\ntype JsonlSessionMetadataFileSystem = Pick<FileSystem, \"readBinaryFile\" | \"readTextLines\">;\n\nexport type JsonlSessionCreationPhase = \"create\" | \"fork\";\nexport type JsonlSessionLoadPhase = \"open\" | \"fork\";\n\ninterface SessionHeader {\n\ttype: \"session\";\n\tversion: 3;\n\tid: string;\n\ttimestamp: string;\n\tcwd: string;\n\tparentSession?: string;\n}\n\n/** Options for creating a JSONL session storage file. */\nexport interface JsonlSessionStorageCreateOptions {\n\tcwd: string;\n\tsessionId: string;\n\tparentSessionPath?: string;\n\tentries?: SessionTreeEntry[];\n\tphase?: JsonlSessionCreationPhase;\n}\n\nfunction updateLabelCache(labelsById: Map<string, string>, entry: SessionTreeEntry): void {\n\tif (entry.type !== \"label\") return;\n\tconst label = entry.label?.trim();\n\tif (label) {\n\t\tlabelsById.set(entry.targetId, label);\n\t} else {\n\t\tlabelsById.delete(entry.targetId);\n\t}\n}\n\nfunction buildLabelsById(entries: SessionTreeEntry[]): Map<string, string> {\n\tconst labelsById = new Map<string, string>();\n\tfor (const entry of entries) {\n\t\tupdateLabelCache(labelsById, entry);\n\t}\n\treturn labelsById;\n}\n\ninterface SessionEntryIdLookup {\n\thas(id: string): boolean;\n}\n\nfunction generateEntryId(byId: SessionEntryIdLookup): string {\n\tfor (let i = 0; i < 100; i++) {\n\t\t// The uuidv7 prefix is timestamp-derived and nearly constant between calls,\n\t\t// so short ids must come from the random tail.\n\t\tconst id = uuidv7().slice(-8);\n\t\tif (!byId.has(id)) return id;\n\t}\n\treturn uuidv7();\n}\n\nconst SAFE_ID_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Raw JSONL line boundaries shared by session storage implementations. */\nexport interface JsonlPhysicalRecord {\n\tbytes: Uint8Array;\n\tline: number;\n\tstart: number;\n\tterminated: boolean;\n}\n\nfunction splitPhysicalRecords(bytes: Uint8Array): JsonlPhysicalRecord[] {\n\tconst records: JsonlPhysicalRecord[] = [];\n\tlet start = 0;\n\tlet line = 1;\n\tfor (let index = 0; index < bytes.length; index++) {\n\t\tif (bytes[index] !== 0x0a) continue;\n\t\trecords.push({ bytes: bytes.subarray(start, index), line, start, terminated: true });\n\t\tstart = index + 1;\n\t\tline++;\n\t}\n\tif (start < bytes.length) records.push({ bytes: bytes.subarray(start), line, start, terminated: false });\n\treturn records;\n}\n\nfunction decodeRecord(record: JsonlPhysicalRecord): string {\n\tlet bytes = record.bytes;\n\tif (bytes.at(-1) === 0x0d) bytes = bytes.subarray(0, bytes.length - 1);\n\ttry {\n\t\treturn new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes);\n\t} catch (error) {\n\t\tthrow new JsonlDecodeFailure(\"utf8\", \"contains invalid UTF-8\", toError(error));\n\t}\n}\n\nfunction parseJsonObject(record: JsonlPhysicalRecord): Record<string, unknown> {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(decodeRecord(record));\n\t} catch (error) {\n\t\tif (error instanceof JsonlDecodeFailure) throw error;\n\t\tthrow new JsonlDecodeFailure(\"syntax\", \"is not valid JSON\", toError(error));\n\t}\n\tif (!isRecord(parsed)) throw new JsonlDecodeFailure(\"schema\", \"is not a JSON object\");\n\treturn parsed;\n}\n\nfunction invalidSession(\n\tfilePath: string,\n\tmessage: string,\n\tcause?: Error,\n\tphase: JsonlErrorPhase = \"open\",\n): JsonlSessionError {\n\tconst decodeCause = cause instanceof JsonlDecodeFailure ? cause : new JsonlDecodeFailure(\"schema\", message, cause);\n\treturn new JsonlSessionError({\n\t\tcode: \"invalid_session\",\n\t\treference: filePath,\n\t\tphase,\n\t\tline: 1,\n\t\tbyteOffset: 0,\n\t\tdecodeKind: decodeCause.decodeKind,\n\t\tmessage: `Invalid JSONL session file ${filePath}: ${message}`,\n\t\tcause: decodeCause,\n\t});\n}\n\nfunction invalidEntry(\n\tfilePath: string,\n\tlineNumber: number,\n\tmessage: string,\n\tcause?: Error,\n\tbyteOffset?: number,\n\tphase: JsonlErrorPhase = \"open\",\n): JsonlSessionError {\n\tconst decodeCause = cause instanceof JsonlDecodeFailure ? cause : new JsonlDecodeFailure(\"state\", message, cause);\n\treturn new JsonlSessionError({\n\t\tcode: \"invalid_entry\",\n\t\treference: filePath,\n\t\tphase,\n\t\tline: lineNumber,\n\t\tbyteOffset,\n\t\tdecodeKind: decodeCause.decodeKind,\n\t\tmessage: `Invalid JSONL session file ${filePath}: line ${lineNumber} ${message}`,\n\t\tcause: decodeCause,\n\t});\n}\n\nfunction withJsonlPhase(error: JsonlSessionError, phase: JsonlErrorPhase): JsonlSessionError {\n\treturn new JsonlSessionError({\n\t\tcode: error.code,\n\t\treference: error.reference,\n\t\tphase,\n\t\tline: error.line,\n\t\tbyteOffset: error.byteOffset,\n\t\tdecodeKind: error.decodeKind,\n\t\toutcome: error.outcome,\n\t\tmessage: error.message,\n\t\tcause: error.cause instanceof Error ? error.cause : undefined,\n\t});\n}\n\nfunction jsonlStorageError(\n\treference: string,\n\tphase: JsonlErrorPhase,\n\tmessage: string,\n\tcause: Error,\n\toutcome?: JsonlWriteOutcome,\n): JsonlSessionError {\n\tif (cause instanceof JsonlSessionError) return withJsonlPhase(cause, phase);\n\treturn new JsonlSessionError({\n\t\tcode: cause instanceof SessionError ? cause.code : \"storage\",\n\t\treference,\n\t\tphase,\n\t\tmessage: message.includes(cause.message) ? message : `${message}: ${cause.message}`,\n\t\toutcome,\n\t\tcause,\n\t});\n}\n\nfunction parseHeaderRecord(record: JsonlPhysicalRecord, filePath: string): SessionHeader {\n\tlet parsed: Record<string, unknown>;\n\ttry {\n\t\tparsed = parseJsonObject(record);\n\t} catch (error) {\n\t\tthrow invalidSession(filePath, \"first line is not a valid session header\", toError(error));\n\t}\n\tif (parsed.type !== \"session\") throw invalidSession(filePath, \"first line is not a valid session header\");\n\tif (parsed.version !== 3) throw invalidSession(filePath, \"unsupported session version\");\n\tif (typeof parsed.id !== \"string\" || !SAFE_ID_PATTERN.test(parsed.id)) {\n\t\tthrow invalidSession(filePath, \"session header has invalid id\");\n\t}\n\tif (typeof parsed.timestamp !== \"string\" || Number.isNaN(Date.parse(parsed.timestamp))) {\n\t\tthrow invalidSession(filePath, \"session header has invalid timestamp\");\n\t}\n\tif (typeof parsed.cwd !== \"string\" || !parsed.cwd) throw invalidSession(filePath, \"session header is missing cwd\");\n\tif (parsed.parentSession !== undefined && typeof parsed.parentSession !== \"string\") {\n\t\tthrow invalidSession(filePath, \"session header parentSession must be a string\");\n\t}\n\treturn {\n\t\ttype: \"session\",\n\t\tversion: 3,\n\t\tid: parsed.id,\n\t\ttimestamp: parsed.timestamp,\n\t\tcwd: parsed.cwd,\n\t\tparentSession: parsed.parentSession,\n\t};\n}\n\nconst ENTRY_TYPES = new Set<SessionTreeEntry[\"type\"]>([\n\t\"message\",\n\t\"thinking_level_change\",\n\t\"model_change\",\n\t\"compaction\",\n\t\"branch_summary\",\n\t\"custom\",\n\t\"custom_message\",\n\t\"label\",\n\t\"session_info\",\n\t\"leaf\",\n]);\n\nfunction requireString(value: unknown, field: string): string {\n\tif (typeof value !== \"string\" || value.length === 0) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", `has invalid ${field}`);\n\t}\n\treturn value;\n}\n\nfunction requireId(value: unknown, field: string): string {\n\tconst id = requireString(value, field);\n\tif (!SAFE_ID_PATTERN.test(id)) throw new JsonlDecodeFailure(\"schema\", `has invalid ${field}`);\n\treturn id;\n}\n\nfunction requireTimestamp(value: unknown): string {\n\tconst timestamp = requireString(value, \"timestamp\");\n\tif (Number.isNaN(Date.parse(timestamp))) throw new JsonlDecodeFailure(\"schema\", \"has invalid timestamp\");\n\treturn timestamp;\n}\n\nconst MESSAGE_ROLES = new Set([\n\t\"user\",\n\t\"assistant\",\n\t\"toolResult\",\n\t\"bashExecution\",\n\t\"custom\",\n\t\"branchSummary\",\n\t\"compactionSummary\",\n\t\"hookMessage\",\n]);\n\nfunction validateToolResultMessage(value: Record<string, unknown>): void {\n\trequireString(value.toolCallId, \"toolCallId\");\n\trequireString(value.toolName, \"toolName\");\n\tif (typeof value.isError !== \"boolean\") throw new JsonlDecodeFailure(\"schema\", \"has invalid isError\");\n}\n\nfunction validateCustomMessage(value: Record<string, unknown>): void {\n\trequireString(value.customType, \"customType\");\n\tif (typeof value.display !== \"boolean\") throw new JsonlDecodeFailure(\"schema\", \"has invalid display\");\n}\n\nfunction validateBashExecutionMessage(value: Record<string, unknown>): void {\n\trequireString(value.command, \"command\");\n\tif (typeof value.output !== \"string\") throw new JsonlDecodeFailure(\"schema\", \"has invalid output\");\n\tif (typeof value.cancelled !== \"boolean\" || typeof value.truncated !== \"boolean\") {\n\t\tthrow new JsonlDecodeFailure(\"schema\", \"has invalid bash state\");\n\t}\n}\n\nfunction validateSummaryMessage(value: Record<string, unknown>): void {\n\trequireString(value.summary, \"summary\");\n}\n\nfunction validateMessageRolePayload(role: string, value: Record<string, unknown>): void {\n\tswitch (role) {\n\t\tcase \"toolResult\":\n\t\t\tvalidateToolResultMessage(value);\n\t\t\tbreak;\n\t\tcase \"custom\":\n\t\tcase \"hookMessage\":\n\t\t\tvalidateCustomMessage(value);\n\t\t\tbreak;\n\t\tcase \"bashExecution\":\n\t\t\tvalidateBashExecutionMessage(value);\n\t\t\tbreak;\n\t\tcase \"branchSummary\":\n\t\tcase \"compactionSummary\":\n\t\t\tvalidateSummaryMessage(value);\n\t\t\tbreak;\n\t}\n}\n\nfunction validatePersistedMessage(value: unknown): void {\n\tif (!isRecord(value)) throw new JsonlDecodeFailure(\"schema\", \"has invalid message\");\n\tconst role = requireString(value.role, \"message role\");\n\tif (!MESSAGE_ROLES.has(role)) throw new JsonlDecodeFailure(\"schema\", `has unknown message role ${role}`);\n\tif (typeof value.timestamp !== \"number\" || !Number.isFinite(value.timestamp)) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", \"has invalid message timestamp\");\n\t}\n\tif (value.content != null && typeof value.content !== \"string\" && !Array.isArray(value.content)) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", \"has invalid message content\");\n\t}\n\tvalidateMessageRolePayload(role, value);\n}\n\nfunction validateCompactionEntry(value: Record<string, unknown>): void {\n\trequireString(value.summary, \"summary\");\n\trequireId(value.firstKeptEntryId, \"firstKeptEntryId\");\n\tif (typeof value.tokensBefore !== \"number\" || !Number.isFinite(value.tokensBefore)) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", \"has invalid tokensBefore\");\n\t}\n}\n\nfunction validateCustomMessageEntry(value: Record<string, unknown>): void {\n\trequireString(value.customType, \"customType\");\n\tif (value.content != null && typeof value.content !== \"string\" && !Array.isArray(value.content)) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", \"has invalid content\");\n\t}\n\tif (typeof value.display !== \"boolean\") throw new JsonlDecodeFailure(\"schema\", \"has invalid display\");\n}\n\nfunction validateOptionalString(value: unknown, field: string): void {\n\tif (value !== undefined && typeof value !== \"string\") {\n\t\tthrow new JsonlDecodeFailure(\"schema\", `has invalid ${field}`);\n\t}\n}\n\nfunction validateNullableId(value: unknown, field: string): void {\n\tif (value !== null && (typeof value !== \"string\" || !SAFE_ID_PATTERN.test(value))) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", `has invalid ${field}`);\n\t}\n}\n\nfunction validateEntryPayload(type: string, parsed: Record<string, unknown>): void {\n\tswitch (type) {\n\t\tcase \"message\":\n\t\t\tvalidatePersistedMessage(parsed.message);\n\t\t\tbreak;\n\t\tcase \"thinking_level_change\":\n\t\t\trequireString(parsed.thinkingLevel, \"thinkingLevel\");\n\t\t\tbreak;\n\t\tcase \"model_change\":\n\t\t\trequireString(parsed.provider, \"provider\");\n\t\t\trequireString(parsed.modelId, \"modelId\");\n\t\t\tbreak;\n\t\tcase \"compaction\":\n\t\t\tvalidateCompactionEntry(parsed);\n\t\t\tbreak;\n\t\tcase \"branch_summary\":\n\t\t\trequireId(parsed.fromId, \"fromId\");\n\t\t\trequireString(parsed.summary, \"summary\");\n\t\t\tbreak;\n\t\tcase \"custom\":\n\t\t\trequireString(parsed.customType, \"customType\");\n\t\t\tbreak;\n\t\tcase \"custom_message\":\n\t\t\tvalidateCustomMessageEntry(parsed);\n\t\t\tbreak;\n\t\tcase \"label\":\n\t\t\trequireId(parsed.targetId, \"targetId\");\n\t\t\tvalidateOptionalString(parsed.label, \"label\");\n\t\t\tbreak;\n\t\tcase \"session_info\":\n\t\t\tvalidateOptionalString(parsed.name, \"name\");\n\t\t\tbreak;\n\t\tcase \"leaf\":\n\t\t\tvalidateNullableId(parsed.targetId, \"targetId\");\n\t\t\tbreak;\n\t}\n}\n\nfunction parseEntryRecord(record: JsonlPhysicalRecord): SessionTreeEntry {\n\tconst parsed = parseJsonObject(record);\n\tconst type = requireString(parsed.type, \"entry type\");\n\tif (!ENTRY_TYPES.has(type as SessionTreeEntry[\"type\"])) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", `has unknown entry type ${type}`);\n\t}\n\trequireId(parsed.id, \"entry id\");\n\tif (parsed.parentId !== null && (typeof parsed.parentId !== \"string\" || !SAFE_ID_PATTERN.test(parsed.parentId))) {\n\t\tthrow new JsonlDecodeFailure(\"schema\", \"has invalid parentId\");\n\t}\n\trequireTimestamp(parsed.timestamp);\n\tvalidateEntryPayload(type, parsed);\n\treturn parsed as unknown as SessionTreeEntry;\n}\n\nfunction leafIdAfterEntry(entry: SessionTreeEntry): string | null {\n\treturn entry.type === \"leaf\" ? entry.targetId : entry.id;\n}\n\nfunction leafIdAfterEntries(entries: SessionTreeEntry[]): string | null {\n\tlet leafId: string | null = null;\n\tfor (const entry of entries) leafId = leafIdAfterEntry(entry);\n\treturn leafId;\n}\n\nfunction isDefinitelyNotWritten(error: unknown): boolean {\n\tconst cause = error instanceof SessionError ? error.cause : error;\n\treturn cause instanceof FileError && cause.code !== \"unknown\" && cause.code !== \"aborted\";\n}\n\nfunction serializeJsonlSession(header: SessionHeader, entries: SessionTreeEntry[]): string {\n\treturn `${[header, ...entries].map((entry) => JSON.stringify(entry)).join(\"\\n\")}\\n`;\n}\n\nasync function publishJsonlContentAtomicallyUnsafe(\n\tfs: JsonlSessionStorageFileSystem,\n\tfilePath: string,\n\tcontent: string | Uint8Array,\n\tallowReplace: boolean,\n): Promise<void> {\n\tconst destinationInfo = await fs.fileInfo(filePath);\n\tif (destinationInfo.ok) {\n\t\tif (!allowReplace) throw new SessionError(\"already_exists\", `Session already exists: ${filePath}`);\n\t\tif (destinationInfo.value.kind !== \"file\") {\n\t\t\tthrow new SessionError(\"storage\", `Refusing to replace non-file session path: ${filePath}`);\n\t\t}\n\t} else if (destinationInfo.error.code !== \"not_found\") {\n\t\tgetFileSystemResultOrThrow(destinationInfo, `Failed to inspect session destination ${filePath}`);\n\t}\n\n\tlet tempPath: string | undefined;\n\tfor (let attempt = 0; attempt < 100; attempt++) {\n\t\tconst candidate = `${filePath}.${uuidv7()}.tmp`;\n\t\tif (\n\t\t\t!getFileSystemResultOrThrow(await fs.exists(candidate), `Failed to inspect session staging path ${candidate}`)\n\t\t) {\n\t\t\ttempPath = candidate;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (!tempPath) throw new SessionError(\"storage\", `Failed to allocate staging path for session ${filePath}`);\n\n\tlet published = false;\n\ttry {\n\t\ttry {\n\t\t\tgetFileSystemResultOrThrow(await fs.writeFile(tempPath, content), `Failed to stage session ${filePath}`);\n\t\t} catch (error) {\n\t\t\tthrow jsonlStorageError(\n\t\t\t\tfilePath,\n\t\t\t\t\"replace\",\n\t\t\t\t`Failed to stage session ${filePath}`,\n\t\t\t\ttoError(error),\n\t\t\t\t\"not_written\",\n\t\t\t);\n\t\t}\n\t\ttry {\n\t\t\tgetFileSystemResultOrThrow(await fs.renameFile(tempPath, filePath), `Failed to publish session ${filePath}`);\n\t\t} catch (error) {\n\t\t\tthrow jsonlStorageError(\n\t\t\t\tfilePath,\n\t\t\t\t\"replace\",\n\t\t\t\t`Failed to publish session ${filePath}`,\n\t\t\t\ttoError(error),\n\t\t\t\t\"unknown\",\n\t\t\t);\n\t\t}\n\t\tpublished = true;\n\t} finally {\n\t\tif (!published) await fs.remove(tempPath, { force: true });\n\t}\n}\n\nasync function publishJsonlContentAtomically(\n\tfs: JsonlSessionStorageFileSystem,\n\tfilePath: string,\n\tcontent: string | Uint8Array,\n\tallowReplace: boolean,\n\tphase: JsonlErrorPhase = \"replace\",\n): Promise<void> {\n\ttry {\n\t\tawait publishJsonlContentAtomicallyUnsafe(fs, filePath, content, allowReplace);\n\t} catch (error) {\n\t\tconst cause = toError(error);\n\t\tif (cause instanceof JsonlSessionError) {\n\t\t\tthrow new JsonlSessionError({\n\t\t\t\tcode: cause.code,\n\t\t\t\treference: cause.reference,\n\t\t\t\tphase,\n\t\t\t\tmessage: cause.message,\n\t\t\t\toutcome: cause.outcome,\n\t\t\t\tcause: cause.cause instanceof Error ? cause.cause : cause,\n\t\t\t});\n\t\t}\n\t\tthrow jsonlStorageError(filePath, phase, cause.message, cause, \"not_written\");\n\t}\n}\n\nfunction headerToSessionMetadata(header: SessionHeader, path: string): JsonlSessionMetadata {\n\treturn {\n\t\tid: header.id,\n\t\tcreatedAt: header.timestamp,\n\t\tcwd: header.cwd,\n\t\tpath,\n\t\tparentSessionPath: header.parentSession,\n\t};\n}\n\nexport async function loadJsonlSessionMetadata(\n\tfs: JsonlSessionMetadataFileSystem,\n\tfilePath: string,\n): Promise<JsonlSessionMetadata> {\n\tlet firstLine: string;\n\ttry {\n\t\tconst lines = getFileSystemResultOrThrow(\n\t\t\tawait fs.readTextLines(filePath, { maxLines: 1 }),\n\t\t\t`Failed to read session header ${filePath}`,\n\t\t);\n\t\tfirstLine = lines[0] ?? \"\";\n\t} catch (error) {\n\t\tthrow jsonlStorageError(filePath, \"list\", `Failed to read session header ${filePath}`, toError(error));\n\t}\n\tif (!firstLine) throw invalidSession(filePath, \"missing session header\", undefined, \"list\");\n\tlet headerBytes: Uint8Array = new TextEncoder().encode(firstLine);\n\tif (firstLine.includes(\"\\uFFFD\")) {\n\t\tlet bytes: Uint8Array;\n\t\ttry {\n\t\t\tbytes = getFileSystemResultOrThrow(\n\t\t\t\tawait fs.readBinaryFile(filePath),\n\t\t\t\t`Failed to verify session header encoding ${filePath}`,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tthrow jsonlStorageError(\n\t\t\t\tfilePath,\n\t\t\t\t\"list\",\n\t\t\t\t`Failed to verify session header encoding ${filePath}`,\n\t\t\t\ttoError(error),\n\t\t\t);\n\t\t}\n\t\tconst newline = bytes.indexOf(0x0a);\n\t\theaderBytes = newline === -1 ? bytes : bytes.subarray(0, newline);\n\t}\n\ttry {\n\t\treturn headerToSessionMetadata(\n\t\t\tparseHeaderRecord({ bytes: headerBytes, line: 1, start: 0, terminated: true }, filePath),\n\t\t\tfilePath,\n\t\t);\n\t} catch (error) {\n\t\tif (error instanceof JsonlSessionError) throw withJsonlPhase(error, \"list\");\n\t\tthrow error;\n\t}\n}\n\nfunction validateEntryState(\n\tentry: SessionTreeEntry,\n\tentriesById: Map<string, SessionTreeEntry>,\n\tfilePath: string,\n\tline: number,\n\tbyteOffset?: number,\n\tphase: JsonlErrorPhase = \"open\",\n): void {\n\tif (entriesById.has(entry.id)) {\n\t\tthrow invalidEntry(filePath, line, `duplicates entry id ${entry.id}`, undefined, byteOffset, phase);\n\t}\n\tif (entry.parentId !== null && !entriesById.has(entry.parentId)) {\n\t\tthrow invalidEntry(filePath, line, `references missing parent ${entry.parentId}`, undefined, byteOffset, phase);\n\t}\n\tconst targetId =\n\t\tentry.type === \"label\"\n\t\t\t? entry.targetId\n\t\t\t: entry.type === \"compaction\"\n\t\t\t\t? entry.firstKeptEntryId\n\t\t\t\t: entry.type === \"branch_summary\"\n\t\t\t\t\t? entry.fromId\n\t\t\t\t\t: entry.type === \"leaf\"\n\t\t\t\t\t\t? entry.targetId\n\t\t\t\t\t\t: undefined;\n\tif (targetId !== undefined && targetId !== null && !entriesById.has(targetId)) {\n\t\tthrow invalidEntry(filePath, line, `references missing target ${targetId}`, undefined, byteOffset, phase);\n\t}\n\tentriesById.set(entry.id, entry);\n}\n\ninterface JsonlAppendPosition {\n\tnextLine: number;\n\tnextOffset: number;\n}\n\ninterface JsonlEntryRecordResolution {\n\tentry?: SessionTreeEntry;\n\trepairTruncatedTail: boolean;\n}\n\ninterface JsonlStorageLoadResult extends JsonlAppendPosition {\n\theader: SessionHeader;\n\tentries: SessionTreeEntry[];\n\tleafId: string | null;\n}\nfunction getNextAppendPosition(bytes: Uint8Array): JsonlAppendPosition {\n\tlet nextLine = 1;\n\tfor (const byte of bytes) {\n\t\tif (byte === 0x0a) nextLine++;\n\t}\n\treturn { nextLine, nextOffset: bytes.length };\n}\n\nfunction resolveJsonlEntryRecord(\n\trecord: JsonlPhysicalRecord,\n\tisLastRecord: boolean,\n\tfilePath: string,\n\tphase: JsonlErrorPhase,\n): JsonlEntryRecordResolution {\n\tlet line: string;\n\ttry {\n\t\tline = decodeRecord(record);\n\t} catch (error) {\n\t\tconst failure = toError(error);\n\t\tconst isRepairableTail = !record.terminated && isLastRecord && failure instanceof JsonlDecodeFailure;\n\t\tif (isRepairableTail) return { repairTruncatedTail: true };\n\t\tthrow invalidEntry(filePath, record.line, failure.message, failure, record.start, phase);\n\t}\n\tif (!line.trim()) return { repairTruncatedTail: false };\n\ttry {\n\t\treturn { entry: parseEntryRecord(record), repairTruncatedTail: false };\n\t} catch (error) {\n\t\tconst failure = toError(error);\n\t\tconst isRepairableTail =\n\t\t\t!record.terminated && isLastRecord && failure instanceof JsonlDecodeFailure && failure.kind === \"syntax\";\n\t\tif (isRepairableTail) return { repairTruncatedTail: true };\n\t\tthrow invalidEntry(filePath, record.line, failure.message, failure, record.start, phase);\n\t}\n}\n\nasync function loadJsonlStorage(\n\tfs: JsonlSessionStorageFileSystem,\n\tfilePath: string,\n\tphase: JsonlSessionLoadPhase = \"open\",\n): Promise<JsonlStorageLoadResult> {\n\tlet bytes: Uint8Array;\n\ttry {\n\t\tbytes = getFileSystemResultOrThrow(await fs.readBinaryFile(filePath), `Failed to read session ${filePath}`);\n\t} catch (error) {\n\t\tthrow jsonlStorageError(filePath, phase, `Failed to read session ${filePath}`, toError(error));\n\t}\n\tconst records = splitPhysicalRecords(bytes);\n\tif (records.length === 0) throw invalidSession(filePath, \"missing session header\", undefined, phase);\n\tlet header: SessionHeader;\n\ttry {\n\t\theader = parseHeaderRecord(records[0]!, filePath);\n\t} catch (error) {\n\t\tif (error instanceof JsonlSessionError) throw withJsonlPhase(error, phase);\n\t\tthrow error;\n\t}\n\tconst entries: SessionTreeEntry[] = [];\n\tconst entriesById = new Map<string, SessionTreeEntry>();\n\tlet leafId: string | null = null;\n\n\tfor (let index = 1; index < records.length; index++) {\n\t\tconst record = records[index]!;\n\t\tconst resolution = resolveJsonlEntryRecord(record, index === records.length - 1, filePath, phase);\n\t\tif (resolution.repairTruncatedTail) {\n\t\t\tconst repairedBytes = bytes.subarray(0, record.start);\n\t\t\tawait publishJsonlContentAtomically(fs, filePath, repairedBytes, true, \"repair\");\n\t\t\treturn { header, entries, leafId, ...getNextAppendPosition(repairedBytes) };\n\t\t}\n\t\tif (!resolution.entry) continue;\n\t\tvalidateEntryState(resolution.entry, entriesById, filePath, record.line, record.start, phase);\n\t\tentries.push(resolution.entry);\n\t\tleafId = leafIdAfterEntry(resolution.entry);\n\t}\n\n\tif (records.at(-1)?.terminated === false) {\n\t\tconst repaired = new Uint8Array(bytes.length + 1);\n\t\trepaired.set(bytes);\n\t\trepaired[bytes.length] = 0x0a;\n\t\tawait publishJsonlContentAtomically(fs, filePath, repaired, true, \"repair\");\n\t}\n\tconst position = getNextAppendPosition(bytes);\n\tif (records.at(-1)?.terminated === false) {\n\t\tposition.nextLine++;\n\t\tposition.nextOffset++;\n\t}\n\treturn { header, entries, leafId, ...position };\n}\n\nexport class JsonlSessionStorage implements SessionStorage<JsonlSessionMetadata> {\n\tprivate readonly fs: JsonlSessionStorageFileSystem;\n\tprivate readonly filePath: string;\n\tprivate readonly metadata: JsonlSessionMetadata;\n\tprivate entries: SessionTreeEntry[];\n\tprivate byId: Map<string, SessionTreeEntry>;\n\tprivate labelsById: Map<string, string>;\n\tprivate currentLeafId: string | null;\n\tprivate appendQueue: Promise<void> = Promise.resolve();\n\tprivate writeFence: JsonlSessionError | undefined;\n\tprivate nextAppendLine: number;\n\tprivate nextAppendOffset: number;\n\n\tprivate constructor(\n\t\tfs: JsonlSessionStorageFileSystem,\n\t\tfilePath: string,\n\t\theader: SessionHeader,\n\t\tentries: SessionTreeEntry[],\n\t\tleafId: string | null,\n\t\tnextAppendLine: number,\n\t\tnextAppendOffset: number,\n\t) {\n\t\tthis.fs = fs;\n\t\tthis.filePath = filePath;\n\t\tthis.metadata = headerToSessionMetadata(header, this.filePath);\n\t\tthis.entries = entries;\n\t\tthis.byId = new Map(entries.map((entry) => [entry.id, entry]));\n\t\tthis.labelsById = buildLabelsById(entries);\n\t\tthis.currentLeafId = leafId;\n\t\tthis.nextAppendLine = nextAppendLine;\n\t\tthis.nextAppendOffset = nextAppendOffset;\n\t}\n\n\tstatic async open(\n\t\tfs: JsonlSessionStorageFileSystem,\n\t\tfilePath: string,\n\t\tphase: JsonlSessionLoadPhase = \"open\",\n\t): Promise<JsonlSessionStorage> {\n\t\tconst loaded = await loadJsonlStorage(fs, filePath, phase);\n\t\treturn new JsonlSessionStorage(\n\t\t\tfs,\n\t\t\tfilePath,\n\t\t\tloaded.header,\n\t\t\tloaded.entries,\n\t\t\tloaded.leafId,\n\t\t\tloaded.nextLine,\n\t\t\tloaded.nextOffset,\n\t\t);\n\t}\n\n\tstatic async create(\n\t\tfs: JsonlSessionStorageFileSystem,\n\t\tfilePath: string,\n\t\toptions: JsonlSessionStorageCreateOptions,\n\t): Promise<JsonlSessionStorage> {\n\t\tconst header: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tversion: 3,\n\t\t\tid: options.sessionId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tcwd: options.cwd,\n\t\t\tparentSession: options.parentSessionPath,\n\t\t};\n\t\tconst entries = [...(options.entries ?? [])];\n\t\tconst serialized = serializeJsonlSession(header, entries);\n\t\tawait publishJsonlContentAtomically(fs, filePath, serialized, false, options.phase ?? \"create\");\n\t\tconst position = getNextAppendPosition(new TextEncoder().encode(serialized));\n\t\treturn new JsonlSessionStorage(\n\t\t\tfs,\n\t\t\tfilePath,\n\t\t\theader,\n\t\t\tentries,\n\t\t\tleafIdAfterEntries(entries),\n\t\t\tposition.nextLine,\n\t\t\tposition.nextOffset,\n\t\t);\n\t}\n\n\tasync getMetadata(): Promise<JsonlSessionMetadata> {\n\t\treturn this.metadata;\n\t}\n\n\tasync getLeafId(): Promise<string | null> {\n\t\tif (this.currentLeafId !== null && !this.byId.has(this.currentLeafId)) {\n\t\t\tthrow new SessionError(\"invalid_session\", `Entry ${this.currentLeafId} not found`);\n\t\t}\n\t\treturn this.currentLeafId;\n\t}\n\n\tasync setLeafId(leafId: string | null): Promise<void> {\n\t\tif (leafId !== null && !this.byId.has(leafId)) {\n\t\t\tthrow new SessionError(\"not_found\", `Entry ${leafId} not found`);\n\t\t}\n\t\tconst entry: LeafEntry = {\n\t\t\ttype: \"leaf\",\n\t\t\tid: generateEntryId(this.byId),\n\t\t\tparentId: this.currentLeafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\ttargetId: leafId,\n\t\t};\n\t\tawait this.appendSerializedEntry(entry, `Failed to append session leaf ${entry.id}`, () => {\n\t\t\tthis.entries.push(entry);\n\t\t\tthis.byId.set(entry.id, entry);\n\t\t\tthis.currentLeafId = leafId;\n\t\t});\n\t}\n\n\tasync createEntryId(): Promise<string> {\n\t\treturn generateEntryId(this.byId);\n\t}\n\n\tasync appendEntry(entry: SessionTreeEntry): Promise<void> {\n\t\tawait this.appendSerializedEntry(entry, `Failed to append session entry ${entry.id}`, () => {\n\t\t\tthis.entries.push(entry);\n\t\t\tthis.byId.set(entry.id, entry);\n\t\t\tupdateLabelCache(this.labelsById, entry);\n\t\t\tthis.currentLeafId = leafIdAfterEntry(entry);\n\t\t});\n\t}\n\n\tprivate async appendSerializedEntry(entry: SessionTreeEntry, message: string, commit: () => void): Promise<void> {\n\t\tconst serialized = `${JSON.stringify(entry)}\\n`;\n\t\tconst serializedLength = new TextEncoder().encode(serialized).length;\n\t\tconst operation = this.appendQueue.then(async () => {\n\t\t\tvalidateEntryState(\n\t\t\t\tentry,\n\t\t\t\tnew Map(this.byId),\n\t\t\t\tthis.filePath,\n\t\t\t\tthis.nextAppendLine,\n\t\t\t\tthis.nextAppendOffset,\n\t\t\t\t\"append\",\n\t\t\t);\n\t\t\tif (this.writeFence) {\n\t\t\t\tthrow new JsonlSessionError({\n\t\t\t\t\tcode: \"storage\",\n\t\t\t\t\treference: this.filePath,\n\t\t\t\t\tphase: \"append\",\n\t\t\t\t\tmessage: `Session writes are fenced after an ambiguous append failure: ${this.filePath}`,\n\t\t\t\t\toutcome: \"unknown\",\n\t\t\t\t\tcause: this.writeFence,\n\t\t\t\t});\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tgetFileSystemResultOrThrow(await this.fs.appendFile(this.filePath, serialized), message);\n\t\t\t} catch (error) {\n\t\t\t\tconst cause = toError(error);\n\t\t\t\tif (isDefinitelyNotWritten(error)) {\n\t\t\t\t\tthrow jsonlStorageError(this.filePath, \"append\", message, cause, \"not_written\");\n\t\t\t\t}\n\t\t\t\tthis.writeFence = jsonlStorageError(this.filePath, \"append\", message, cause, \"unknown\");\n\t\t\t\tthrow this.writeFence;\n\t\t\t}\n\t\t\tcommit();\n\t\t\tthis.nextAppendLine++;\n\t\t\tthis.nextAppendOffset += serializedLength;\n\t\t});\n\t\tthis.appendQueue = operation.catch(() => {});\n\t\tawait operation;\n\t}\n\n\tasync getEntry(id: string): Promise<SessionTreeEntry | undefined> {\n\t\treturn this.byId.get(id);\n\t}\n\n\tasync findEntries<TType extends SessionTreeEntry[\"type\"]>(\n\t\ttype: TType,\n\t): Promise<Array<SessionTreeEntryOfType<TType>>> {\n\t\treturn this.entries.filter((entry): entry is SessionTreeEntryOfType<TType> => entry.type === type);\n\t}\n\n\tasync getLabel(id: string): Promise<string | undefined> {\n\t\treturn this.labelsById.get(id);\n\t}\n\n\tasync getPathToRoot(leafId: string | null): Promise<SessionTreeEntry[]> {\n\t\tif (leafId === null) return [];\n\t\tconst path: SessionTreeEntry[] = [];\n\t\tlet current = this.byId.get(leafId);\n\t\tif (!current) throw new SessionError(\"not_found\", `Entry ${leafId} not found`);\n\t\twhile (current) {\n\t\t\tpath.unshift(current);\n\t\t\tif (!current.parentId) break;\n\t\t\tconst parent = this.byId.get(current.parentId);\n\t\t\tif (!parent) throw new SessionError(\"invalid_session\", `Entry ${current.parentId} not found`);\n\t\t\tcurrent = parent;\n\t\t}\n\t\treturn path;\n\t}\n\n\tasync getEntries(): Promise<SessionTreeEntry[]> {\n\t\treturn [...this.entries];\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"memory-repo.d.ts","sourceRoot":"","sources":["../../../src/harness/session/memory-repo.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,OAAO,EACZ,KAAK,oBAAoB,EAEzB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,MAAM,aAAa,CAAC;AAIrB,qBAAa,mBAAoB,YAAW,WAAW,CAAC,eAAe,EAAE;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,IAAI,CAAC;IAC9F,OAAO,CAAC,QAAQ,CAA+C;IAEzD,MAAM,CAAC,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CASlF;IAEK,IAAI,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAMvE;IAEK,IAAI,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAEvC;IAEK,MAAM,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAErD;IAEK,IAAI,CAAC,cAAc,EAAE,eAAe,EAAE,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAW1G;CACD","sourcesContent":["import {\n\ttype Session,\n\ttype SessionCreateOptions,\n\tSessionError,\n\ttype SessionForkOptions,\n\ttype SessionMetadata,\n\ttype SessionRepo,\n} from \"../types.ts\";\nimport { InMemorySessionStorage } from \"./memory-storage.ts\";\nimport { createSessionId, createTimestamp, getEntriesToFork, toSession } from \"./repo-utils.ts\";\n\nexport class InMemorySessionRepo implements SessionRepo<SessionMetadata, { id?: string }, void> {\n\tprivate sessions = new Map<string, Session<SessionMetadata>>();\n\n\tasync create(options: SessionCreateOptions = {}): Promise<Session<SessionMetadata>> {\n\t\tconst metadata: SessionMetadata = {\n\t\t\tid: options.id ?? createSessionId(),\n\t\t\tcreatedAt: createTimestamp(),\n\t\t};\n\t\tconst storage = new InMemorySessionStorage({ metadata });\n\t\tconst session = toSession(storage);\n\t\tthis.sessions.set(metadata.id, session);\n\t\treturn session;\n\t}\n\n\tasync open(metadata: SessionMetadata): Promise<Session<SessionMetadata>> {\n\t\tconst session = this.sessions.get(metadata.id);\n\t\tif (!session) {\n\t\t\tthrow new SessionError(\"not_found\", `Session not found: ${metadata.id}`);\n\t\t}\n\t\treturn session;\n\t}\n\n\tasync list(): Promise<SessionMetadata[]> {\n\t\treturn Promise.all([...this.sessions.values()].map((session) => session.getMetadata()));\n\t}\n\n\tasync delete(metadata: SessionMetadata): Promise<void> {\n\t\tthis.sessions.delete(metadata.id);\n\t}\n\n\tasync fork(sourceMetadata: SessionMetadata, options: SessionForkOptions): Promise<Session<SessionMetadata>> {\n\t\tconst source = await this.open(sourceMetadata);\n\t\tconst forkedEntries = await getEntriesToFork(source.getStorage(), options);\n\t\tconst metadata: SessionMetadata = {\n\t\t\tid: options.id ?? createSessionId(),\n\t\t\tcreatedAt: createTimestamp(),\n\t\t};\n\t\tconst storage = new InMemorySessionStorage({ metadata, entries: forkedEntries });\n\t\tconst session = toSession(storage);\n\t\tthis.sessions.set(metadata.id, session);\n\t\treturn session;\n\t}\n}\n"]}
1
+ {"version":3,"file":"memory-repo.d.ts","sourceRoot":"","sources":["../../../src/harness/session/memory-repo.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,OAAO,EACZ,KAAK,oBAAoB,EAEzB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,MAAM,aAAa,CAAC;AAIrB,qBAAa,mBAAoB,YAAW,WAAW,CAAC,eAAe,EAAE;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,IAAI,CAAC;IAC9F,OAAO,CAAC,QAAQ,CAA+C;IAEzD,MAAM,CAAC,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CASlF;IAEK,IAAI,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAMvE;IAEK,IAAI,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAEvC;IAEK,MAAM,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAErD;IAEK,IAAI,CAAC,cAAc,EAAE,eAAe,EAAE,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAW1G;CACD"}
@@ -2,7 +2,9 @@ import { SessionError, } from "../types.js";
2
2
  import { InMemorySessionStorage } from "./memory-storage.js";
3
3
  import { createSessionId, createTimestamp, getEntriesToFork, toSession } from "./repo-utils.js";
4
4
  export class InMemorySessionRepo {
5
- sessions = new Map();
5
+ constructor() {
6
+ this.sessions = new Map();
7
+ }
6
8
  async create(options = {}) {
7
9
  const metadata = {
8
10
  id: options.id ?? createSessionId(),
@@ -1 +1 @@
1
- {"version":3,"file":"memory-repo.js","sourceRoot":"","sources":["../../../src/harness/session/memory-repo.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,YAAY,GAIZ,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEhG,MAAM,OAAO,mBAAmB;IACvB,QAAQ,GAAG,IAAI,GAAG,EAAoC,CAAC;IAE/D,KAAK,CAAC,MAAM,CAAC,OAAO,GAAyB,EAAE,EAAqC;QACnF,MAAM,QAAQ,GAAoB;YACjC,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,eAAe,EAAE;YACnC,SAAS,EAAE,eAAe,EAAE;SAC5B,CAAC;QACF,MAAM,OAAO,GAAG,IAAI,sBAAsB,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;QACzD,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACxC,OAAO,OAAO,CAAC;IAAA,CACf;IAED,KAAK,CAAC,IAAI,CAAC,QAAyB,EAAqC;QACxE,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC/C,IAAI,CAAC,OAAO,EAAE,CAAC;YACd,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,sBAAsB,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1E,CAAC;QACD,OAAO,OAAO,CAAC;IAAA,CACf;IAED,KAAK,CAAC,IAAI,GAA+B;QACxC,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IAAA,CACxF;IAED,KAAK,CAAC,MAAM,CAAC,QAAyB,EAAiB;QACtD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAAA,CAClC;IAED,KAAK,CAAC,IAAI,CAAC,cAA+B,EAAE,OAA2B,EAAqC;QAC3G,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC/C,MAAM,aAAa,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;QAC3E,MAAM,QAAQ,GAAoB;YACjC,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,eAAe,EAAE;YACnC,SAAS,EAAE,eAAe,EAAE;SAC5B,CAAC;QACF,MAAM,OAAO,GAAG,IAAI,sBAAsB,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC;QACjF,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACxC,OAAO,OAAO,CAAC;IAAA,CACf;CACD","sourcesContent":["import {\n\ttype Session,\n\ttype SessionCreateOptions,\n\tSessionError,\n\ttype SessionForkOptions,\n\ttype SessionMetadata,\n\ttype SessionRepo,\n} from \"../types.ts\";\nimport { InMemorySessionStorage } from \"./memory-storage.ts\";\nimport { createSessionId, createTimestamp, getEntriesToFork, toSession } from \"./repo-utils.ts\";\n\nexport class InMemorySessionRepo implements SessionRepo<SessionMetadata, { id?: string }, void> {\n\tprivate sessions = new Map<string, Session<SessionMetadata>>();\n\n\tasync create(options: SessionCreateOptions = {}): Promise<Session<SessionMetadata>> {\n\t\tconst metadata: SessionMetadata = {\n\t\t\tid: options.id ?? createSessionId(),\n\t\t\tcreatedAt: createTimestamp(),\n\t\t};\n\t\tconst storage = new InMemorySessionStorage({ metadata });\n\t\tconst session = toSession(storage);\n\t\tthis.sessions.set(metadata.id, session);\n\t\treturn session;\n\t}\n\n\tasync open(metadata: SessionMetadata): Promise<Session<SessionMetadata>> {\n\t\tconst session = this.sessions.get(metadata.id);\n\t\tif (!session) {\n\t\t\tthrow new SessionError(\"not_found\", `Session not found: ${metadata.id}`);\n\t\t}\n\t\treturn session;\n\t}\n\n\tasync list(): Promise<SessionMetadata[]> {\n\t\treturn Promise.all([...this.sessions.values()].map((session) => session.getMetadata()));\n\t}\n\n\tasync delete(metadata: SessionMetadata): Promise<void> {\n\t\tthis.sessions.delete(metadata.id);\n\t}\n\n\tasync fork(sourceMetadata: SessionMetadata, options: SessionForkOptions): Promise<Session<SessionMetadata>> {\n\t\tconst source = await this.open(sourceMetadata);\n\t\tconst forkedEntries = await getEntriesToFork(source.getStorage(), options);\n\t\tconst metadata: SessionMetadata = {\n\t\t\tid: options.id ?? createSessionId(),\n\t\t\tcreatedAt: createTimestamp(),\n\t\t};\n\t\tconst storage = new InMemorySessionStorage({ metadata, entries: forkedEntries });\n\t\tconst session = toSession(storage);\n\t\tthis.sessions.set(metadata.id, session);\n\t\treturn session;\n\t}\n}\n"]}
1
+ {"version":3,"file":"memory-repo.js","sourceRoot":"","sources":["../../../src/harness/session/memory-repo.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,YAAY,GAIZ,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEhG,MAAM,OAAO,mBAAmB;IAAhC;QACS,aAAQ,GAAG,IAAI,GAAG,EAAoC,CAAC;IAyChE,CAAC;IAvCA,KAAK,CAAC,MAAM,CAAC,OAAO,GAAyB,EAAE;QAC9C,MAAM,QAAQ,GAAoB;YACjC,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,eAAe,EAAE;YACnC,SAAS,EAAE,eAAe,EAAE;SAC5B,CAAC;QACF,MAAM,OAAO,GAAG,IAAI,sBAAsB,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;QACzD,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACxC,OAAO,OAAO,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,QAAyB;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC/C,IAAI,CAAC,OAAO,EAAE,CAAC;YACd,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,sBAAsB,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1E,CAAC;QACD,OAAO,OAAO,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,IAAI;QACT,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IACzF,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,QAAyB;QACrC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,cAA+B,EAAE,OAA2B;QACtE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC/C,MAAM,aAAa,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC;QAC3E,MAAM,QAAQ,GAAoB;YACjC,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,eAAe,EAAE;YACnC,SAAS,EAAE,eAAe,EAAE;SAC5B,CAAC;QACF,MAAM,OAAO,GAAG,IAAI,sBAAsB,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC;QACjF,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACxC,OAAO,OAAO,CAAC;IAChB,CAAC;CACD","sourcesContent":["import {\n\ttype Session,\n\ttype SessionCreateOptions,\n\tSessionError,\n\ttype SessionForkOptions,\n\ttype SessionMetadata,\n\ttype SessionRepo,\n} from \"../types.ts\";\nimport { InMemorySessionStorage } from \"./memory-storage.ts\";\nimport { createSessionId, createTimestamp, getEntriesToFork, toSession } from \"./repo-utils.ts\";\n\nexport class InMemorySessionRepo implements SessionRepo<SessionMetadata, { id?: string }, void> {\n\tprivate sessions = new Map<string, Session<SessionMetadata>>();\n\n\tasync create(options: SessionCreateOptions = {}): Promise<Session<SessionMetadata>> {\n\t\tconst metadata: SessionMetadata = {\n\t\t\tid: options.id ?? createSessionId(),\n\t\t\tcreatedAt: createTimestamp(),\n\t\t};\n\t\tconst storage = new InMemorySessionStorage({ metadata });\n\t\tconst session = toSession(storage);\n\t\tthis.sessions.set(metadata.id, session);\n\t\treturn session;\n\t}\n\n\tasync open(metadata: SessionMetadata): Promise<Session<SessionMetadata>> {\n\t\tconst session = this.sessions.get(metadata.id);\n\t\tif (!session) {\n\t\t\tthrow new SessionError(\"not_found\", `Session not found: ${metadata.id}`);\n\t\t}\n\t\treturn session;\n\t}\n\n\tasync list(): Promise<SessionMetadata[]> {\n\t\treturn Promise.all([...this.sessions.values()].map((session) => session.getMetadata()));\n\t}\n\n\tasync delete(metadata: SessionMetadata): Promise<void> {\n\t\tthis.sessions.delete(metadata.id);\n\t}\n\n\tasync fork(sourceMetadata: SessionMetadata, options: SessionForkOptions): Promise<Session<SessionMetadata>> {\n\t\tconst source = await this.open(sourceMetadata);\n\t\tconst forkedEntries = await getEntriesToFork(source.getStorage(), options);\n\t\tconst metadata: SessionMetadata = {\n\t\t\tid: options.id ?? createSessionId(),\n\t\t\tcreatedAt: createTimestamp(),\n\t\t};\n\t\tconst storage = new InMemorySessionStorage({ metadata, entries: forkedEntries });\n\t\tconst session = toSession(storage);\n\t\tthis.sessions.set(metadata.id, session);\n\t\treturn session;\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"memory-storage.d.ts","sourceRoot":"","sources":["../../../src/harness/session/memory-storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,MAAM,aAAa,CAAC;AAuCrB,UAAU,6BAA6B,CAAC,SAAS;IAChD,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC7B,QAAQ,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,qBAAa,sBAAsB,CAAC,SAAS,SAAS,eAAe,GAAG,eAAe,CACtF,YAAW,cAAc,CAAC,SAAS,CAAC;IAEpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAY;IACrC,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,IAAI,CAAgC;IAC5C,OAAO,CAAC,UAAU,CAAsB;IACxC,OAAO,CAAC,MAAM,CAAgB;IAE9B,YAAY,OAAO,CAAC,EAAE,6BAA6B,CAAC,SAAS,CAAC,EAU7D;IAEK,WAAW,IAAI,OAAO,CAAC,SAAS,CAAC,CAEtC;IAEK,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAKxC;IAEK,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAcpD;IAEK,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAErC;IAEK,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAKxD;IAEK,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAEhE;IAEK,WAAW,CAAC,KAAK,SAAS,gBAAgB,CAAC,MAAM,CAAC,EACvD,IAAI,EAAE,KAAK,GACT,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAC,CAAC,CAE/C;IAEK,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAEtD;IAEK,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAatE;IAEK,UAAU,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAE9C;CACD","sourcesContent":["import {\n\ttype LeafEntry,\n\tSessionError,\n\ttype SessionMetadata,\n\ttype SessionStorage,\n\ttype SessionTreeEntry,\n\ttype SessionTreeEntryOfType,\n} from \"../types.ts\";\nimport { uuidv7 } from \"./uuid.ts\";\n\nfunction updateLabelCache(labelsById: Map<string, string>, entry: SessionTreeEntry): void {\n\tif (entry.type !== \"label\") return;\n\tconst label = entry.label?.trim();\n\tif (label) {\n\t\tlabelsById.set(entry.targetId, label);\n\t} else {\n\t\tlabelsById.delete(entry.targetId);\n\t}\n}\n\nfunction buildLabelsById(entries: SessionTreeEntry[]): Map<string, string> {\n\tconst labelsById = new Map<string, string>();\n\tfor (const entry of entries) {\n\t\tupdateLabelCache(labelsById, entry);\n\t}\n\treturn labelsById;\n}\n\ninterface SessionEntryIdLookup {\n\thas(id: string): boolean;\n}\n\nfunction generateEntryId(byId: SessionEntryIdLookup): string {\n\tfor (let i = 0; i < 100; i++) {\n\t\t// The uuidv7 prefix is timestamp-derived and nearly constant between calls,\n\t\t// so short ids must come from the random tail.\n\t\tconst id = uuidv7().slice(-8);\n\t\tif (!byId.has(id)) return id;\n\t}\n\treturn uuidv7();\n}\n\nfunction leafIdAfterEntry(entry: SessionTreeEntry): string | null {\n\treturn entry.type === \"leaf\" ? entry.targetId : entry.id;\n}\n\ninterface InMemorySessionStorageOptions<TMetadata> {\n\tentries?: SessionTreeEntry[];\n\tmetadata?: TMetadata;\n}\n\nexport class InMemorySessionStorage<TMetadata extends SessionMetadata = SessionMetadata>\n\timplements SessionStorage<TMetadata>\n{\n\tprivate readonly metadata: TMetadata;\n\tprivate entries: SessionTreeEntry[];\n\tprivate byId: Map<string, SessionTreeEntry>;\n\tprivate labelsById: Map<string, string>;\n\tprivate leafId: string | null;\n\n\tconstructor(options?: InMemorySessionStorageOptions<TMetadata>) {\n\t\tthis.entries = options?.entries ? [...options.entries] : [];\n\t\tthis.byId = new Map(this.entries.map((entry) => [entry.id, entry]));\n\t\tthis.labelsById = buildLabelsById(this.entries);\n\t\tthis.leafId = null;\n\t\tfor (const entry of this.entries) this.leafId = leafIdAfterEntry(entry);\n\t\tif (this.leafId !== null && !this.byId.has(this.leafId)) {\n\t\t\tthrow new SessionError(\"invalid_session\", `Entry ${this.leafId} not found`);\n\t\t}\n\t\tthis.metadata = options?.metadata ?? ({ id: uuidv7(), createdAt: new Date().toISOString() } as TMetadata);\n\t}\n\n\tasync getMetadata(): Promise<TMetadata> {\n\t\treturn this.metadata;\n\t}\n\n\tasync getLeafId(): Promise<string | null> {\n\t\tif (this.leafId !== null && !this.byId.has(this.leafId)) {\n\t\t\tthrow new SessionError(\"invalid_session\", `Entry ${this.leafId} not found`);\n\t\t}\n\t\treturn this.leafId;\n\t}\n\n\tasync setLeafId(leafId: string | null): Promise<void> {\n\t\tif (leafId !== null && !this.byId.has(leafId)) {\n\t\t\tthrow new SessionError(\"not_found\", `Entry ${leafId} not found`);\n\t\t}\n\t\tconst entry: LeafEntry = {\n\t\t\ttype: \"leaf\",\n\t\t\tid: generateEntryId(this.byId),\n\t\t\tparentId: this.leafId,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\ttargetId: leafId,\n\t\t};\n\t\tthis.entries.push(entry);\n\t\tthis.byId.set(entry.id, entry);\n\t\tthis.leafId = leafId;\n\t}\n\n\tasync createEntryId(): Promise<string> {\n\t\treturn generateEntryId(this.byId);\n\t}\n\n\tasync appendEntry(entry: SessionTreeEntry): Promise<void> {\n\t\tthis.entries.push(entry);\n\t\tthis.byId.set(entry.id, entry);\n\t\tupdateLabelCache(this.labelsById, entry);\n\t\tthis.leafId = leafIdAfterEntry(entry);\n\t}\n\n\tasync getEntry(id: string): Promise<SessionTreeEntry | undefined> {\n\t\treturn this.byId.get(id);\n\t}\n\n\tasync findEntries<TType extends SessionTreeEntry[\"type\"]>(\n\t\ttype: TType,\n\t): Promise<Array<SessionTreeEntryOfType<TType>>> {\n\t\treturn this.entries.filter((entry): entry is SessionTreeEntryOfType<TType> => entry.type === type);\n\t}\n\n\tasync getLabel(id: string): Promise<string | undefined> {\n\t\treturn this.labelsById.get(id);\n\t}\n\n\tasync getPathToRoot(leafId: string | null): Promise<SessionTreeEntry[]> {\n\t\tif (leafId === null) return [];\n\t\tconst path: SessionTreeEntry[] = [];\n\t\tlet current = this.byId.get(leafId);\n\t\tif (!current) throw new SessionError(\"not_found\", `Entry ${leafId} not found`);\n\t\twhile (current) {\n\t\t\tpath.unshift(current);\n\t\t\tif (!current.parentId) break;\n\t\t\tconst parent = this.byId.get(current.parentId);\n\t\t\tif (!parent) throw new SessionError(\"invalid_session\", `Entry ${current.parentId} not found`);\n\t\t\tcurrent = parent;\n\t\t}\n\t\treturn path;\n\t}\n\n\tasync getEntries(): Promise<SessionTreeEntry[]> {\n\t\treturn [...this.entries];\n\t}\n}\n"]}
1
+ {"version":3,"file":"memory-storage.d.ts","sourceRoot":"","sources":["../../../src/harness/session/memory-storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,MAAM,aAAa,CAAC;AAuCrB,UAAU,6BAA6B,CAAC,SAAS;IAChD,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC7B,QAAQ,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,qBAAa,sBAAsB,CAAC,SAAS,SAAS,eAAe,GAAG,eAAe,CACtF,YAAW,cAAc,CAAC,SAAS,CAAC;IAEpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAY;IACrC,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,IAAI,CAAgC;IAC5C,OAAO,CAAC,UAAU,CAAsB;IACxC,OAAO,CAAC,MAAM,CAAgB;IAE9B,YAAY,OAAO,CAAC,EAAE,6BAA6B,CAAC,SAAS,CAAC,EAU7D;IAEK,WAAW,IAAI,OAAO,CAAC,SAAS,CAAC,CAEtC;IAEK,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAKxC;IAEK,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAcpD;IAEK,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAErC;IAEK,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAKxD;IAEK,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAEhE;IAEK,WAAW,CAAC,KAAK,SAAS,gBAAgB,CAAC,MAAM,CAAC,EACvD,IAAI,EAAE,KAAK,GACT,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAC,CAAC,CAE/C;IAEK,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAEtD;IAEK,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAatE;IAEK,UAAU,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAE9C;CACD"}
@@ -32,11 +32,6 @@ function leafIdAfterEntry(entry) {
32
32
  return entry.type === "leaf" ? entry.targetId : entry.id;
33
33
  }
34
34
  export class InMemorySessionStorage {
35
- metadata;
36
- entries;
37
- byId;
38
- labelsById;
39
- leafId;
40
35
  constructor(options) {
41
36
  this.entries = options?.entries ? [...options.entries] : [];
42
37
  this.byId = new Map(this.entries.map((entry) => [entry.id, entry]));