UNPKG

@workflow-manager/runner

Version:

CLI runner for in-memory and markdown workflow orchestration using ATEP-like envelopes

79 lines (78 loc) 2.63 kB
import { splitLines } from "../runFormat.js"; const DEFAULT_MAX_LINES_PER_STEP = 2000; // Sentinel bucket key for chunks/meta with no stepKey (workflow-level output). // A symbol can never collide with a real (string) step key. const WORKFLOW_BUCKET_KEY = Symbol("workflow"); function bucketKey(stepKey) { return stepKey ?? WORKFLOW_BUCKET_KEY; } export class TuiLogStore { maxLinesPerStep; buckets = new Map(); // Per-bucket, per-stream partial line remainders awaiting a terminating newline. partials = new Map(); constructor(options) { this.maxLinesPerStep = options?.maxLinesPerStep ?? DEFAULT_MAX_LINES_PER_STEP; } appendChunk(log) { const key = bucketKey(log.stepKey); const streamMap = this.partials.get(key) ?? new Map(); if (!this.partials.has(key)) { this.partials.set(key, streamMap); } const existing = streamMap.get(log.stream) ?? ""; const { lines, remainder } = splitLines(existing + log.text); streamMap.set(log.stream, remainder); if (lines.length === 0) { return; } const bucket = this.bucketFor(key); for (const line of lines) { this.pushLine(bucket, { kind: log.stream, text: line }); } } appendMeta(stepKey, text) { const bucket = this.bucketFor(bucketKey(stepKey)); this.pushLine(bucket, { kind: "meta", text }); } flushPartialLines() { for (const [key, streamMap] of this.partials.entries()) { for (const [stream, text] of streamMap.entries()) { if (!text) { continue; } const bucket = this.bucketFor(key); this.pushLine(bucket, { kind: stream, text }); } } this.partials.clear(); } tail(stepKey, count) { const bucket = this.buckets.get(bucketKey(stepKey)); if (!bucket || count <= 0) { return []; } if (count >= bucket.length) { return bucket.slice(); } return bucket.slice(bucket.length - count); } lineCount(stepKey) { return this.buckets.get(bucketKey(stepKey))?.length ?? 0; } bucketFor(key) { const existing = this.buckets.get(key); if (existing) { return existing; } const bucket = []; this.buckets.set(key, bucket); return bucket; } pushLine(bucket, line) { bucket.push(line); while (bucket.length > this.maxLinesPerStep) { bucket.shift(); } } }