@geminixiang/mikan 1.0.0-beta.44 → 1.0.0-beta.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,12 @@ any release.
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
## [1.0.0-beta.45]
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Session migration now collapses crash-duplicated v3 lines (a retried append writing the same header and entry twice) the way the v3 reader did, instead of failing v4 verification on the duplicate id. Found rehearsing the migration against 5,446 production session files; after the fix all migrate and reopen cleanly.
|
|
17
|
+
|
|
12
18
|
## [1.0.0-beta.44]
|
|
13
19
|
|
|
14
20
|
### Added
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate-v3.d.ts","sourceRoot":"","sources":["../../src/sessions/migrate-v3.ts"],"names":[],"mappings":"AA2FA,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAUzD;
|
|
1
|
+
{"version":3,"file":"migrate-v3.d.ts","sourceRoot":"","sources":["../../src/sessions/migrate-v3.ts"],"names":[],"mappings":"AA2FA,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAUzD;AA0SD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,GAAG,YAAY,GAAG,SAAS,CAAC;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAsBD;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7B,OAAO,CAAC,aAAa,CAAC,CAgBxB;AAED,0EAA0E;AAC1E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAqBzD"}
|
|
@@ -57,9 +57,23 @@ function readV3SessionFile(filePath) {
|
|
|
57
57
|
if (!header || header.type !== "session" || typeof header.id !== "string") {
|
|
58
58
|
throw new Error(`Not a v3 session file: ${filePath}`);
|
|
59
59
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
// Crash-era v3 files can contain duplicated lines (a retried append wrote
|
|
61
|
+
// the header+entry pair twice). The v3 runtime read entries into a Map, so
|
|
62
|
+
// duplicates were silently collapsed; v4 rejects duplicate mutation ids.
|
|
63
|
+
// Reproduce the v3 semantics: keep one entry per id, drop stray repeated
|
|
64
|
+
// session headers.
|
|
65
|
+
const seen = new Set();
|
|
66
|
+
const entries = [];
|
|
67
|
+
for (const record of records.slice(1)) {
|
|
68
|
+
if (typeof record.type !== "string" || typeof record.id !== "string")
|
|
69
|
+
continue;
|
|
70
|
+
if (record.type === "session")
|
|
71
|
+
continue;
|
|
72
|
+
if (seen.has(record.id))
|
|
73
|
+
continue;
|
|
74
|
+
seen.add(record.id);
|
|
75
|
+
entries.push(record);
|
|
76
|
+
}
|
|
63
77
|
return { header: header, entries };
|
|
64
78
|
}
|
|
65
79
|
function toEpochMillis(timestamp) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate-v3.js","sourceRoot":"","sources":["../../src/sessions/migrate-v3.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * One-time migration of legacy v3 session files to pi's v4 JSONL format.\n *\n * v3 is the entry family mikan wrote up to pi 0.83: a `{\"type\":\"session\"}`\n * header followed by tree entries with string ISO timestamps and compaction\n * entries that point at `firstKeptEntryId`. v4 (pi 0.84+) uses a\n * `{\"kind\":\"header\",\"version\":4}` header followed by mutation lines whose\n * entries carry numeric timestamps and a consecutive `seq`, with compaction\n * retention stored inline as `retainedTail`.\n *\n * The migration preserves entry ids, parent links, and timestamps, converts\n * `custom_message` entries into v4 `custom`-role messages, folds\n * `session_info` into the v4 name fact, `label` entries into label facts,\n * and rewrites each compaction's kept range into its inline `retainedTail`.\n * Every migrated file is verified before it replaces the original: the v4\n * file is re-opened with pi's reader and its built context must equal the\n * v3 context computed by the reference converter below. The original file\n * is kept beside the migrated one as `<name>.v3.bak`.\n */\nimport { existsSync, readdirSync, readFileSync, renameSync, rmSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n buildSessionContext,\n createCustomMessage,\n type AgentMessage,\n type Entry as PiEntry,\n type JsonlV4Header,\n} from \"@earendil-works/pi-agent-core\";\nimport { SessionStore } from \"../harness/session-store.js\";\nimport { atomicWritePrivateFile } from \"../utils/file-guards.js\";\n\n// ── v3 shapes ────────────────────────────────────────────────────────────────\n\ninterface V3EntryBase {\n type: string;\n id: string;\n parentId: string | null;\n timestamp: string;\n}\n\ntype V3Entry = V3EntryBase &\n (\n | { type: \"message\"; message: AgentMessage }\n | { type: \"thinking_level_change\"; thinkingLevel: string }\n | { type: \"model_change\"; provider: string; modelId: string }\n | { type: \"active_tools_change\"; activeToolNames: string[] }\n | {\n type: \"compaction\";\n summary: string;\n firstKeptEntryId?: string;\n tokensBefore: number;\n retainedTail?: AgentMessage[];\n details?: unknown;\n usage?: unknown;\n }\n | {\n type: \"branch_summary\";\n fromId: string;\n summary: string;\n details?: unknown;\n usage?: unknown;\n }\n | { type: \"custom\"; customType: string; data?: unknown }\n | {\n type: \"custom_message\";\n customType: string;\n content: Parameters<typeof createCustomMessage>[1];\n display: boolean;\n details?: unknown;\n }\n | { type: \"label\"; targetId: string; label: string | undefined }\n | { type: \"session_info\"; name?: string }\n | { type: \"leaf\"; targetId: string | null }\n );\n\ninterface V3SessionHeader {\n type: \"session\";\n version?: number;\n id: string;\n timestamp: string;\n cwd: string;\n parentSession?: string;\n parentSessionId?: string;\n [extra: string]: unknown;\n}\n\ninterface V3SessionFile {\n header: V3SessionHeader;\n entries: V3Entry[];\n}\n\n/** Whether a file's first non-empty line is a v3 session header. */\nexport function isV3SessionFile(filePath: string): boolean {\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const firstLine = content.split(\"\\n\").find((line) => line.trim().length > 0);\n if (!firstLine) return false;\n const parsed = JSON.parse(firstLine) as { type?: unknown };\n return parsed.type === \"session\";\n } catch {\n return false;\n }\n}\n\n/** Read a v3 session file, ignoring a torn final line (crash tail). */\nfunction readV3SessionFile(filePath: string): V3SessionFile {\n const lines = readFileSync(filePath, \"utf-8\")\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line.length > 0);\n const records: Record<string, unknown>[] = [];\n for (const [index, line] of lines.entries()) {\n try {\n records.push(JSON.parse(line) as Record<string, unknown>);\n } catch (error) {\n if (index === lines.length - 1 && index > 0) continue;\n throw new Error(`Invalid JSON on line ${index + 1} of ${filePath}`, { cause: error });\n }\n }\n const header = records[0];\n if (!header || header.type !== \"session\" || typeof header.id !== \"string\") {\n throw new Error(`Not a v3 session file: ${filePath}`);\n }\n const entries = records\n .slice(1)\n .filter(\n (record): record is Record<string, unknown> & { id: string } =>\n typeof record.type === \"string\" && typeof record.id === \"string\",\n ) as unknown as V3Entry[];\n return { header: header as unknown as V3SessionHeader, entries };\n}\n\nfunction toEpochMillis(timestamp: string): number {\n const parsed = Date.parse(timestamp);\n return Number.isNaN(parsed) ? 0 : parsed;\n}\n\n/** Walk a v3 tree from an entry to the root; returns root-first path order. */\nfunction v3Branch(entries: V3Entry[], fromId: string | null): V3Entry[] {\n const byId = new Map(entries.map((entry) => [entry.id, entry]));\n const path: V3Entry[] = [];\n let currentId = fromId;\n while (currentId) {\n const entry = byId.get(currentId);\n if (!entry) break;\n path.push(entry);\n currentId = entry.parentId;\n }\n return path.toReversed();\n}\n\nfunction v3LeafId(entries: V3Entry[]): string | null {\n let leafId: string | null = null;\n for (const entry of entries) {\n leafId = entry.type === \"leaf\" ? entry.targetId : entry.id;\n }\n return leafId;\n}\n\n/** Convert one tree-shaping v3 entry to its v4 counterpart (facts excluded). */\nfunction convertEntry(entry: V3Entry, entries: V3Entry[]): PiEntry | null {\n const base = {\n id: entry.id,\n seq: 0, // assigned at mutation-encoding time\n parentId: resolveV4Parent(entry, entries),\n timestamp: toEpochMillis(entry.timestamp),\n };\n switch (entry.type) {\n case \"message\":\n return { ...base, type: \"message\", message: entry.message };\n case \"custom_message\":\n return {\n ...base,\n type: \"message\",\n message: createCustomMessage(\n entry.customType,\n entry.content,\n entry.display,\n entry.details,\n toEpochMillis(entry.timestamp),\n ),\n };\n case \"thinking_level_change\":\n return { ...base, type: \"thinking_level_change\", thinkingLevel: entry.thinkingLevel };\n case \"model_change\":\n return { ...base, type: \"model_change\", provider: entry.provider, modelId: entry.modelId };\n case \"active_tools_change\":\n return { ...base, type: \"active_tools_change\", activeToolNames: entry.activeToolNames };\n case \"compaction\":\n return {\n ...base,\n type: \"compaction\",\n summary: entry.summary,\n retainedTail: entry.retainedTail ?? compactionKeptMessages(entry, entries),\n tokensBefore: entry.tokensBefore,\n ...(entry.details !== undefined ? { details: entry.details } : {}),\n ...(entry.usage !== undefined ? { usage: entry.usage as PiEntry & object } : {}),\n } as unknown as PiEntry;\n case \"branch_summary\":\n return {\n ...base,\n type: \"branch_summary\",\n fromId: entry.fromId,\n summary: entry.summary,\n ...(entry.details !== undefined ? { details: entry.details } : {}),\n ...(entry.usage !== undefined ? { usage: entry.usage } : {}),\n } as unknown as PiEntry;\n case \"custom\":\n return { ...base, type: \"custom\", customType: entry.customType, data: entry.data };\n default:\n // session_info / label / leaf become facts and the lane pointer.\n return null;\n }\n}\n\n/**\n * Skip fact-only ancestors (session_info/label/leaf) when re-linking the v4\n * tree: those entries disappear from the entry stream, so children re-attach\n * to the nearest surviving ancestor.\n */\nfunction resolveV4Parent(entry: V3Entry, entries: V3Entry[]): string | null {\n const byId = new Map(entries.map((item) => [item.id, item]));\n let parentId = entry.parentId;\n while (parentId !== null) {\n const parent = byId.get(parentId);\n if (!parent) return null;\n if (parent.type !== \"session_info\" && parent.type !== \"label\" && parent.type !== \"leaf\") {\n return parentId;\n }\n parentId = parent.parentId;\n }\n return null;\n}\n\n/**\n * Messages of the v3 kept range (`firstKeptEntryId` .. compaction parent),\n * which v4 stores inline on the compaction entry.\n */\nfunction compactionKeptMessages(\n compaction: Extract<V3Entry, { type: \"compaction\" }>,\n entries: V3Entry[],\n): AgentMessage[] {\n if (!compaction.firstKeptEntryId) return [];\n const ancestors = v3Branch(entries, compaction.parentId);\n const keptStart = ancestors.findIndex((entry) => entry.id === compaction.firstKeptEntryId);\n if (keptStart === -1) return [];\n const messages: AgentMessage[] = [];\n for (const entry of ancestors.slice(keptStart)) {\n if (entry.type === \"message\") messages.push(entry.message);\n else if (entry.type === \"custom_message\") {\n messages.push(\n createCustomMessage(\n entry.customType,\n entry.content,\n entry.display,\n entry.details,\n toEpochMillis(entry.timestamp),\n ),\n );\n }\n }\n return messages;\n}\n\n// ── reference converter (verification oracle) ───────────────────────────────\n\n/**\n * Convert a v3 branch to v4 entries with the pi-0.83 context semantics:\n * the last compaction is repositioned ahead of its kept range so pi's v4\n * transform reproduces the v3 context exactly. This mirrors what the\n * runtime shim did before mikan moved to native v4 files, and serves as\n * the verification oracle for migrated output.\n */\nfunction referenceContextEntries(branch: V3Entry[]): PiEntry[] {\n let lastCompactionIndex = -1;\n for (let i = branch.length - 1; i >= 0; i--) {\n if (branch[i]?.type === \"compaction\") {\n lastCompactionIndex = i;\n break;\n }\n }\n const lastCompaction = branch[lastCompactionIndex] as\n | Extract<V3Entry, { type: \"compaction\" }>\n | undefined;\n const firstKeptId =\n lastCompaction && !lastCompaction.retainedTail ? lastCompaction.firstKeptEntryId : undefined;\n const firstKeptIndex =\n firstKeptId === undefined ? -1 : branch.findIndex((entry) => entry.id === firstKeptId);\n\n const ordered: V3Entry[] = [];\n if (firstKeptIndex !== -1 && lastCompaction) {\n ordered.push(...branch.slice(0, firstKeptIndex));\n ordered.push(lastCompaction);\n for (const [index, entry] of branch.entries()) {\n if (index >= firstKeptIndex && index !== lastCompactionIndex) ordered.push(entry);\n }\n } else {\n ordered.push(...branch);\n }\n\n const converted: PiEntry[] = [];\n for (const entry of ordered) {\n if (entry.type === \"compaction\" && entry === lastCompaction && firstKeptIndex !== -1) {\n converted.push({\n type: \"compaction\",\n id: entry.id,\n seq: 0,\n parentId: null,\n timestamp: toEpochMillis(entry.timestamp),\n summary: entry.summary,\n retainedTail: [],\n tokensBefore: entry.tokensBefore,\n });\n continue;\n }\n const piEntry = convertEntry(entry, []);\n if (piEntry) converted.push(piEntry);\n }\n let previousId: string | null = null;\n for (const [index, entry] of converted.entries()) {\n entry.seq = index;\n entry.parentId = previousId;\n previousId = entry.id;\n }\n return converted;\n}\n\n// ── v4 encoding ─────────────────────────────────────────────────────────────\n\nfunction buildV4Header(header: V3SessionHeader): JsonlV4Header {\n const {\n type: _type,\n version: _version,\n id,\n timestamp,\n cwd,\n parentSession,\n parentSessionId,\n ...extras\n } = header;\n const metadata: Record<string, unknown> = { ...extras };\n if (parentSession !== undefined) metadata.parentSessionPath = parentSession;\n return {\n kind: \"header\",\n version: 4,\n id,\n createdAt: toEpochMillis(timestamp),\n cwd,\n ...(parentSessionId !== undefined ? { parentSessionId } : {}),\n ...(Object.keys(metadata).length > 0\n ? { metadata: metadata as JsonlV4Header[\"metadata\"] }\n : {}),\n };\n}\n\nfunction encodeV4File(file: V3SessionFile): string {\n const lines: string[] = [JSON.stringify(buildV4Header(file.header))];\n let seq = 0;\n const push = (mutation: Record<string, unknown>) => {\n lines.push(JSON.stringify(mutation));\n };\n\n let name: string | undefined;\n const labels: Array<{ targetId: string; label: string | undefined }> = [];\n for (const entry of file.entries) {\n if (entry.type === \"session_info\") {\n name = entry.name?.trim() || undefined;\n continue;\n }\n if (entry.type === \"label\") {\n labels.push({ targetId: entry.targetId, label: entry.label });\n continue;\n }\n if (entry.type === \"leaf\") continue;\n const converted = convertEntry(entry, file.entries);\n if (!converted) continue;\n converted.seq = ++seq;\n // Entry mutations are encoded flat: {kind:\"entry\", ...entry fields}.\n push({ kind: \"entry\", ...converted });\n }\n\n const leafId = v3LeafId(file.entries);\n push({ kind: \"lane\", seq: ++seq, lane: \"main\", leafId });\n if (name !== undefined) push({ kind: \"fact\", seq: ++seq, fact: \"name\", name });\n for (const { targetId, label } of labels) {\n push({ kind: \"fact\", seq: ++seq, fact: \"label\", targetId, label });\n }\n return `${lines.join(\"\\n\")}\\n`;\n}\n\n// ── migration driver ────────────────────────────────────────────────────────\n\nexport interface MigrateResult {\n file: string;\n status: \"migrated\" | \"already-v4\" | \"skipped\";\n detail?: string;\n}\n\nasync function verifyMigratedFile(v4Path: string, source: V3SessionFile): Promise<void> {\n const store = await SessionStore.inspect(v4Path);\n const migratedContext = await store.buildSessionContext();\n const branch = v3Branch(source.entries, v3LeafId(source.entries));\n const referenceContext = buildSessionContext(referenceContextEntries(branch));\n const migrated = JSON.stringify(migratedContext.messages);\n const reference = JSON.stringify(referenceContext.messages);\n if (migrated !== reference) {\n throw new Error(\"migrated context does not match the v3 reference context\");\n }\n const migratedName = await store.getSessionName();\n const v3Name = [...source.entries]\n .toReversed()\n .find((entry) => entry.type === \"session_info\")\n ?.name?.trim();\n if ((migratedName ?? \"\") !== (v3Name || \"\")) {\n throw new Error(\"migrated session name does not match the v3 session name\");\n }\n}\n\n/**\n * Migrate one session file in place. The migrated file is verified against\n * the v3 reference semantics before it replaces the original; the original\n * is preserved as `<file>.v3.bak`.\n */\nexport async function migrateSessionFile(\n filePath: string,\n options?: { dryRun?: boolean },\n): Promise<MigrateResult> {\n if (!isV3SessionFile(filePath)) return { file: filePath, status: \"already-v4\" };\n const source = readV3SessionFile(filePath);\n if (options?.dryRun) return { file: filePath, status: \"migrated\", detail: \"dry run\" };\n\n const tempPath = `${filePath}.v4.tmp`;\n atomicWritePrivateFile(tempPath, encodeV4File(source));\n try {\n await verifyMigratedFile(tempPath, source);\n } catch (error) {\n rmSync(tempPath, { force: true });\n throw new Error(`Verification failed for ${filePath}`, { cause: error });\n }\n renameSync(filePath, `${filePath}.v3.bak`);\n renameSync(tempPath, filePath);\n return { file: filePath, status: \"migrated\" };\n}\n\n/** Recursively find candidate session files (.jsonl with a v3 header). */\nexport function findV3SessionFiles(root: string): string[] {\n if (!existsSync(root)) return [];\n const found: string[] = [];\n const walk = (dir: string) => {\n for (const name of readdirSync(dir)) {\n const path = join(dir, name);\n let stats;\n try {\n stats = statSync(path);\n } catch {\n continue;\n }\n if (stats.isDirectory()) {\n walk(path);\n } else if (name.endsWith(\".jsonl\") && isV3SessionFile(path)) {\n found.push(path);\n }\n }\n };\n walk(root);\n return found;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"migrate-v3.js","sourceRoot":"","sources":["../../src/sessions/migrate-v3.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * One-time migration of legacy v3 session files to pi's v4 JSONL format.\n *\n * v3 is the entry family mikan wrote up to pi 0.83: a `{\"type\":\"session\"}`\n * header followed by tree entries with string ISO timestamps and compaction\n * entries that point at `firstKeptEntryId`. v4 (pi 0.84+) uses a\n * `{\"kind\":\"header\",\"version\":4}` header followed by mutation lines whose\n * entries carry numeric timestamps and a consecutive `seq`, with compaction\n * retention stored inline as `retainedTail`.\n *\n * The migration preserves entry ids, parent links, and timestamps, converts\n * `custom_message` entries into v4 `custom`-role messages, folds\n * `session_info` into the v4 name fact, `label` entries into label facts,\n * and rewrites each compaction's kept range into its inline `retainedTail`.\n * Every migrated file is verified before it replaces the original: the v4\n * file is re-opened with pi's reader and its built context must equal the\n * v3 context computed by the reference converter below. The original file\n * is kept beside the migrated one as `<name>.v3.bak`.\n */\nimport { existsSync, readdirSync, readFileSync, renameSync, rmSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n buildSessionContext,\n createCustomMessage,\n type AgentMessage,\n type Entry as PiEntry,\n type JsonlV4Header,\n} from \"@earendil-works/pi-agent-core\";\nimport { SessionStore } from \"../harness/session-store.js\";\nimport { atomicWritePrivateFile } from \"../utils/file-guards.js\";\n\n// ── v3 shapes ────────────────────────────────────────────────────────────────\n\ninterface V3EntryBase {\n type: string;\n id: string;\n parentId: string | null;\n timestamp: string;\n}\n\ntype V3Entry = V3EntryBase &\n (\n | { type: \"message\"; message: AgentMessage }\n | { type: \"thinking_level_change\"; thinkingLevel: string }\n | { type: \"model_change\"; provider: string; modelId: string }\n | { type: \"active_tools_change\"; activeToolNames: string[] }\n | {\n type: \"compaction\";\n summary: string;\n firstKeptEntryId?: string;\n tokensBefore: number;\n retainedTail?: AgentMessage[];\n details?: unknown;\n usage?: unknown;\n }\n | {\n type: \"branch_summary\";\n fromId: string;\n summary: string;\n details?: unknown;\n usage?: unknown;\n }\n | { type: \"custom\"; customType: string; data?: unknown }\n | {\n type: \"custom_message\";\n customType: string;\n content: Parameters<typeof createCustomMessage>[1];\n display: boolean;\n details?: unknown;\n }\n | { type: \"label\"; targetId: string; label: string | undefined }\n | { type: \"session_info\"; name?: string }\n | { type: \"leaf\"; targetId: string | null }\n );\n\ninterface V3SessionHeader {\n type: \"session\";\n version?: number;\n id: string;\n timestamp: string;\n cwd: string;\n parentSession?: string;\n parentSessionId?: string;\n [extra: string]: unknown;\n}\n\ninterface V3SessionFile {\n header: V3SessionHeader;\n entries: V3Entry[];\n}\n\n/** Whether a file's first non-empty line is a v3 session header. */\nexport function isV3SessionFile(filePath: string): boolean {\n try {\n const content = readFileSync(filePath, \"utf-8\");\n const firstLine = content.split(\"\\n\").find((line) => line.trim().length > 0);\n if (!firstLine) return false;\n const parsed = JSON.parse(firstLine) as { type?: unknown };\n return parsed.type === \"session\";\n } catch {\n return false;\n }\n}\n\n/** Read a v3 session file, ignoring a torn final line (crash tail). */\nfunction readV3SessionFile(filePath: string): V3SessionFile {\n const lines = readFileSync(filePath, \"utf-8\")\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line.length > 0);\n const records: Record<string, unknown>[] = [];\n for (const [index, line] of lines.entries()) {\n try {\n records.push(JSON.parse(line) as Record<string, unknown>);\n } catch (error) {\n if (index === lines.length - 1 && index > 0) continue;\n throw new Error(`Invalid JSON on line ${index + 1} of ${filePath}`, { cause: error });\n }\n }\n const header = records[0];\n if (!header || header.type !== \"session\" || typeof header.id !== \"string\") {\n throw new Error(`Not a v3 session file: ${filePath}`);\n }\n // Crash-era v3 files can contain duplicated lines (a retried append wrote\n // the header+entry pair twice). The v3 runtime read entries into a Map, so\n // duplicates were silently collapsed; v4 rejects duplicate mutation ids.\n // Reproduce the v3 semantics: keep one entry per id, drop stray repeated\n // session headers.\n const seen = new Set<string>();\n const entries: V3Entry[] = [];\n for (const record of records.slice(1)) {\n if (typeof record.type !== \"string\" || typeof record.id !== \"string\") continue;\n if (record.type === \"session\") continue;\n if (seen.has(record.id)) continue;\n seen.add(record.id);\n entries.push(record as unknown as V3Entry);\n }\n return { header: header as unknown as V3SessionHeader, entries };\n}\n\nfunction toEpochMillis(timestamp: string): number {\n const parsed = Date.parse(timestamp);\n return Number.isNaN(parsed) ? 0 : parsed;\n}\n\n/** Walk a v3 tree from an entry to the root; returns root-first path order. */\nfunction v3Branch(entries: V3Entry[], fromId: string | null): V3Entry[] {\n const byId = new Map(entries.map((entry) => [entry.id, entry]));\n const path: V3Entry[] = [];\n let currentId = fromId;\n while (currentId) {\n const entry = byId.get(currentId);\n if (!entry) break;\n path.push(entry);\n currentId = entry.parentId;\n }\n return path.toReversed();\n}\n\nfunction v3LeafId(entries: V3Entry[]): string | null {\n let leafId: string | null = null;\n for (const entry of entries) {\n leafId = entry.type === \"leaf\" ? entry.targetId : entry.id;\n }\n return leafId;\n}\n\n/** Convert one tree-shaping v3 entry to its v4 counterpart (facts excluded). */\nfunction convertEntry(entry: V3Entry, entries: V3Entry[]): PiEntry | null {\n const base = {\n id: entry.id,\n seq: 0, // assigned at mutation-encoding time\n parentId: resolveV4Parent(entry, entries),\n timestamp: toEpochMillis(entry.timestamp),\n };\n switch (entry.type) {\n case \"message\":\n return { ...base, type: \"message\", message: entry.message };\n case \"custom_message\":\n return {\n ...base,\n type: \"message\",\n message: createCustomMessage(\n entry.customType,\n entry.content,\n entry.display,\n entry.details,\n toEpochMillis(entry.timestamp),\n ),\n };\n case \"thinking_level_change\":\n return { ...base, type: \"thinking_level_change\", thinkingLevel: entry.thinkingLevel };\n case \"model_change\":\n return { ...base, type: \"model_change\", provider: entry.provider, modelId: entry.modelId };\n case \"active_tools_change\":\n return { ...base, type: \"active_tools_change\", activeToolNames: entry.activeToolNames };\n case \"compaction\":\n return {\n ...base,\n type: \"compaction\",\n summary: entry.summary,\n retainedTail: entry.retainedTail ?? compactionKeptMessages(entry, entries),\n tokensBefore: entry.tokensBefore,\n ...(entry.details !== undefined ? { details: entry.details } : {}),\n ...(entry.usage !== undefined ? { usage: entry.usage as PiEntry & object } : {}),\n } as unknown as PiEntry;\n case \"branch_summary\":\n return {\n ...base,\n type: \"branch_summary\",\n fromId: entry.fromId,\n summary: entry.summary,\n ...(entry.details !== undefined ? { details: entry.details } : {}),\n ...(entry.usage !== undefined ? { usage: entry.usage } : {}),\n } as unknown as PiEntry;\n case \"custom\":\n return { ...base, type: \"custom\", customType: entry.customType, data: entry.data };\n default:\n // session_info / label / leaf become facts and the lane pointer.\n return null;\n }\n}\n\n/**\n * Skip fact-only ancestors (session_info/label/leaf) when re-linking the v4\n * tree: those entries disappear from the entry stream, so children re-attach\n * to the nearest surviving ancestor.\n */\nfunction resolveV4Parent(entry: V3Entry, entries: V3Entry[]): string | null {\n const byId = new Map(entries.map((item) => [item.id, item]));\n let parentId = entry.parentId;\n while (parentId !== null) {\n const parent = byId.get(parentId);\n if (!parent) return null;\n if (parent.type !== \"session_info\" && parent.type !== \"label\" && parent.type !== \"leaf\") {\n return parentId;\n }\n parentId = parent.parentId;\n }\n return null;\n}\n\n/**\n * Messages of the v3 kept range (`firstKeptEntryId` .. compaction parent),\n * which v4 stores inline on the compaction entry.\n */\nfunction compactionKeptMessages(\n compaction: Extract<V3Entry, { type: \"compaction\" }>,\n entries: V3Entry[],\n): AgentMessage[] {\n if (!compaction.firstKeptEntryId) return [];\n const ancestors = v3Branch(entries, compaction.parentId);\n const keptStart = ancestors.findIndex((entry) => entry.id === compaction.firstKeptEntryId);\n if (keptStart === -1) return [];\n const messages: AgentMessage[] = [];\n for (const entry of ancestors.slice(keptStart)) {\n if (entry.type === \"message\") messages.push(entry.message);\n else if (entry.type === \"custom_message\") {\n messages.push(\n createCustomMessage(\n entry.customType,\n entry.content,\n entry.display,\n entry.details,\n toEpochMillis(entry.timestamp),\n ),\n );\n }\n }\n return messages;\n}\n\n// ── reference converter (verification oracle) ───────────────────────────────\n\n/**\n * Convert a v3 branch to v4 entries with the pi-0.83 context semantics:\n * the last compaction is repositioned ahead of its kept range so pi's v4\n * transform reproduces the v3 context exactly. This mirrors what the\n * runtime shim did before mikan moved to native v4 files, and serves as\n * the verification oracle for migrated output.\n */\nfunction referenceContextEntries(branch: V3Entry[]): PiEntry[] {\n let lastCompactionIndex = -1;\n for (let i = branch.length - 1; i >= 0; i--) {\n if (branch[i]?.type === \"compaction\") {\n lastCompactionIndex = i;\n break;\n }\n }\n const lastCompaction = branch[lastCompactionIndex] as\n | Extract<V3Entry, { type: \"compaction\" }>\n | undefined;\n const firstKeptId =\n lastCompaction && !lastCompaction.retainedTail ? lastCompaction.firstKeptEntryId : undefined;\n const firstKeptIndex =\n firstKeptId === undefined ? -1 : branch.findIndex((entry) => entry.id === firstKeptId);\n\n const ordered: V3Entry[] = [];\n if (firstKeptIndex !== -1 && lastCompaction) {\n ordered.push(...branch.slice(0, firstKeptIndex));\n ordered.push(lastCompaction);\n for (const [index, entry] of branch.entries()) {\n if (index >= firstKeptIndex && index !== lastCompactionIndex) ordered.push(entry);\n }\n } else {\n ordered.push(...branch);\n }\n\n const converted: PiEntry[] = [];\n for (const entry of ordered) {\n if (entry.type === \"compaction\" && entry === lastCompaction && firstKeptIndex !== -1) {\n converted.push({\n type: \"compaction\",\n id: entry.id,\n seq: 0,\n parentId: null,\n timestamp: toEpochMillis(entry.timestamp),\n summary: entry.summary,\n retainedTail: [],\n tokensBefore: entry.tokensBefore,\n });\n continue;\n }\n const piEntry = convertEntry(entry, []);\n if (piEntry) converted.push(piEntry);\n }\n let previousId: string | null = null;\n for (const [index, entry] of converted.entries()) {\n entry.seq = index;\n entry.parentId = previousId;\n previousId = entry.id;\n }\n return converted;\n}\n\n// ── v4 encoding ─────────────────────────────────────────────────────────────\n\nfunction buildV4Header(header: V3SessionHeader): JsonlV4Header {\n const {\n type: _type,\n version: _version,\n id,\n timestamp,\n cwd,\n parentSession,\n parentSessionId,\n ...extras\n } = header;\n const metadata: Record<string, unknown> = { ...extras };\n if (parentSession !== undefined) metadata.parentSessionPath = parentSession;\n return {\n kind: \"header\",\n version: 4,\n id,\n createdAt: toEpochMillis(timestamp),\n cwd,\n ...(parentSessionId !== undefined ? { parentSessionId } : {}),\n ...(Object.keys(metadata).length > 0\n ? { metadata: metadata as JsonlV4Header[\"metadata\"] }\n : {}),\n };\n}\n\nfunction encodeV4File(file: V3SessionFile): string {\n const lines: string[] = [JSON.stringify(buildV4Header(file.header))];\n let seq = 0;\n const push = (mutation: Record<string, unknown>) => {\n lines.push(JSON.stringify(mutation));\n };\n\n let name: string | undefined;\n const labels: Array<{ targetId: string; label: string | undefined }> = [];\n for (const entry of file.entries) {\n if (entry.type === \"session_info\") {\n name = entry.name?.trim() || undefined;\n continue;\n }\n if (entry.type === \"label\") {\n labels.push({ targetId: entry.targetId, label: entry.label });\n continue;\n }\n if (entry.type === \"leaf\") continue;\n const converted = convertEntry(entry, file.entries);\n if (!converted) continue;\n converted.seq = ++seq;\n // Entry mutations are encoded flat: {kind:\"entry\", ...entry fields}.\n push({ kind: \"entry\", ...converted });\n }\n\n const leafId = v3LeafId(file.entries);\n push({ kind: \"lane\", seq: ++seq, lane: \"main\", leafId });\n if (name !== undefined) push({ kind: \"fact\", seq: ++seq, fact: \"name\", name });\n for (const { targetId, label } of labels) {\n push({ kind: \"fact\", seq: ++seq, fact: \"label\", targetId, label });\n }\n return `${lines.join(\"\\n\")}\\n`;\n}\n\n// ── migration driver ────────────────────────────────────────────────────────\n\nexport interface MigrateResult {\n file: string;\n status: \"migrated\" | \"already-v4\" | \"skipped\";\n detail?: string;\n}\n\nasync function verifyMigratedFile(v4Path: string, source: V3SessionFile): Promise<void> {\n const store = await SessionStore.inspect(v4Path);\n const migratedContext = await store.buildSessionContext();\n const branch = v3Branch(source.entries, v3LeafId(source.entries));\n const referenceContext = buildSessionContext(referenceContextEntries(branch));\n const migrated = JSON.stringify(migratedContext.messages);\n const reference = JSON.stringify(referenceContext.messages);\n if (migrated !== reference) {\n throw new Error(\"migrated context does not match the v3 reference context\");\n }\n const migratedName = await store.getSessionName();\n const v3Name = [...source.entries]\n .toReversed()\n .find((entry) => entry.type === \"session_info\")\n ?.name?.trim();\n if ((migratedName ?? \"\") !== (v3Name || \"\")) {\n throw new Error(\"migrated session name does not match the v3 session name\");\n }\n}\n\n/**\n * Migrate one session file in place. The migrated file is verified against\n * the v3 reference semantics before it replaces the original; the original\n * is preserved as `<file>.v3.bak`.\n */\nexport async function migrateSessionFile(\n filePath: string,\n options?: { dryRun?: boolean },\n): Promise<MigrateResult> {\n if (!isV3SessionFile(filePath)) return { file: filePath, status: \"already-v4\" };\n const source = readV3SessionFile(filePath);\n if (options?.dryRun) return { file: filePath, status: \"migrated\", detail: \"dry run\" };\n\n const tempPath = `${filePath}.v4.tmp`;\n atomicWritePrivateFile(tempPath, encodeV4File(source));\n try {\n await verifyMigratedFile(tempPath, source);\n } catch (error) {\n rmSync(tempPath, { force: true });\n throw new Error(`Verification failed for ${filePath}`, { cause: error });\n }\n renameSync(filePath, `${filePath}.v3.bak`);\n renameSync(tempPath, filePath);\n return { file: filePath, status: \"migrated\" };\n}\n\n/** Recursively find candidate session files (.jsonl with a v3 header). */\nexport function findV3SessionFiles(root: string): string[] {\n if (!existsSync(root)) return [];\n const found: string[] = [];\n const walk = (dir: string) => {\n for (const name of readdirSync(dir)) {\n const path = join(dir, name);\n let stats;\n try {\n stats = statSync(path);\n } catch {\n continue;\n }\n if (stats.isDirectory()) {\n walk(path);\n } else if (name.endsWith(\".jsonl\") && isV3SessionFile(path)) {\n found.push(path);\n }\n }\n };\n walk(root);\n return found;\n}\n"]}
|