Files
makelore/electron/coding-projects/conversation-history.ts

53 lines
2.0 KiB
TypeScript

import { readFile } from 'node:fs/promises';
import path from 'node:path';
import type { CodingConversationV2 } from './conversation-store';
import { validateSessionKey } from './conversation-store';
import type { ConversationSnapshot } from '../../shared/coding-conversation-contracts';
import { getPiManagedPaths } from '../coding-runtime/pi/resource-loader';
import { projectPiSessionSnapshot } from '../coding-runtime/pi/session-projector';
/** Read durable active-branch history without starting or reconfiguring Pi. */
export async function readCodingConversationHistory(
userDataDir: string,
projectId: string,
conversation: CodingConversationV2
): Promise<ConversationSnapshot> {
const base: ConversationSnapshot = {
schemaVersion: 1,
conversation: {
id: conversation.id,
projectId,
agentId: conversation.agentId,
title: conversation.title,
model: { model: conversation.model, modelResolution: conversation.modelResolution },
},
nodes: [],
run: { status: 'idle' },
queue: { items: [] },
context: { usedTokens: 0, contextWindow: 0, compaction: 'idle' },
pendingInteractions: [],
worker: { status: 'stopped', generation: 0 },
cursor: { workerGeneration: 0, seq: 0 },
};
if (!conversation.sessionKey) return base;
const filename = path.join(
getPiManagedPaths(userDataDir).sessionsDir,
projectId,
validateSessionKey(conversation.sessionKey) + '.jsonl'
);
const text = await readFile(filename, 'utf8');
// Pi 0.84.2 rebuilds its current leaf from the last non-header entry.
const entries = text
.split('\n')
.filter((line) => line.trim())
.map((line) => JSON.parse(line) as { id: string; type: string })
.filter((entry) => entry.type !== 'session');
const snapshot = await projectPiSessionSnapshot({
snapshot: base,
workerGeneration: 1,
state: { isStreaming: false },
entries: { entries, leafId: entries.at(-1)?.id ?? null },
});
return { ...snapshot, worker: { status: 'stopped', generation: 1 } };
}