baa-conductor

git clone 

baa-conductor / packages / logging / src
im_wower  ·  2026-03-21

session.ts

  1import {
  2  type LocalRunLogContext,
  3  type LocalRunLogSession,
  4  type LocalRunLogSummary,
  5  type LocalRunPaths,
  6  type StreamChunkInput,
  7  type StreamChunkLogEntry,
  8  type StreamChunkLogStream,
  9  type StreamLogChannel,
 10  type WorkerLifecycleEventInput,
 11  type WorkerLifecycleLogEntry
 12} from "./contracts";
 13import { createLocalRunLogTargets } from "./paths";
 14
 15function allocateSeq(session: LocalRunLogSession): number {
 16  const seq = session.nextSeq;
 17  session.nextSeq += 1;
 18
 19  return seq;
 20}
 21
 22function getStream(session: LocalRunLogSession, channel: StreamLogChannel): StreamChunkLogStream {
 23  switch (channel) {
 24    case "stdout":
 25      return session.stdout;
 26    case "stderr":
 27      return session.stderr;
 28  }
 29}
 30
 31export function serializeLifecycleEvent(
 32  entry: Omit<WorkerLifecycleLogEntry, "renderedLine">
 33): string {
 34  return JSON.stringify({
 35    seq: entry.seq,
 36    eventId: entry.eventId,
 37    taskId: entry.taskId,
 38    stepId: entry.stepId,
 39    runId: entry.runId,
 40    type: entry.type,
 41    level: entry.level,
 42    createdAt: entry.createdAt,
 43    message: entry.message,
 44    data: entry.data
 45  });
 46}
 47
 48export function createLocalRunLogSession(
 49  paths: LocalRunPaths,
 50  context: LocalRunLogContext
 51): LocalRunLogSession {
 52  const targets = createLocalRunLogTargets(paths);
 53
 54  return {
 55    context,
 56    paths,
 57    nextSeq: 1,
 58    worker: {
 59      channel: "worker",
 60      filePath: targets.worker.filePath,
 61      entries: []
 62    },
 63    stdout: {
 64      channel: "stdout",
 65      filePath: targets.stdout.filePath,
 66      entries: []
 67    },
 68    stderr: {
 69      channel: "stderr",
 70      filePath: targets.stderr.filePath,
 71      entries: []
 72    }
 73  };
 74}
 75
 76export function recordLifecycleEvent(
 77  session: LocalRunLogSession,
 78  input: WorkerLifecycleEventInput
 79): WorkerLifecycleLogEntry {
 80  const seq = allocateSeq(session);
 81  const createdAt = input.createdAt ?? new Date().toISOString();
 82  const baseEntry = {
 83    ...session.context,
 84    seq,
 85    channel: "worker" as const,
 86    eventId: `${session.context.runId}:event:${String(seq).padStart(4, "0")}`,
 87    type: input.type,
 88    level: input.level,
 89    createdAt,
 90    message: input.message,
 91    data: input.data ?? {}
 92  };
 93  const entry: WorkerLifecycleLogEntry = {
 94    ...baseEntry,
 95    renderedLine: serializeLifecycleEvent(baseEntry)
 96  };
 97
 98  session.worker.entries.push(entry);
 99
100  return entry;
101}
102
103export function appendStreamChunk(
104  session: LocalRunLogSession,
105  channel: StreamLogChannel,
106  input: StreamChunkInput
107): StreamChunkLogEntry {
108  const seq = allocateSeq(session);
109  const entry: StreamChunkLogEntry = {
110    ...session.context,
111    seq,
112    channel,
113    createdAt: input.createdAt ?? new Date().toISOString(),
114    text: input.text
115  };
116
117  getStream(session, channel).entries.push(entry);
118
119  return entry;
120}
121
122export function summarizeLocalRunLogSession(session: LocalRunLogSession): LocalRunLogSummary {
123  const lifecycleEventCount = session.worker.entries.length;
124  const stdoutChunkCount = session.stdout.entries.length;
125  const stderrChunkCount = session.stderr.entries.length;
126
127  return {
128    totalEntries: lifecycleEventCount + stdoutChunkCount + stderrChunkCount,
129    lastSeq: session.nextSeq - 1,
130    lifecycleEventCount,
131    stdoutChunkCount,
132    stderrChunkCount
133  };
134}