/* RFC-0958: mission.journal.show — inspect the operation journal for a mission. Do not modify the journal — read-only command. RFC-0958: initial mission.journal.show command handler. RFC-1149: migrate ambient filesystem and process IO to the WorkspaceIO port across engine and shared RFC-1249: wire werkstatt.commands.validate into packages.check + retire CMD-OUTPUT debt */ import type { KernelCommandInput, KernelCommandResult, KernelRuntimeContext, } from "@warpgogol/werkstatt-engine/kernel"; import { resolveMissionDir } from "./mission-io.ts"; import { readJournal, findIncompleteOperation } from "../journal/index.ts"; import path from "node:path"; export interface MissionJournalShowData { missionId: string; records: unknown[]; incompleteOperation: { opId: string; op: string; lastSeq: number } | null; } function flagString(input: KernelCommandInput, key: string): string | undefined { const v = input.flags[key]; return typeof v === "string" ? v : undefined; } function flagBool(input: KernelCommandInput, key: string): boolean { const v = input.flags[key]; return v === true || v === "true"; } export async function runMissionJournalShow( input: KernelCommandInput, context: KernelRuntimeContext, ): Promise> { const { workspaceRoot } = context; const missionId = flagString(input, "mission"); if (!missionId) { return { exitCode: 1, summary: "[mission.journal.show] --mission is required", nextSteps: [ { action: "Pass --mission to select the mission journal", kind: "required" }, ], }; } const missionDir = await resolveMissionDir(workspaceRoot, missionId, context.io); const journalPath = path.join(missionDir, "journal.jsonl"); const opFilter = flagString(input, "op"); const json = flagBool(input, "json"); const allRecords = await readJournal(journalPath); const records = opFilter ? allRecords.filter((r) => "opId" in r && r.opId === opFilter) : allRecords; const incomplete = findIncompleteOperation(allRecords); if (json) { return { data: { missionId, records, incompleteOperation: incomplete }, exitCode: 0, summary: `[mission.journal.show] ${records.length} records for ${missionId}`, }; } const lines: string[] = []; for (const r of records) { const rec = r as Record; const seq = rec.seq !== undefined ? ` seq=${rec.seq}` : ""; const step = rec.step ? ` step=${rec.step}` : ""; const error = rec.error ? ` error="${rec.error}"` : ""; lines.push(` ${rec.kind}${seq}${step}${error}`); } const incompleteSummary = incomplete ? `\n incomplete: ${incomplete.op} (${incomplete.opId}) at seq ${incomplete.lastSeq}` : "\n no incomplete operation"; return { data: { missionId, records, incompleteOperation: incomplete }, exitCode: 0, summary: `[mission.journal.show] ${missionId} — ${records.length} records${incompleteSummary}\n${lines.join("\n")}`, }; }