import { randomUUID } from 'node:crypto'; import { mkdir, readFile, writeFile } from 'node:fs/promises'; import { homedir } from 'node:os'; import { dirname, join } from 'node:path'; import type { NoteArtifactDoc } from '../modules/note-artifacts/types.js'; import type { NoteDoc } from '../modules/notes/types.js'; export const DEFAULT_PHASE1_ROOT = join(homedir(), '.bytelyst', 'ecosystem', 'phase1'); type TranscriptArtifact = { id: string; title: string | null; summary: string | null; sourceSurface: string; createdAt: string; tags: string[]; ownership: { userId: string; orgId?: string | null; }; provenance: { originProductId: string; originActionId?: string | null; sessionId?: string | null; runId?: string | null; approvalId?: string | null; correlationId?: string | null; lineage: Array<{ stepType: string; productId: string; actorType: 'user' | 'agent' | 'system'; timestamp: string; }>; }; payload: { transcriptText: string; transcriptSource: string; language: string; durationMs: number; }; }; type EcosystemEvent = { eventId: string; eventName: string; eventVersion: 1; occurredAt: string; productId: string; sourceSurface: string; userId: string | null; orgId?: string | null; sessionId?: string | null; runId?: string | null; artifactId?: string | null; actor: { actorType: 'user' | 'agent' | 'system' | 'device'; actorId?: string | null; }; trace: { correlationId: string | null; causationId: string | null; parentEventId: string | null; }; payload: Record; }; type TranscriptCaptureEvent = EcosystemEvent & { eventName: 'capture.transcript.created'; artifactId: string; }; type NoteArtifactEnvelope = { id: string; artifactType: 'note'; schemaVersion: 1; productId: 'notelett'; sourceSurface: string; title: string; summary: string; createdAt: string; updatedAt: string; createdBy: { actorType: 'agent'; actorId: string; }; ownership: { userId: string; orgId?: string | null; }; visibility: { scope: 'private'; }; status: string; tags: string[]; links: Array<{ relation: 'summarizes'; targetArtifactId: string; }>; provenance: TranscriptArtifact['provenance']; payload: { noteFormat: 'markdown'; body: string; excerpt: string; }; }; export function getPhase1Root(): string { return process.env.BYTELYST_ECOSYSTEM_DIR ?? DEFAULT_PHASE1_ROOT; } export async function loadLatestTranscriptArtifact(root = getPhase1Root()): Promise { const raw = await readFile(join(root, 'indexes', 'latest-transcript.json'), 'utf-8'); return JSON.parse(raw) as TranscriptArtifact; } export async function loadLatestTranscriptCaptureEvent( root = getPhase1Root() ): Promise { try { const raw = await readFile(join(root, 'indexes', 'latest-transcript-event.json'), 'utf-8'); return JSON.parse(raw) as TranscriptCaptureEvent; } catch (error) { if ((error as NodeJS.ErrnoException).code === 'ENOENT') { return null; } throw error; } } export function buildPhase1NoteImport(params: { transcriptArtifact: TranscriptArtifact; transcriptCaptureEvent?: TranscriptCaptureEvent | null; workspaceId: string; userId: string; now?: string; }): { note: NoteDoc; noteArtifactDoc: NoteArtifactDoc; ecosystemNoteArtifact: NoteArtifactEnvelope; createdEvent: EcosystemEvent; linkedEvent: EcosystemEvent; } { const { transcriptArtifact, workspaceId, userId } = params; const now = params.now ?? new Date().toISOString(); const noteId = `note_phase1_${randomUUID().replace(/-/g, '').slice(0, 12)}`; const correlationId = transcriptArtifact.provenance.correlationId ?? `corr_${randomUUID().slice(0, 12)}`; const runId = `run_note_${randomUUID().replace(/-/g, '').slice(0, 10)}`; const title = transcriptArtifact.title || 'Imported transcript note'; const body = `# ${title}\n\n${transcriptArtifact.payload.transcriptText}`; const excerpt = transcriptArtifact.summary || transcriptArtifact.payload.transcriptText.slice(0, 160); const noteArtifactId = `art_note_${randomUUID().replace(/-/g, '').slice(0, 12)}`; const note: NoteDoc = { id: noteId, productId: 'notelett', workspaceId, userId, title, body, status: 'draft', tags: Array.from(new Set([...transcriptArtifact.tags, 'ecosystem', 'phase1'])), links: [transcriptArtifact.id], sourceType: 'ecosystem-transcript', sourceUri: transcriptArtifact.id, createdAt: now, updatedAt: now, createdBy: userId, updatedBy: userId, agentId: 'phase1-transcript-importer', }; const noteArtifactDoc: NoteArtifactDoc = { id: `na_${randomUUID().replace(/-/g, '').slice(0, 12)}`, productId: 'notelett', workspaceId, userId, noteId, artifactType: 'summary', title: 'Imported transcript artifact', description: `Transcript source ${transcriptArtifact.id}`, blobPath: join(getPhase1Root(), 'artifacts', 'note', `${noteArtifactId}.json`), contentType: 'application/json', createdAt: now, createdBy: userId, updatedAt: now, updatedBy: userId, }; const ecosystemNoteArtifact: NoteArtifactEnvelope = { id: noteArtifactId, artifactType: 'note', schemaVersion: 1, productId: 'notelett', sourceSurface: 'backend', title, summary: excerpt, createdAt: now, updatedAt: now, createdBy: { actorType: 'agent', actorId: 'phase1-transcript-importer', }, ownership: { userId, orgId: transcriptArtifact.ownership.orgId ?? null, }, visibility: { scope: 'private', }, status: note.status, tags: note.tags, links: [ { relation: 'summarizes', targetArtifactId: transcriptArtifact.id, }, ], provenance: { ...transcriptArtifact.provenance, runId, lineage: [ ...transcriptArtifact.provenance.lineage, { stepType: 'note-created', productId: 'notelett', actorType: 'agent', timestamp: now, }, ], }, payload: { noteFormat: 'markdown', body, excerpt, }, }; const createdEvent: EcosystemEvent = { eventId: `evt_note_created_${randomUUID().replace(/-/g, '').slice(0, 12)}`, eventName: 'artifact.created', eventVersion: 1, occurredAt: now, productId: 'notelett', sourceSurface: 'backend', userId, orgId: transcriptArtifact.ownership.orgId ?? null, sessionId: transcriptArtifact.provenance.sessionId ?? null, runId, artifactId: ecosystemNoteArtifact.id, actor: { actorType: 'agent', actorId: 'phase1-transcript-importer', }, trace: { correlationId, causationId: params.transcriptCaptureEvent?.eventId ?? null, parentEventId: params.transcriptCaptureEvent?.eventId ?? null, }, payload: { artifactType: 'note', title, status: note.status, }, }; const linkedEvent: EcosystemEvent = { eventId: `evt_note_linked_${randomUUID().replace(/-/g, '').slice(0, 12)}`, eventName: 'artifact.linked', eventVersion: 1, occurredAt: now, productId: 'notelett', sourceSurface: 'backend', userId, orgId: transcriptArtifact.ownership.orgId ?? null, sessionId: transcriptArtifact.provenance.sessionId ?? null, runId, artifactId: ecosystemNoteArtifact.id, actor: { actorType: 'agent', actorId: 'phase1-transcript-importer', }, trace: { correlationId, causationId: createdEvent.eventId, parentEventId: createdEvent.eventId, }, payload: { sourceArtifactId: ecosystemNoteArtifact.id, targetArtifactId: transcriptArtifact.id, relation: 'summarizes', }, }; return { note, noteArtifactDoc, ecosystemNoteArtifact, createdEvent, linkedEvent }; } export async function persistPhase1NoteOutputs(params: { ecosystemNoteArtifact: NoteArtifactEnvelope; createdEvent: EcosystemEvent; linkedEvent: EcosystemEvent; root?: string; }): Promise { const root = params.root ?? getPhase1Root(); await writeJson(join(root, 'artifacts', 'note', `${params.ecosystemNoteArtifact.id}.json`), params.ecosystemNoteArtifact); await writeJson(join(root, 'events', 'artifact.created', `${params.createdEvent.eventId}.json`), params.createdEvent); await writeJson(join(root, 'events', 'artifact.linked', `${params.linkedEvent.eventId}.json`), params.linkedEvent); await writeJson(join(root, 'indexes', 'latest-note.json'), params.ecosystemNoteArtifact); await writeJson(join(root, 'indexes', 'latest-note-created-event.json'), params.createdEvent); await writeJson(join(root, 'indexes', 'latest-note-linked-event.json'), params.linkedEvent); } async function writeJson(path: string, payload: unknown): Promise { await mkdir(dirname(path), { recursive: true }); await writeFile(path, `${JSON.stringify(payload, null, 2)}\n`, 'utf-8'); }